-#ifndef BH_H
-#define BH_H
-
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h> // TODO: Replace with needed functions
-#include <assert.h>
-
-//-------------------------------------------------------------------------------------
-// Better types
-//-------------------------------------------------------------------------------------
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-typedef unsigned long u64;
-typedef unsigned long long u128;
-typedef signed char i8;
-typedef signed short i16;
-typedef signed int i32;
-typedef signed long i64;
-typedef signed long long i128;
-typedef unsigned long isize;
-typedef i32 b32;
-typedef void* ptr;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better character functions
-//-------------------------------------------------------------------------------------
-b32 char_is_alpha(const char a);
-b32 char_is_num(const char a);
-b32 char_is_alphanum(const char a);
-b32 char_is_whitespace(const char a);
-b32 char_in_range(const char lo, const char hi, const char a);
-char charset_contains(const char* charset, char ch);
-i64 chars_match(char* ptr1, char* ptr2);
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better math functions
-//-------------------------------------------------------------------------------------
-#define bh_max(a, b) ((a) > (b) ? (a) : (b))
-#define bh_min(a, b) ((a) < (b) ? (a) : (b))
-#define bh_clamp(v, a, b) (bh_min((b), bh_max((a), (v))))
-#define bh_abs(x) ((x) < 0 ? -(x) : (x))
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Helpful macros
-//-------------------------------------------------------------------------------------
-#define bh_offset_of(Type, elem) ((isize)&(((Type)*) 0)->elem)
-#define bh_aligh_of(Type) bh_offset_of(struct { char c; Type member; }, member)
-#define bh_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while(0)
-
-#define bh_pointer_add(ptr, amm) ((void *)((u8 *) ptr + amm))
-#define BH_BIT(x) (1 << (x))
-#define BH_MASK_SET(var, set, mask) ((set) ? (var) |= (mask) : (var) &= ~(mask))
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Custom allocators
-//-------------------------------------------------------------------------------------
-
-typedef enum bh_allocator_actions {
- bh_allocator_action_alloc,
- bh_allocator_action_free,
- bh_allocator_action_resize,
-} bh_allocator_actions;
-
-#define BH_ALLOCATOR_PROC(name) \
-ptr name(ptr data, bh_allocator_actions action, \
- isize size, isize alignment, \
- void* prev_memory, \
- u64 flags)
-
-typedef BH_ALLOCATOR_PROC(bh__allocator_proc); // NOTE: so bh__allocator_proc can be used instead of that type
-
-typedef struct bh_allocator {
- bh__allocator_proc* proc; // Procedure that can handle bh_allocator_actions
- ptr data; // Pointer to the other data for the allocator
-} bh_allocator;
-
-typedef enum bh_allocator_flags {
- bh_allocator_flag_clear = 1 // Sets all memory to be 0
-} bh_allocator_flags;
-
-ptr bh_alloc(bh_allocator a, isize size);
-ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment);
-ptr bh_resize(bh_allocator a, ptr data, isize new_size);
-ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment);
-void bh_free(bh_allocator a, ptr data);
-
-#define bh_alloc_item(allocator_, T) (T *) bh_alloc(allocator_, sizeof(T))
-#define bh_alloc_array(allocator_, T, n) (T *) bh_alloc(allocator_, sizeof(T) * (n))
-
-// NOTE: This should get optimized out since alignment should be a power of two
-#define bh__align(x, alignment) ((((x) / alignment) + 1) * alignment)
-
-
-
-
-// HEAP ALLOCATOR
-// Essentially a wrapper for malloc, free and realloc
-bh_allocator bh_heap_allocator(void);
-BH_ALLOCATOR_PROC(bh_heap_allocator_proc);
-
-
-
-
-
-// ARENA ALLOCATOR
-typedef struct bh_arena {
- bh_allocator backing;
- ptr first_arena, current_arena;
- isize size, arena_size; // in bytes
-} bh_arena;
-
-typedef struct bh__arena_internal {
- ptr next_arena;
- void* data; // Not actually a pointer, just used for the offset
-} bh__arena_internal;
-
-void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size);
-void bh_arena_free(bh_arena* alloc);
-bh_allocator bh_arena_allocator(bh_arena* alloc);
-BH_ALLOCATOR_PROC(bh_arena_allocator_proc);
-
-
-
-// SCRATCH ALLOCATOR
-typedef struct bh_scratch {
- bh_allocator backing;
- ptr memory, end, curr;
-} bh_scratch;
-
-void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size);
-void bh_scratch_free(bh_scratch* scratch);
-bh_allocator bh_scratch_allocator(bh_scratch* scratch);
-BH_ALLOCATOR_PROC(bh_scratch_allocator_proc);
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better strings
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_STRING
-
-typedef struct bh__string {
- u64 length;
- u64 capacity;
-} bh__string;
-
-typedef char bh_string;
-
-#define bh__stringhead(x) (((bh__string *)(x)) - 1)
-
-#define bh_string_new(x) _Generic((x), \
- unsigned long: bh_string_new_cap, \
- unsigned int: bh_string_new_cap, \
- int: bh_string_new_cap, \
- long: bh_string_new_cap, \
- const char*: bh_string_new_str, \
- char*: bh_string_new_str)(x)
-
-#define bh_string_append(str1, str2) _Generic((str2), \
- bh_string*: bh_string_append_bh_string, \
- char*: bh_string_append_cstr, \
- const char*: bh_string_append_cstr)(str1, str2)
-
-#define bh_string_replace_at(dest, src, offset) _Generic((src), \
- bh_string*: bh_string_replace_at_bh_string, \
- char*: bh_string_replace_at_cstr, \
- const char*: bh_string_replace_at_cstr)(dest, src, offset)
-
-#define bh_string_insert_at(dest, src, offset) _Generic((src), \
- bh_string*: bh_string_insert_at_bh_string, \
- char*: bh_string_insert_at_cstr, \
- const char*: bh_string_insert_at_cstr)(dest, src, offset)
-
-bh_string bh_string_new_cap(unsigned long cap);
-bh_string bh_string_new_str(const char* cstr);
-b32 bh_string_delete(bh_string* str);
-b32 bh_string_ensure_capacity(bh_string* str, u64 cap);
-void bh_string_append_bh_string(bh_string* str1, bh_string* str2);
-void bh_string_append_cstr(bh_string* str1, const char* str2);
-void bh_string_replace_at_bh_string(bh_string* dest, bh_string* src, u64 offset);
-void bh_string_replace_at_cstr(bh_string* dest, const char* src, u64 offset);
-void bh_string_insert_at_bh_string(bh_string* dest, bh_string* src, u64 offset);
-void bh_string_insert_at_cstr(bh_string* dest, const char* src, u64 offset);
-void bh_string_trim_end(bh_string* str, const char* charset);
-void bh_string_trim_begin(bh_string* str, const char* charset);
-void bh_string_trim_end_space(bh_string* str);
-// TEMP
-void bh_string_print(bh_string* str);
-
-#endif
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better files
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_FILE
-
-typedef enum bh_file_error {
- BH_FILE_ERROR_NONE,
- BH_FILE_ERROR_INVALID,
- BH_FILE_ERROR_BAD_FD,
-} bh_file_error;
-
-typedef enum bh_file_mode {
- BH_FILE_MODE_READ = 1 << 0,
- BH_FILE_MODE_WRITE = 1 << 1,
- BH_FILE_MODE_APPEND = 1 << 2,
- BH_FILE_MODE_RW = 1 << 3,
-
- BH_FILE_MODE_MODES = BH_FILE_MODE_READ | BH_FILE_MODE_WRITE | BH_FILE_MODE_APPEND | BH_FILE_MODE_RW
-} bh_file_mode;
-
-typedef enum bh_file_whence {
- BH_FILE_WHENCE_BEGIN = SEEK_SET,
- BH_FILE_WHENCE_CURRENT = SEEK_CUR,
- BH_FILE_WHENCE_END = SEEK_END,
-} bh_file_whence;
-
-typedef int bh_file_descriptor;
-
-typedef struct bh_file {
- bh_file_descriptor fd;
- char const* filename;
-} bh_file;
-
-typedef enum bh_file_standard {
- BH_FILE_STANDARD_INPUT,
- BH_FILE_STANDARD_OUTPUT,
- BH_FILE_STANDARD_ERROR
-} bh_file_standard;
-
-typedef struct bh_file_contents {
- bh_allocator allocator;
- const char *filename;
- isize length;
- void* data;
-} bh_file_contents;
-
-bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand);
-
-bh_file_error bh_file_create(bh_file* file, char const* filename);
-bh_file_error bh_file_open(bh_file* file, char const* filename);
-bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename);
-bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename);
-b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read);
-b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote);
-static b32 bh__file_seek_wrapper(i32 fd, i64 offset, bh_file_whence whence, i64* new_offset);
-i64 bh_file_seek_to_end(bh_file* file);
-i64 bh_file_skip(bh_file* file, i64 bytes);
-i64 bh_file_tell(bh_file* file);
-bh_file_error bh_file_close(bh_file* file);
-i32 bh_file_read(bh_file* file, void* buffer, isize buff_size);
-i32 bh_file_write(bh_file* file, void* buffer, isize buff_size);
-i64 bh_file_size(bh_file* file);
-
-#define bh_file_read_contents(allocator_, x) _Generic((x), \
- bh_file*: bh_file_read_contents_bh_file, \
- const char*: bh_file_read_contents_direct, \
- char*: bh_file_read_contents_direct)((allocator_), x)
-
-bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file);
-bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename);
-i32 bh_file_contents_delete(bh_file_contents* contents);
-
-#endif
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Alternate printing
-//-------------------------------------------------------------------------------------
-// Barebones implementation of printf. Does not support all format options
-// Currently supports:
-// %c - chars
-// %_(u)d - ints where _ is:
-// nothing - decimal
-// o - octal
-// x - hexadecimal
-// %_(u)l - longs where _ is:
-// nothing - decimal
-// o - octal
-// x - hexadecimal
-// %f - floating points
-// %s - null terminated strings
-// %p - pointers
-// %% - literal %
-
-typedef struct bh__print_format {
- u32 base;
-} bh__print_format;
-
-isize bh_printf(char const *fmt, ...);
-isize bh_printf_va(char const *fmt, va_list va);
-isize bh_printf_err(char const *fmt, ...);
-isize bh_printf_err_va(char const *fmt, va_list va);
-isize bh_fprintf(bh_file* f, char const *fmt, ...);
-isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va);
-char* bh_bprintf(char const *fmt, ...);
-char* bh_bprintf_va(char const *fmt, va_list va);
-isize bh_snprintf(char *str, isize n, char const *fmt, ...);
-isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va);
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better debug functions
-//-------------------------------------------------------------------------------------
-#ifdef BH_DEBUG
-
-void* bh__debug_malloc(size_t size, const char* file, u64 line);
-void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line);
-void bh__debug_free(void* ptr, const char* file, u64 line);
-void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line);
-
-#ifdef BH_DEFINE
-
-void* bh__debug_malloc(size_t size, const char* file, u64 line) {
- void* p = malloc(size);
- bh_printf("[DEBUG] %p = malloc(%d) at %s:%d\n", p, size, file, line);
- return p;
-}
-
-void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line) {
- void* p = aligned_alloc(size, alignment);
- bh_printf("[DEBUG] %p = aligned_alloc(%d, %d) at %s:%d\n", p, alignment, size, file, line);
- return p;
-}
-
-void bh__debug_free(void* ptr, const char* file, u64 line) {
- bh_printf("[DEBUG] free(%p) at %s:%d\n", ptr, file, line);
- free(ptr);
-}
-
-void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line) {
- void* p = realloc(ptr, size);
- bh_printf("[DEBUG] %p = realloc(%p, %d) at %s:%d\n", p, ptr, size, file, line);
- return p;
-}
-
-#endif
-
-#define malloc(size) (bh__debug_malloc(size, __FILE__, __LINE__))
-#define aligned_alloc(size, alignment) (bh__debug_aligned_alloc(size, alignment, __FILE__, __LINE__))
-#define free(ptr) (bh__debug_free(ptr, __FILE__, __LINE__))
-#define realloc(ptr, size) (bh__debug_realloc(ptr, size, __FILE__, __LINE__))
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// Better dynamically-sized arrays
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_ARRAY
-
-typedef struct bh__arr {
- bh_allocator allocator;
- i32 length, capacity;
-} bh__arr;
-
-#ifndef BH_ARR_GROW_FORMULA
-#define BH_ARR_GROW_FORMULA(x) ((x) > 0 ? ((x) << 1) : 4)
-#endif
-
-#define bh_arr(T) T*
-#define bh__arrhead(arr) (((bh__arr *)(arr)) - 1)
-
-#define bh_arr_allocator(arr) (arr ? bh__arrhead(arr)->allocator : bh_heap_allocator())
-#define bh_arr_length(arr) (arr ? bh__arrhead(arr)->length : 0)
-#define bh_arr_capacity(arr) (arr ? bh__arrhead(arr)->capacity : 0)
-#define bh_arr_size(arr) (arr ? bh__arrhead(arr)->capacity * sizeof(*(arr)) : 0)
-#define bh_arr_valid(arr, i) (arr ? (i32)(i) < bh__arrhead(arr)->length : 0)
-
-#define bh_arr_pop(arr) ((arr)[--bh__arrhead(arr)->length])
-#define bh_arr_last(arr) ((arr)[bh__arrhead(arr)->length - 1])
-#define bh_arr_end(arr, i) ((i) >= &(arr)[bh_arr_length(arr)])
-
-#define bh_arr_new(allocator_, arr, cap) (bh__arr_grow((allocator_), (void**) &(arr), sizeof(*(arr)), cap))
-#define bh_arr_free(arr) (bh__arr_free((void**) &(arr)))
-#define bh_arr_copy(allocator_, arr) (bh__arr_copy((allocator_), (arr), sizeof(*(arr))))
-
-#define bh_arr_grow(arr, cap) (bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), cap))
-#define bh_arr_shrink(arr, cap) (bh__arr_shrink((void **) &(arr), sizeof(*(arr)), cap))
-#define bh_arr_set_length(arr, n) ( \
- bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), n), \
- bh__arrhead(arr)->length = n)
-
-#define bh_arr_insertn(arr, i, n) (bh__arr_insertn((void **) &(arr), sizeof(*(arr)), i, n))
-
-#define bh_arr_insert_end(arr, n) ( \
- bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + n), \
- bh__arrhead(arr)->length += n)
-
-#define bh_arr_push(arr, value) ( \
- bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + 1), \
- arr[bh__arrhead(arr)->length++] = value)
-
-#define bh_arr_is_empty(arr) (arr ? bh__arrhead(arr)->length == 0 : 1)
-#define bh_arr_clear(arr) (arr ? (bh__arrhead(arr)->length = 0) : 0)
-
-#define bh_arr_deleten(arr, i, n) (bh__arr_deleten((void **) &(arr), sizeof(*(arr)), i, n))
-#define bh_arr_fastdelete(arr, i) (arr[i] = arr[--bh__arrhead(arr)->length])
-
-b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap);
-b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap);
-b32 bh__arr_free(void **arr);
-void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize);
-void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems);
-void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems);
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// HASH TABLE FUNCTIONS
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_HASHTABLE
-
-#define BH__HASH_STORED_KEY_SIZE 64
-typedef struct bh__hash_entry {
- char key[BH__HASH_STORED_KEY_SIZE];
- i32 value; // NOTE: Not actually an i32, just used as a placeholder for offset
-} bh__hash_entry;
-
-#define BH__HASH_MODULUS 1021
-#define BH__HASH_KEYSIZE 64
-#ifdef BH_DEFINE
-u64 bh__hash_function(const char* str, i32 len) {
- u64 hash = 5381;
- i32 c, l = 0;
- if (len == 0) len = BH__HASH_KEYSIZE;
-
- while ((c = *str++) && l++ < len) {
- hash = (hash << 5) + hash + c;
- }
-
- return hash % BH__HASH_MODULUS;
-}
-#endif
-
-typedef struct bh_hash_iterator {
- ptr *tab, *endtab;
- i32 elemsize, arrlen;
- bh__hash_entry* entry;
-} bh_hash_iterator;
-
-typedef struct bh__hash {
- bh_allocator allocator;
- ptr arrs[BH__HASH_MODULUS];
-} bh__hash;
-
-#define bh_hash(T) T*
-
-#ifdef BH_HASH_SIZE_SAFE
- #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab))
- #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab))
- #define bh_hash_put(T, tab, key, value) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = (T) value))
- #define bh_hash_has(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (bh__hash_has((bh__hash *) tab, sizeof(T), key)))
- #define bh_hash_get(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key))))
- #define bh_hash_delete(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_delete((bh__hash *) tab, sizeof(T), key))
-
- #define bh_hash_iter_setup(T, tab) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_iter_setup((bh__hash *) tab, sizeof(T)))
- #define bh_hash_iter_key(it) (it.entry->key)
- #define bh_hash_iter_value(T, it) (assert(sizeof(T) == it.elemsize), *(T *)&(it.entry->value))
-#else
- #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab))
- #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab))
- #define bh_hash_put(T, tab, key, value) (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = value)
- #define bh_hash_has(T, tab, key) (bh__hash_has((bh__hash *) tab, sizeof(T), key))
- #define bh_hash_get(T, tab, key) (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key)))
- #define bh_hash_delete(T, tab, key) (bh__hash_delete((bh__hash *) tab, sizeof(T), key))
-
- #define bh_hash_iter_setup(T, tab) (bh__hash_iter_setup((bh__hash *) tab, sizeof(T)))
- #define bh_hash_iter_key(it) (it.entry->key)
- #define bh_hash_iter_value(T, it) (*(T *)&(it.entry->value))
-#endif
-
-b32 bh__hash_init(bh_allocator allocator, bh__hash **table);
-b32 bh__hash_free(bh__hash **table);
-ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key);
-b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key);
-ptr bh__hash_get(bh__hash *table, i32 elemsize, char *key);
-void bh__hash_delete(bh__hash *table, i32 elemsize, char *key);
-bh_hash_iterator bh__hash_iter_setup(bh__hash *table, i32 elemsize);
-b32 bh_hash_iter_next(bh_hash_iterator* it);
-
-#endif
-
-#ifdef BH_DEFINE
-#undef BH_DEFINE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// IMPLEMENTATIONS
-//-------------------------------------------------------------------------------------
-
-//-------------------------------------------------------------------------------------
-// CHAR FUNCTIONS
-//-------------------------------------------------------------------------------------
-b32 char_is_alpha(const char a) {
- return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z');
-}
-
-b32 char_is_num(const char a) {
- return ('0' <= a && a <= '9');
-}
-
-b32 char_is_alphanum(const char a) {
- return char_is_alpha(a) || char_is_num(a);
-}
-
-b32 char_is_whitespace(const char a) {
- return charset_contains(" \t\r\n", a);
-}
-
-b32 char_in_range(const char lo, const char hi, const char a) {
- return lo <= a <= hi;
-}
-
-char charset_contains(const char* charset, char ch) {
- while (*charset) {
- if (*charset == ch) return ch;
- charset++;
- }
-
- return 0;
-}
-
-i64 chars_match(char* ptr1, char* ptr2) {
- i64 len = 0;
- while (*ptr2 != '\0' && *ptr1 == *ptr2) ptr1++, ptr2++, len++;
- return *ptr2 == '\0' ? len : 0;
-}
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// CUSTOM ALLOCATORS IMPLEMENTATION
-//-------------------------------------------------------------------------------------
-
-
-ptr bh_alloc(bh_allocator a, isize size) {
- return bh_alloc_aligned(a, size, 16);
-}
-
-ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment) {
- return a.proc(a.data, bh_allocator_action_alloc, size, alignment, NULL, 0);
-}
-
-ptr bh_resize(bh_allocator a, ptr data, isize new_size) {
- return bh_resize_aligned(a, data, new_size, 16);
-}
-
-ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment) {
- return a.proc(a.data, bh_allocator_action_resize, new_size, alignment, data, 0);
-}
-
-void bh_free(bh_allocator a, ptr data) {
- if (data != NULL) a.proc(a.data, bh_allocator_action_free, 0, 0, data, 0);
-}
-
-
-
-// HEAP ALLOCATOR IMPLEMENTATION
-
-bh_allocator bh_heap_allocator(void) {
- return (bh_allocator) {
- .proc = bh_heap_allocator_proc,
- .data = NULL
- };
-}
-
-BH_ALLOCATOR_PROC(bh_heap_allocator_proc) {
- ptr retval = NULL;
-
- switch (action) {
- case bh_allocator_action_alloc: {
- retval = aligned_alloc(alignment, size);
-
- if (flags & bh_allocator_flag_clear && retval != NULL) {
- memset(retval, 0, size);
- }
- } break;
-
- case bh_allocator_action_resize: {
- // TODO: Maybe replace with better custom function
- retval = realloc(prev_memory, size);
- } break;
-
- case bh_allocator_action_free: {
- free(prev_memory);
- } break;
- }
-
- return retval;
-}
-
-
-
-
-
-
-
-// ARENA ALLOCATOR IMPLEMENTATION
-void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size) {
- ptr data = bh_alloc(backing, arena_size);
-
- alloc->backing = backing;
- alloc->arena_size = arena_size;
- alloc->size = sizeof(ptr);
- alloc->first_arena = data;
- alloc->current_arena = data;
-
- ((bh__arena_internal *)(alloc->first_arena))->next_arena = NULL;
-}
-
-void bh_arena_free(bh_arena* alloc) {
- bh__arena_internal *walker = (bh__arena_internal *) alloc->first_arena;
- bh__arena_internal *trailer = walker;
- while (walker != NULL) {
- walker = walker->next_arena;
- bh_free(alloc->backing, trailer);
- trailer = walker;
- }
-
- alloc->first_arena = NULL;
- alloc->current_arena = NULL;
- alloc->arena_size = 0;
- alloc->size = 0;
-}
-
-bh_allocator bh_arena_allocator(bh_arena* alloc) {
- return (bh_allocator) {
- .proc = bh_arena_allocator_proc,
- .data = alloc,
- };
-}
-
-BH_ALLOCATOR_PROC(bh_arena_allocator_proc) {
- bh_arena* alloc_arena = (bh_arena*) data;
-
- ptr retval = NULL;
-
- switch (action) {
- case bh_allocator_action_alloc: {
-
- // TODO: Do this better because right now bh__align is bad
- // size = bh__align(size, alignment);
- if (size > alloc_arena->arena_size) {
- // Size too large for the arena
- return NULL;
- }
-
- if (alloc_arena->size + size >= alloc_arena->arena_size) {
- alloc_arena->size = sizeof(ptr);
- bh__arena_internal* new_arena = (bh__arena_internal *) bh_alloc(alloc_arena->backing, alloc_arena->arena_size);
-
- if (new_arena == NULL) {
- bh_printf_err("Arena Allocator: couldn't allocate new arena");
- return NULL;
- }
-
- new_arena->next_arena = NULL;
- ((bh__arena_internal *)(alloc_arena->current_arena))->next_arena = new_arena;
- alloc_arena->current_arena = new_arena;
- }
-
- retval = bh_pointer_add(alloc_arena->current_arena, alloc_arena->size);
- alloc_arena->size += size;
- } break;
-
- case bh_allocator_action_resize: {
- // Do nothing since this is a fixed allocator
- } break;
-
- case bh_allocator_action_free: {
- // Do nothing since this allocator isn't made for freeing memory
- } break;
- }
-
- return retval;
-}
-
-
-
-
-// SCRATCH ALLOCATOR IMPLEMENTATION
-void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size) {
- ptr memory = bh_alloc(backing, scratch_size);
-
- scratch->backing = backing;
- scratch->memory = memory;
- scratch->curr = memory;
- scratch->end = memory + scratch_size;
-}
-
-void bh_scratch_free(bh_scratch* scratch) {
- bh_free(scratch->backing, scratch->memory);
-
- scratch->memory = NULL;
- scratch->curr = NULL;
- scratch->end = NULL;
-}
-
-bh_allocator bh_scratch_allocator(bh_scratch* scratch) {
- return (bh_allocator) {
- .proc = bh_scratch_allocator_proc,
- .data = scratch,
- };
-}
-
-BH_ALLOCATOR_PROC(bh_scratch_allocator_proc) {
- bh_scratch* scratch = (bh_scratch*) data;
- ptr retval = NULL;
-
- switch (action) {
- case bh_allocator_action_alloc: {
- if (size > scratch->end - scratch->memory) {
- return NULL;
- }
-
- retval = scratch->curr;
- scratch->curr += size;
-
- if (scratch->curr >= scratch->end) {
- scratch->curr = scratch->memory;
- retval = scratch->curr;
- }
- } break;
-
- case bh_allocator_action_free:
- case bh_allocator_action_resize:
- // Do nothing
- break;
- }
-
- return retval;
-}
-
-
-//-------------------------------------------------------------------------------------
-// STRING IMPLEMENTATION (BROKEN)
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_STRING
-
-bh_string* bh_string_new_cap(unsigned long cap) {
- bh__string* str;
- str = (bh__string*) malloc(sizeof(*str) + sizeof(char) * cap + 1);
- str[0] = 0;
- return str + 1;
-}
-
-bh_string* bh_string_new_str(const char* cstr) {
- const i32 len = strlen(cstr);
- bh__string* str;
- i32 i;
-
- str = malloc(sizeof(*str) + sizeof(char) * len + 1);
- char* data = (char*) (str + 1);
- for (i = 0; i < len; i++) {
- data[i] = cstr[i];
- }
-
- data[len] = 0; // Always null terminate the string
-
- str->length = len;
- str->capacity = len;
- return str + 1;
-}
-
-b32 bh_string_delete(bh_string** str) {
- bh__string* strptr = bh__stringhead(*str);
- free(strptr);
- str->length = 0;
- str->capacity = 0;
- return 1;
-}
-
-b32 bh_string_grow(bh_string** str, u64 cap) {
- bh__string* strptr = bh__stringhead(*str);
- if (strptr->capacity >= cap) return 1;
-
- void* p;
- p = realloc(strptr, sizeof(*strptr) + sizeof(char) * cap + 1);
-
- strptr->capacity = cap;
-
- return 1;
-}
-
-void bh_string_append_bh_string(bh_string** str1, bh_string** str2) {
- if (!bh_string_ensure_capacity(str1, str1->length + str2->length)) return;
-
- //TODO: Replace with custom memory management
- memcpy(str1->data + str1->length, str2->data, str2->length);
- str1->length += str2->length;
-}
-
-void bh_string_append_cstr(bh_string* str1, const char* str2) {
- const i32 str2len = strlen(str2);
- if (!bh_string_ensure_capacity(str1, str1->length + str2len)) return;
-
- //TODO: Replace with custom memory management
- memcpy(str1->data + str1->length, str2, str2len);
- str1->length += str2len;
-}
-
-void bh_string_replace_at_bh_string(bh_string* dest, bh_string* src, u64 offset) {
- if (offset > dest->length) return;
- if (!bh_string_ensure_capacity(dest, offset + src->length)) return;
-
- memcpy(dest->data + offset, src->data, src->length);
- if (offset + src->length > dest->length)
- dest->length = offset + src->length;
-}
-
-void bh_string_replace_at_cstr(bh_string* dest, const char* src, u64 offset) {
- if (offset > dest->length) return;
- const i32 srclen = strlen(src);
- if (!bh_string_ensure_capacity(dest, offset + srclen)) return;
-
- memcpy(dest->data + offset, src, srclen);
- if (offset + srclen > dest->length)
- dest->length = offset + srclen;
-}
-
-void bh_string_insert_at_bh_string(bh_string* dest, bh_string* src, u64 offset) {
- if (!bh_string_ensure_capacity(dest, dest->length + src->length)) return;
-
- memmove(dest->data + offset + src->length, dest->data + offset, dest->length + src->length - offset);
- memcpy(dest->data + offset, src->data, src->length);
- dest->length += src->length;
-}
-
-void bh_string_insert_at_cstr(bh_string* dest, const char* src, u64 offset) {
- const i32 srclen = strlen(src);
- if (!bh_string_ensure_capacity(dest, dest->length + srclen)) return;
-
- // TODO: Use something better. This copies to a seperate buffer first
- memmove(dest->data + offset + srclen, dest->data + offset, dest->length + srclen - offset);
- memcpy(dest->data + offset, src, srclen);
- dest->length += srclen;
-}
-
-
-void bh_string_trim_end(bh_string* str, const char* charset) {
- while (charset_contains(charset, str->data[str->length - 1]))
- str->length--;
-}
-
-void bh_string_trim_begin(bh_string* str, const char* charset) {
- u32 off = 0, i;
- while (charset_contains(charset, str->data[off])) off++;
-
- if (off == 0) return;
-
- for (i = 0; i < str->length - off; i++) {
- str->data[i] = str->data[i + off];
- }
-
- str->length -= off;
-}
-
-void bh_string_trim_end_space(bh_string* str) {
- bh_string_trim_end(str, " \t\n\r");
-}
-
-// TEMP
-void bh_string_print(bh_string* str) {
- write(STDOUT_FILENO, str->data, str->length);
-}
-
-#endif // ifndef BH_NO_STRING
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// FILE IMPLEMENTATION
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_FILE
-
-bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand) {
- i32 sd_fd = -1;
- const char* filename = NULL;
-
- switch (stand) {
- case BH_FILE_STANDARD_INPUT:
- sd_fd = STDIN_FILENO;
- filename = "stdin"; // These are constants in the data section so everything should be okay
- break;
- case BH_FILE_STANDARD_OUTPUT:
- sd_fd = STDOUT_FILENO;
- filename = "stdout";
- break;
- case BH_FILE_STANDARD_ERROR:
- sd_fd = STDERR_FILENO;
- filename = "stderr";
- break;
- default:
- return BH_FILE_ERROR_BAD_FD;
- }
-
- file->fd = sd_fd;
- file->filename = filename;
-
- return BH_FILE_ERROR_NONE;
-}
-
-bh_file_error bh_file_create(bh_file* file, const char* filename) {
- // Need to do this to avoid compiler complaining about types
- bh_file_mode write_rw = (bh_file_mode) (BH_FILE_MODE_WRITE | BH_FILE_MODE_RW);
- return bh_file_open_mode(file, write_rw, filename);
-}
-
-bh_file_error bh_file_open(bh_file* file, const char* filename) {
- return bh_file_open_mode(file, BH_FILE_MODE_READ, filename);
-}
-
-bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename) {
-
- i32 os_mode = 0;
-
- switch (mode & BH_FILE_MODE_MODES) {
- case BH_FILE_MODE_READ: os_mode = O_RDONLY; break;
- case BH_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break;
- case BH_FILE_MODE_APPEND: os_mode = O_RDONLY | O_APPEND | O_CREAT; break;
- case BH_FILE_MODE_READ | BH_FILE_MODE_RW: os_mode = O_RDWR; break;
- case BH_FILE_MODE_WRITE | BH_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break;
- case BH_FILE_MODE_APPEND | BH_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break;
- //default: // TODO Handle errors
- }
-
- file->fd = open(filename, os_mode,
- S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP //+rw-rw-rw-
- );
- if (file->fd < 0) {
- return BH_FILE_ERROR_INVALID;
- }
-
- // TODO: Set this using some allocator
- file->filename = filename;
-
- return BH_FILE_ERROR_NONE;
-}
-
-bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename) {
- file->filename = filename; // This may be unsafe
- file->fd = fd;
- return BH_FILE_ERROR_NONE;
-}
-
-b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read) {
- isize res = pread(file->fd, buffer, buff_size, offset);
- if (res < 0) return 0;
- if (bytes_read) *bytes_read = res;
- return 1;
-}
-
-b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote) {
- isize res;
- i64 current_offset = 0;
- bh__file_seek_wrapper(file->fd, offset, BH_FILE_WHENCE_CURRENT, ¤t_offset);
- if (current_offset == offset) {
- // Standard in and out do like pwrite()
- res = write(file->fd, buffer, buff_size);
- } else {
- res = pwrite(file->fd, buffer, buff_size, offset);
- }
- if (res < 0) return 0;
- if (bytes_wrote) *bytes_wrote = res;
-
- return 1;
-}
-
-static b32 bh__file_seek_wrapper(i32 fd, i64 offset, bh_file_whence whence, i64* new_offset) {
- i64 res = lseek(fd, offset, whence);
- if (res < 0) return 0;
- if (new_offset) *new_offset = res;
- return 1;
-}
-
-// Returns new offset
-i64 bh_file_seek_to(bh_file* file, i64 offset) {
- i64 new_offset = -1;
- bh__file_seek_wrapper(file->fd, offset, BH_FILE_WHENCE_BEGIN, &new_offset);
- return new_offset;
-}
-
-i64 bh_file_seek_to_end(bh_file* file) {
- i64 new_offset = -1;
- bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_END, &new_offset);
- return new_offset;
-}
-
-i64 bh_file_skip(bh_file* file, i64 bytes) {
- i64 new_offset = 0;
- bh__file_seek_wrapper(file->fd, bytes, BH_FILE_WHENCE_CURRENT, &new_offset);
- return new_offset;
-}
-
-i64 bh_file_tell(bh_file* file) {
- i64 new_offset = 0;
- bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_CURRENT, &new_offset);
- return new_offset;
-}
-
-bh_file_error bh_file_close(bh_file* file) {
- bh_file_error err = BH_FILE_ERROR_NONE;
- i32 res = close(file->fd);
- if (res < 0)
- err = BH_FILE_ERROR_INVALID;
-
- return err;
-}
-
-b32 bh_file_read(bh_file* file, void* buffer, isize buff_size) {
- return bh_file_read_at(file, bh_file_tell(file), buffer, buff_size, NULL);
-}
-
-b32 bh_file_write(bh_file* file, void* buffer, isize buff_size) {
- return bh_file_write_at(file, bh_file_tell(file), buffer, buff_size, NULL);
-}
-
-i64 bh_file_size(bh_file* file) {
- i64 size = 0;
- i64 prev = bh_file_tell(file);
- bh_file_seek_to_end(file);
- size = bh_file_tell(file);
- bh_file_seek_to(file, prev);
- return size;
-}
-
-bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file) {
- bh_file_contents fc = {
- .allocator = alloc,
- .filename = file->filename,
- .length = 0, .data = NULL
- };
-
- isize size = bh_file_size(file);
- if (size <= 0) return fc;
-
- fc.data = bh_alloc(alloc, size + 1);
- fc.length = size;
- bh_file_read_at(file, 0, fc.data, fc.length, NULL);
- ((u8*) fc.data)[fc.length] = '\0';
-
- return fc;
-}
-
-bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename) {
- bh_file file;
- bh_file_open(&file, filename);
- bh_file_contents fc = bh_file_read_contents(alloc, &file);
- bh_file_close(&file);
- return fc;
-}
-
-b32 bh_file_contents_delete(bh_file_contents* contents) {
- bh_free(contents->allocator, contents->data);
- contents->length = 0;
- return 1;
-}
-
-#endif // ifndef BH_NO_FILE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// ALTERNATE PRINTF IMPLEMENTATION
-//-------------------------------------------------------------------------------------
-isize bh_printf(char const *fmt, ...) {
- isize res;
- va_list va;
- va_start(va, fmt);
- res = bh_printf_va(fmt, va);
- va_end(va);
- return res;
-}
-
-isize bh_printf_va(char const *fmt, va_list va) {
- bh_file file;
- bh_file_get_standard(&file, BH_FILE_STANDARD_OUTPUT);
- return bh_fprintf_va(&file, fmt, va);
-}
-
-isize bh_printf_err(char const *fmt, ...) {
- isize res;
- va_list va;
- va_start(va, fmt);
- res = bh_printf_err_va(fmt, va);
- va_end(va);
- return res;
-}
-
-isize bh_printf_err_va(char const *fmt, va_list va) {
- bh_file file;
- bh_file_get_standard(&file, BH_FILE_STANDARD_ERROR);
- return bh_fprintf_va(&file, fmt, va);
-}
-
-isize bh_fprintf(bh_file* f, char const *fmt, ...) {
- isize res;
- va_list va;
- va_start(va, fmt);
- res = bh_fprintf_va(f, fmt, va);
- va_end(va);
- return res;
-}
-
-isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va) {
- static char buf[4096];
- isize len = bh_snprintf_va(buf, sizeof(buf), fmt, va);
- bh_file_write(f, buf, len - 1);
- return len;
-}
-
-char* bh_bprintf(char const *fmt, ...) {
- char* res;
- va_list va;
- va_start(va, fmt);
- res = bh_bprintf_va(fmt, va);
- va_end(va);
- return res;
-}
-
-char* bh_bprintf_va(char const *fmt, va_list va) {
- static char buffer[4096];
- bh_snprintf_va(buffer, sizeof(buffer), fmt, va);
- return buffer;
-}
-
-isize bh_snprintf(char *str, isize n, char const *fmt, ...) {
- isize res;
- va_list va;
- va_start(va, fmt);
- res = bh_snprintf_va(str, n, fmt, va);
- va_end(va);
- return res;
-}
-
-isize bh__print_string(char* dest, isize n, char* src) {
- isize len = 0;
- while (n-- && (*dest++ = *src++)) len++;
- return len;
-}
-
-isize bh__printu64(char* str, isize n, bh__print_format format, u64 value) {
- char buf[128];
- buf[127] = 0;
- char* walker = buf + 127;
- u32 base = format.base ? format.base : 10, tmp;
-
- while (value > 0) {
- tmp = value % base;
- if (tmp > 9) {
- switch (tmp) {
- case 10: tmp = 'a'; break;
- case 11: tmp = 'b'; break;
- case 12: tmp = 'c'; break;
- case 13: tmp = 'd'; break;
- case 14: tmp = 'e'; break;
- case 15: tmp = 'f'; break;
- }
- } else {
- tmp += '0';
- }
-
- *--walker = tmp;
- value /= base;
- }
-
- if (format.base == 16) {
- *--walker = 'x';
- *--walker = '0';
- }
-
- return bh__print_string(str, n, walker);
-}
-
-isize bh__printi64(char* str, isize n, bh__print_format format, i64 value) {
- char buf[128];
- buf[127] = 0;
- char* walker = buf + 127;
- u32 base = format.base ? format.base : 10, tmp;
-
- b32 negative = value < 0;
- if (negative) value = -value;
-
- if (value == 0) {
- *--walker = '0';
- } else {
- while (value > 0) {
- tmp = value % base;
- if (tmp > 9) {
- switch (tmp) {
- case 10: tmp = 'a'; break;
- case 11: tmp = 'b'; break;
- case 12: tmp = 'c'; break;
- case 13: tmp = 'd'; break;
- case 14: tmp = 'e'; break;
- case 15: tmp = 'f'; break;
- }
- } else {
- tmp += '0';
- }
-
- *--walker = tmp;
- value /= base;
- }
- }
-
- if (negative) {
- *--walker = '-';
- }
-
- if (format.base == 16) {
- *--walker = 'x';
- *--walker = '0';
- }
-
- return bh__print_string(str, n, walker);
-}
-
-// TODO: This is very hacked together but for now it will work.
-isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va) {
- char const *text_start = str;
- isize res;
-
- while (*fmt) {
- bh__print_format format = { 0 };
- isize len = 0;
-
- while (*fmt && *fmt != '%') {
- *(str++) = *(fmt++);
- }
-
- if (!*fmt) goto end_of_format;
-
- fmt++;
-
- switch (*fmt++) {
- case 'o': format.base = 8; break;
- case 'x': format.base = 16; break;
- default: fmt--;
- }
-
- switch (*fmt) {
- case 'c': {
- char c = (char) va_arg(va, int);
- *(str++) = c;
- } break;
-
- case 'd': {
- i64 value = (i64) va_arg(va, int);
- len = bh__printi64(str, n, format, value);
- } break;
-
- case 'l': {
- i64 value = (i64) va_arg(va, long);
- len = bh__printi64(str, n, format, value);
- } break;
-
- case 'p': {
- u64 value = (u64) va_arg(va, ptr);
- format.base = 16;
- len = bh__printu64(str, n, format, value);
- } break;
-
- case 's': {
- char* s = va_arg(va, char *);
- len = bh__print_string(str, n, s);
- } break;
-
- default: fmt--;
- }
-
- fmt++;
-
-end_of_format:
- str += len;
- n -= len;
- }
-
- return str - text_start + 1;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// ARRAY IMPLEMENTATION
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_ARRAY
-
-b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap) {
- bh__arr* arrptr;
-
- if (*arr == NULL) {
- if (cap == 0 && elemsize == 0) return 1;
-
- arrptr = (bh__arr *) bh_alloc(alloc, sizeof(*arrptr) + elemsize * cap);
- if (arrptr == NULL) return 0;
-
- arrptr->allocator = alloc;
- arrptr->capacity = cap;
- arrptr->length = 0;
-
- } else {
- arrptr = bh__arrhead(*arr);
-
- if (arrptr->capacity < cap) {
- void* p;
- i32 newcap = arrptr->capacity;
- while (newcap < cap) newcap = BH_ARR_GROW_FORMULA(newcap);
-
- p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * newcap);
-
- if (p) {
- arrptr = (bh__arr *) p;
- arrptr->capacity = newcap;
- } else {
- return 0;
- }
- }
- }
-
- *arr = arrptr + 1;
- return 1;
-}
-
-b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) {
- if (*arr == NULL) return 0;
-
- bh__arr* arrptr = bh__arrhead(*arr);
- cap = bh_max(cap, arrptr->length);
-
- if (arrptr->capacity > cap) {
- void* p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * cap);
-
- if (p) {
- arrptr = (bh__arr *) p;
- arrptr->capacity = cap;
- } else {
- return 0;
- }
- }
-
- *arr = arrptr + 1;
- return 1;
-}
-
-b32 bh__arr_free(void **arr) {
- bh__arr* arrptr = bh__arrhead(*arr);
- bh_free(arrptr->allocator, arrptr);
- *arr = NULL;
-}
-
-void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize) {
- bh__arr* arrptr = bh__arrhead(arr);
-
- const i32 cap = arrptr->length;
-
- void* newarr = NULL;
- bh__arr_grow(alloc, &newarr, elemsize, cap);
- bh__arrhead(newarr)->length = cap;
- bh__arrhead(newarr)->capacity = cap;
- memcpy(newarr, arr, elemsize * arrptr->length);
-
- return newarr;
-}
-
-void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems) {
- bh__arr* arrptr = bh__arrhead(*arr);
-
- if (index >= arrptr->length) return; // Can't delete past the end of the array
- if (numelems <= 0) return; // Can't delete nothing
-
- memmove(
- (char *)(*arr) + elemsize * index, // Target
- (char *)(*arr) + elemsize * (index + numelems), // Source
- elemsize * (arrptr->length - (index + numelems))); // Length
- arrptr->length -= numelems;
-}
-
-void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) {
- if (numelems) {
- if (*arr == NULL) {
- bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, numelems); // Making a new array
- return;
- }
-
- bh__arr* arrptr = bh__arrhead(*arr);
- if (!bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, arrptr->length + numelems)) return; // Fail case
- memmove(
- (char *)(*arr) + elemsize * (index + numelems),
- (char *)(*arr) + elemsize * index,
- elemsize * (arrptr->length - index));
- arrptr->length += numelems;
- }
-}
-
-#endif // ifndef BH_NO_ARRAY
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-------------------------------------------------------------------------------------
-// HASHTABLE IMPLEMENTATION
-//-------------------------------------------------------------------------------------
-#ifndef BH_NO_HASHTABLE
-
-b32 bh__hash_init(bh_allocator allocator, bh__hash **table) {
- *table = bh_alloc(allocator, sizeof(bh__hash));
- if (*table == NULL) return 0;
-
- (*table)->allocator = allocator;
-
- for (i32 i = 0; i < BH__HASH_MODULUS; i++) {
- (*table)->arrs[i] = NULL;
- }
-
- return 1;
-}
-
-b32 bh__hash_free(bh__hash **table) {
- for (i32 i = 0; i < BH__HASH_MODULUS; i++) {
- if ((*table)->arrs[i] != NULL) {
- bh_arr_free((*table)->arrs[i]);
- }
- }
-
- bh_free((*table)->allocator, *table);
- *table = NULL;
-}
-
-// Assumes NULL terminated string for key
-ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key) {
- u64 index = bh__hash_function(key, 0);
-
- elemsize += BH__HASH_STORED_KEY_SIZE;
-
- ptr arrptr = table->arrs[index];
- i32 len = bh_arr_length(arrptr);
-
- while (len--) {
- if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) goto found_matching;
- arrptr = bh_pointer_add(arrptr, elemsize);
- }
-
- // Didn't find it in the array, make a new one
- arrptr = table->arrs[index];
- len = bh_arr_length(arrptr);
- bh__arr_grow(table->allocator, &arrptr, elemsize, len + 1);
- bh__arrhead(arrptr)->length++;
- table->arrs[index] = arrptr;
-
- arrptr = bh_pointer_add(arrptr, elemsize * len);
- strncpy(arrptr, key, BH__HASH_STORED_KEY_SIZE);
-
-found_matching:
- return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE);
-}
-
-b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key) {
- u64 index = bh__hash_function(key, 0);
-
- ptr arrptr = table->arrs[index];
- if (arrptr == NULL) return 0;
-
- i32 len = bh_arr_length(arrptr);
- i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;
-
- while (len--) {
- if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) return 1;
- arrptr = bh_pointer_add(arrptr, stride);
- }
-
- return 0;
-}
-
-ptr bh__hash_get(bh__hash *table, i32 elemsize, char *key) {
- u64 index = bh__hash_function(key, 0);
-
- ptr arrptr = table->arrs[index];
- if (arrptr == NULL) return NULL;
-
- i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;
-
- i32 len = bh_arr_length(arrptr);
- while (len--) {
- if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) {
- return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE);
- }
-
- return bh_pointer_add(arrptr, stride);
- }
-
- return NULL;
-}
-
-void bh__hash_delete(bh__hash *table, i32 elemsize, char *key) {
- u64 index = bh__hash_function(key, 0);
-
- ptr arrptr = table->arrs[index];
- i32 len = bh_arr_length(arrptr);
- if (arrptr == NULL) return; // Didn't exist
-
- i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;
- i32 i = 0;
-
- while (len && strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) != 0) {
- arrptr = bh_pointer_add(arrptr, stride);
- i++, len--;
- }
-
- if (len == 0) return; // Didn't exist
-
- bh__arr_deleten((void **) &arrptr, elemsize, i, 1);
-}
-
-bh_hash_iterator bh__hash_iter_setup(bh__hash *table, i32 elemsize) {
- bh_hash_iterator it = {
- .tab = table->arrs,
- .endtab = table->arrs + BH__HASH_MODULUS,
- .elemsize = elemsize,
- .entry = NULL
- };
- return it;
-}
-
-b32 bh_hash_iter_next(bh_hash_iterator* it) {
- if (it->tab == NULL) return 0;
-
- if (it->entry != NULL) {
- it->arrlen--;
- if (it->arrlen <= 0) {
- it->tab++;
- goto step_to_next;
- }
-
- it->entry = (bh__hash_entry *)bh_pointer_add(it->entry, BH__HASH_STORED_KEY_SIZE + it->elemsize);
- return 1;
- }
-
-step_to_next:
- // Step forward to find next valid
- while (*it->tab == NULL && it->tab != it->endtab) {
- it->tab++;
- }
-
- if (it->tab == it->endtab) return 0;
-
- it->entry = *it->tab;
- it->arrlen = bh_arr_length(it->entry);
- return 1;
-}
-
-#endif // ifndef BH_NO_HASHTABLE
-
-#endif // ifdef BH_DEFINE
-
-#endif // ifndef BH_H
+#ifndef BH_H\r
+#define BH_H\r
+\r
+#include <sys/stat.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <errno.h>\r
+\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <string.h> // TODO: Replace with needed functions\r
+#include <assert.h>\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better types\r
+//-------------------------------------------------------------------------------------\r
+typedef unsigned char u8;\r
+typedef unsigned short u16;\r
+typedef unsigned int u32;\r
+typedef unsigned long u64;\r
+typedef unsigned long long u128;\r
+typedef signed char i8;\r
+typedef signed short i16;\r
+typedef signed int i32;\r
+typedef signed long i64;\r
+typedef signed long long i128;\r
+typedef unsigned long isize;\r
+typedef i32 b32;\r
+typedef void* ptr;\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better character functions\r
+//-------------------------------------------------------------------------------------\r
+b32 char_is_alpha(const char a);\r
+b32 char_is_num(const char a);\r
+b32 char_is_alphanum(const char a);\r
+b32 char_is_whitespace(const char a);\r
+b32 char_in_range(const char lo, const char hi, const char a);\r
+char charset_contains(const char* charset, char ch);\r
+i64 chars_match(char* ptr1, char* ptr2);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better math functions\r
+//-------------------------------------------------------------------------------------\r
+#define bh_max(a, b) ((a) > (b) ? (a) : (b))\r
+#define bh_min(a, b) ((a) < (b) ? (a) : (b))\r
+#define bh_clamp(v, a, b) (bh_min((b), bh_max((a), (v))))\r
+#define bh_abs(x) ((x) < 0 ? -(x) : (x))\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Helpful macros\r
+//-------------------------------------------------------------------------------------\r
+#define bh_offset_of(Type, elem) ((isize)&(((Type)*) 0)->elem)\r
+#define bh_aligh_of(Type) bh_offset_of(struct { char c; Type member; }, member)\r
+#define bh_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while(0)\r
+\r
+#define bh_pointer_add(ptr, amm) ((void *)((u8 *) ptr + amm))\r
+#define BH_BIT(x) (1 << (x))\r
+#define BH_MASK_SET(var, set, mask) ((set) ? (var) |= (mask) : (var) &= ~(mask))\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Custom allocators\r
+//-------------------------------------------------------------------------------------\r
+\r
+typedef enum bh_allocator_actions {\r
+ bh_allocator_action_alloc,\r
+ bh_allocator_action_free,\r
+ bh_allocator_action_resize,\r
+} bh_allocator_actions;\r
+\r
+#define BH_ALLOCATOR_PROC(name) \\r
+ptr name(ptr data, bh_allocator_actions action, \\r
+ isize size, isize alignment, \\r
+ void* prev_memory, \\r
+ u64 flags)\r
+\r
+typedef BH_ALLOCATOR_PROC(bh__allocator_proc); // NOTE: so bh__allocator_proc can be used instead of that type\r
+\r
+typedef struct bh_allocator {\r
+ bh__allocator_proc* proc; // Procedure that can handle bh_allocator_actions\r
+ ptr data; // Pointer to the other data for the allocator\r
+} bh_allocator;\r
+\r
+typedef enum bh_allocator_flags {\r
+ bh_allocator_flag_clear = 1 // Sets all memory to be 0\r
+} bh_allocator_flags;\r
+\r
+ptr bh_alloc(bh_allocator a, isize size);\r
+ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment);\r
+ptr bh_resize(bh_allocator a, ptr data, isize new_size);\r
+ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment);\r
+void bh_free(bh_allocator a, ptr data);\r
+\r
+#define bh_alloc_item(allocator_, T) (T *) bh_alloc(allocator_, sizeof(T))\r
+#define bh_alloc_array(allocator_, T, n) (T *) bh_alloc(allocator_, sizeof(T) * (n))\r
+\r
+// NOTE: This should get optimized out since alignment should be a power of two\r
+#define bh__align(x, alignment) ((((x) / alignment) + 1) * alignment)\r
+\r
+\r
+\r
+\r
+// HEAP ALLOCATOR\r
+// Essentially a wrapper for malloc, free and realloc\r
+bh_allocator bh_heap_allocator(void);\r
+BH_ALLOCATOR_PROC(bh_heap_allocator_proc);\r
+\r
+\r
+\r
+\r
+\r
+// ARENA ALLOCATOR\r
+typedef struct bh_arena {\r
+ bh_allocator backing;\r
+ ptr first_arena, current_arena;\r
+ isize size, arena_size; // in bytes\r
+} bh_arena;\r
+\r
+typedef struct bh__arena_internal {\r
+ ptr next_arena;\r
+ void* data; // Not actually a pointer, just used for the offset\r
+} bh__arena_internal;\r
+\r
+void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size);\r
+void bh_arena_free(bh_arena* alloc);\r
+bh_allocator bh_arena_allocator(bh_arena* alloc);\r
+BH_ALLOCATOR_PROC(bh_arena_allocator_proc);\r
+\r
+\r
+\r
+// SCRATCH ALLOCATOR\r
+typedef struct bh_scratch {\r
+ bh_allocator backing;\r
+ ptr memory, end, curr;\r
+} bh_scratch;\r
+\r
+void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size);\r
+void bh_scratch_free(bh_scratch* scratch);\r
+bh_allocator bh_scratch_allocator(bh_scratch* scratch);\r
+BH_ALLOCATOR_PROC(bh_scratch_allocator_proc);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better strings\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_STRING\r
+\r
+typedef struct bh__string {\r
+ u64 length;\r
+ u64 capacity;\r
+} bh__string;\r
+\r
+typedef char bh_string;\r
+\r
+#define bh__stringhead(x) (((bh__string *)(x)) - 1)\r
+\r
+#define bh_string_new(x) _Generic((x), \\r
+ unsigned long: bh_string_new_cap, \\r
+ unsigned int: bh_string_new_cap, \\r
+ int: bh_string_new_cap, \\r
+ long: bh_string_new_cap, \\r
+ const char*: bh_string_new_str, \\r
+ char*: bh_string_new_str)(x)\r
+\r
+#define bh_string_append(str1, str2) _Generic((str2), \\r
+ bh_string*: bh_string_append_bh_string, \\r
+ char*: bh_string_append_cstr, \\r
+ const char*: bh_string_append_cstr)(str1, str2)\r
+\r
+#define bh_string_replace_at(dest, src, offset) _Generic((src), \\r
+ bh_string*: bh_string_replace_at_bh_string, \\r
+ char*: bh_string_replace_at_cstr, \\r
+ const char*: bh_string_replace_at_cstr)(dest, src, offset)\r
+\r
+#define bh_string_insert_at(dest, src, offset) _Generic((src), \\r
+ bh_string*: bh_string_insert_at_bh_string, \\r
+ char*: bh_string_insert_at_cstr, \\r
+ const char*: bh_string_insert_at_cstr)(dest, src, offset)\r
+\r
+bh_string bh_string_new_cap(unsigned long cap);\r
+bh_string bh_string_new_str(const char* cstr);\r
+b32 bh_string_delete(bh_string* str);\r
+b32 bh_string_ensure_capacity(bh_string* str, u64 cap);\r
+void bh_string_append_bh_string(bh_string* str1, bh_string* str2);\r
+void bh_string_append_cstr(bh_string* str1, const char* str2);\r
+void bh_string_replace_at_bh_string(bh_string* dest, bh_string* src, u64 offset);\r
+void bh_string_replace_at_cstr(bh_string* dest, const char* src, u64 offset);\r
+void bh_string_insert_at_bh_string(bh_string* dest, bh_string* src, u64 offset);\r
+void bh_string_insert_at_cstr(bh_string* dest, const char* src, u64 offset);\r
+void bh_string_trim_end(bh_string* str, const char* charset);\r
+void bh_string_trim_begin(bh_string* str, const char* charset);\r
+void bh_string_trim_end_space(bh_string* str);\r
+// TEMP\r
+void bh_string_print(bh_string* str);\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better files\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_FILE\r
+\r
+typedef enum bh_file_error {\r
+ BH_FILE_ERROR_NONE,\r
+ BH_FILE_ERROR_INVALID,\r
+ BH_FILE_ERROR_BAD_FD,\r
+} bh_file_error;\r
+\r
+typedef enum bh_file_mode {\r
+ BH_FILE_MODE_READ = 1 << 0,\r
+ BH_FILE_MODE_WRITE = 1 << 1,\r
+ BH_FILE_MODE_APPEND = 1 << 2,\r
+ BH_FILE_MODE_RW = 1 << 3,\r
+\r
+ BH_FILE_MODE_MODES = BH_FILE_MODE_READ | BH_FILE_MODE_WRITE | BH_FILE_MODE_APPEND | BH_FILE_MODE_RW\r
+} bh_file_mode;\r
+\r
+typedef enum bh_file_whence {\r
+ BH_FILE_WHENCE_BEGIN = SEEK_SET,\r
+ BH_FILE_WHENCE_CURRENT = SEEK_CUR,\r
+ BH_FILE_WHENCE_END = SEEK_END,\r
+} bh_file_whence;\r
+\r
+typedef int bh_file_descriptor;\r
+\r
+typedef struct bh_file {\r
+ bh_file_descriptor fd;\r
+ char const* filename;\r
+} bh_file;\r
+\r
+typedef enum bh_file_standard {\r
+ BH_FILE_STANDARD_INPUT,\r
+ BH_FILE_STANDARD_OUTPUT,\r
+ BH_FILE_STANDARD_ERROR\r
+} bh_file_standard;\r
+\r
+typedef struct bh_file_contents {\r
+ bh_allocator allocator;\r
+ const char *filename;\r
+ isize length;\r
+ void* data;\r
+} bh_file_contents;\r
+\r
+bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand);\r
+\r
+bh_file_error bh_file_create(bh_file* file, char const* filename);\r
+bh_file_error bh_file_open(bh_file* file, char const* filename);\r
+bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename);\r
+bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename);\r
+b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read);\r
+b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote);\r
+static b32 bh__file_seek_wrapper(i32 fd, i64 offset, bh_file_whence whence, i64* new_offset);\r
+i64 bh_file_seek_to_end(bh_file* file);\r
+i64 bh_file_skip(bh_file* file, i64 bytes);\r
+i64 bh_file_tell(bh_file* file);\r
+bh_file_error bh_file_close(bh_file* file);\r
+i32 bh_file_read(bh_file* file, void* buffer, isize buff_size);\r
+i32 bh_file_write(bh_file* file, void* buffer, isize buff_size);\r
+i64 bh_file_size(bh_file* file);\r
+\r
+#define bh_file_read_contents(allocator_, x) _Generic((x), \\r
+ bh_file*: bh_file_read_contents_bh_file, \\r
+ const char*: bh_file_read_contents_direct, \\r
+ char*: bh_file_read_contents_direct)((allocator_), x)\r
+\r
+bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file);\r
+bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename);\r
+i32 bh_file_contents_delete(bh_file_contents* contents);\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Alternate printing\r
+//-------------------------------------------------------------------------------------\r
+// Barebones implementation of printf. Does not support all format options\r
+// Currently supports:\r
+// %c - chars\r
+// %_(u)d - ints where _ is:\r
+// nothing - decimal\r
+// o - octal\r
+// x - hexadecimal\r
+// %_(u)l - longs where _ is:\r
+// nothing - decimal\r
+// o - octal\r
+// x - hexadecimal\r
+// %f - floating points\r
+// %s - null terminated strings\r
+// %p - pointers\r
+// %% - literal %\r
+\r
+typedef struct bh__print_format {\r
+ u32 base;\r
+} bh__print_format;\r
+\r
+isize bh_printf(char const *fmt, ...);\r
+isize bh_printf_va(char const *fmt, va_list va);\r
+isize bh_printf_err(char const *fmt, ...);\r
+isize bh_printf_err_va(char const *fmt, va_list va);\r
+isize bh_fprintf(bh_file* f, char const *fmt, ...);\r
+isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va);\r
+char* bh_bprintf(char const *fmt, ...);\r
+char* bh_bprintf_va(char const *fmt, va_list va);\r
+isize bh_snprintf(char *str, isize n, char const *fmt, ...);\r
+isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better debug functions\r
+//-------------------------------------------------------------------------------------\r
+#ifdef BH_DEBUG\r
+\r
+void* bh__debug_malloc(size_t size, const char* file, u64 line);\r
+void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line);\r
+void bh__debug_free(void* ptr, const char* file, u64 line);\r
+void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line);\r
+\r
+#ifdef BH_DEFINE\r
+\r
+void* bh__debug_malloc(size_t size, const char* file, u64 line) {\r
+ void* p = malloc(size);\r
+ bh_printf("[DEBUG] %p = malloc(%d) at %s:%d\n", p, size, file, line);\r
+ return p;\r
+}\r
+\r
+void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line) {\r
+ void* p = aligned_alloc(size, alignment);\r
+ bh_printf("[DEBUG] %p = aligned_alloc(%d, %d) at %s:%d\n", p, alignment, size, file, line);\r
+ return p;\r
+}\r
+\r
+void bh__debug_free(void* ptr, const char* file, u64 line) {\r
+ bh_printf("[DEBUG] free(%p) at %s:%d\n", ptr, file, line);\r
+ free(ptr);\r
+}\r
+\r
+void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line) {\r
+ void* p = realloc(ptr, size);\r
+ bh_printf("[DEBUG] %p = realloc(%p, %d) at %s:%d\n", p, ptr, size, file, line);\r
+ return p;\r
+}\r
+\r
+#endif\r
+\r
+#define malloc(size) (bh__debug_malloc(size, __FILE__, __LINE__))\r
+#define aligned_alloc(size, alignment) (bh__debug_aligned_alloc(size, alignment, __FILE__, __LINE__))\r
+#define free(ptr) (bh__debug_free(ptr, __FILE__, __LINE__))\r
+#define realloc(ptr, size) (bh__debug_realloc(ptr, size, __FILE__, __LINE__))\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// Better dynamically-sized arrays\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_ARRAY\r
+\r
+typedef struct bh__arr {\r
+ bh_allocator allocator;\r
+ i32 length, capacity;\r
+} bh__arr;\r
+\r
+#ifndef BH_ARR_GROW_FORMULA\r
+#define BH_ARR_GROW_FORMULA(x) ((x) > 0 ? ((x) << 1) : 4)\r
+#endif\r
+\r
+#define bh_arr(T) T*\r
+#define bh__arrhead(arr) (((bh__arr *)(arr)) - 1)\r
+\r
+#define bh_arr_allocator(arr) (arr ? bh__arrhead(arr)->allocator : bh_heap_allocator())\r
+#define bh_arr_length(arr) (arr ? bh__arrhead(arr)->length : 0)\r
+#define bh_arr_capacity(arr) (arr ? bh__arrhead(arr)->capacity : 0)\r
+#define bh_arr_size(arr) (arr ? bh__arrhead(arr)->capacity * sizeof(*(arr)) : 0)\r
+#define bh_arr_valid(arr, i) (arr ? (i32)(i) < bh__arrhead(arr)->length : 0)\r
+\r
+#define bh_arr_pop(arr) ((arr)[--bh__arrhead(arr)->length])\r
+#define bh_arr_last(arr) ((arr)[bh__arrhead(arr)->length - 1])\r
+#define bh_arr_end(arr, i) ((i) >= &(arr)[bh_arr_length(arr)])\r
+\r
+#define bh_arr_new(allocator_, arr, cap) (bh__arr_grow((allocator_), (void**) &(arr), sizeof(*(arr)), cap))\r
+#define bh_arr_free(arr) (bh__arr_free((void**) &(arr)))\r
+#define bh_arr_copy(allocator_, arr) (bh__arr_copy((allocator_), (arr), sizeof(*(arr))))\r
+\r
+#define bh_arr_grow(arr, cap) (bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), cap))\r
+#define bh_arr_shrink(arr, cap) (bh__arr_shrink((void **) &(arr), sizeof(*(arr)), cap))\r
+#define bh_arr_set_length(arr, n) ( \\r
+ bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), n), \\r
+ bh__arrhead(arr)->length = n)\r
+\r
+#define bh_arr_insertn(arr, i, n) (bh__arr_insertn((void **) &(arr), sizeof(*(arr)), i, n))\r
+\r
+#define bh_arr_insert_end(arr, n) ( \\r
+ bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + n), \\r
+ bh__arrhead(arr)->length += n)\r
+\r
+#define bh_arr_push(arr, value) ( \\r
+ bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + 1), \\r
+ arr[bh__arrhead(arr)->length++] = value)\r
+\r
+#define bh_arr_is_empty(arr) (arr ? bh__arrhead(arr)->length == 0 : 1)\r
+#define bh_arr_clear(arr) (arr ? (bh__arrhead(arr)->length = 0) : 0)\r
+\r
+#define bh_arr_deleten(arr, i, n) (bh__arr_deleten((void **) &(arr), sizeof(*(arr)), i, n))\r
+#define bh_arr_fastdelete(arr, i) (arr[i] = arr[--bh__arrhead(arr)->length])\r
+\r
+b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap);\r
+b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap);\r
+b32 bh__arr_free(void **arr);\r
+void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize);\r
+void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems);\r
+void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems);\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// HASH TABLE FUNCTIONS\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_HASHTABLE\r
+\r
+#define BH__HASH_STORED_KEY_SIZE 64\r
+typedef struct bh__hash_entry {\r
+ char key[BH__HASH_STORED_KEY_SIZE];\r
+ i32 value; // NOTE: Not actually an i32, just used as a placeholder for offset\r
+} bh__hash_entry;\r
+\r
+#define BH__HASH_MODULUS 1021\r
+#define BH__HASH_KEYSIZE 64\r
+#ifdef BH_DEFINE\r
+u64 bh__hash_function(const char* str, i32 len) {\r
+ u64 hash = 5381;\r
+ i32 c, l = 0;\r
+ if (len == 0) len = BH__HASH_KEYSIZE;\r
+\r
+ while ((c = *str++) && l++ < len) {\r
+ hash = (hash << 5) + hash + c;\r
+ }\r
+\r
+ return hash % BH__HASH_MODULUS;\r
+}\r
+#endif\r
+\r
+typedef struct bh_hash_iterator {\r
+ ptr *tab, *endtab;\r
+ i32 elemsize, arrlen;\r
+ bh__hash_entry* entry;\r
+} bh_hash_iterator;\r
+\r
+typedef struct bh__hash {\r
+ bh_allocator allocator;\r
+ ptr arrs[BH__HASH_MODULUS];\r
+} bh__hash;\r
+\r
+#define bh_hash(T) T*\r
+\r
+#ifdef BH_HASH_SIZE_SAFE\r
+ #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab))\r
+ #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab))\r
+ #define bh_hash_put(T, tab, key, value) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = (T) value))\r
+ #define bh_hash_has(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (bh__hash_has((bh__hash *) tab, sizeof(T), key)))\r
+ #define bh_hash_get(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key))))\r
+ #define bh_hash_delete(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_delete((bh__hash *) tab, sizeof(T), key))\r
+\r
+ #define bh_hash_iter_setup(T, tab) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_iter_setup((bh__hash *) tab, sizeof(T)))\r
+ #define bh_hash_iter_key(it) (it.entry->key)\r
+ #define bh_hash_iter_value(T, it) (assert(sizeof(T) == it.elemsize), *(T *)&(it.entry->value))\r
+#else\r
+ #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab))\r
+ #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab))\r
+ #define bh_hash_put(T, tab, key, value) (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = value)\r
+ #define bh_hash_has(T, tab, key) (bh__hash_has((bh__hash *) tab, sizeof(T), key))\r
+ #define bh_hash_get(T, tab, key) (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key)))\r
+ #define bh_hash_delete(T, tab, key) (bh__hash_delete((bh__hash *) tab, sizeof(T), key))\r
+\r
+ #define bh_hash_iter_setup(T, tab) (bh__hash_iter_setup((bh__hash *) tab, sizeof(T)))\r
+ #define bh_hash_iter_key(it) (it.entry->key)\r
+ #define bh_hash_iter_value(T, it) (*(T *)&(it.entry->value))\r
+#endif\r
+\r
+b32 bh__hash_init(bh_allocator allocator, bh__hash **table);\r
+b32 bh__hash_free(bh__hash **table);\r
+ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key);\r
+b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key);\r
+ptr bh__hash_get(bh__hash *table, i32 elemsize, char *key);\r
+void bh__hash_delete(bh__hash *table, i32 elemsize, char *key);\r
+bh_hash_iterator bh__hash_iter_setup(bh__hash *table, i32 elemsize);\r
+b32 bh_hash_iter_next(bh_hash_iterator* it);\r
+\r
+#endif\r
+\r
+#ifdef BH_DEFINE\r
+#undef BH_DEFINE\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// IMPLEMENTATIONS\r
+//-------------------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------------------\r
+// CHAR FUNCTIONS\r
+//-------------------------------------------------------------------------------------\r
+b32 char_is_alpha(const char a) {\r
+ return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z');\r
+}\r
+\r
+b32 char_is_num(const char a) {\r
+ return ('0' <= a && a <= '9');\r
+}\r
+\r
+b32 char_is_alphanum(const char a) {\r
+ return char_is_alpha(a) || char_is_num(a);\r
+}\r
+\r
+b32 char_is_whitespace(const char a) {\r
+ return charset_contains(" \t\r\n", a);\r
+}\r
+\r
+b32 char_in_range(const char lo, const char hi, const char a) {\r
+ return lo <= a <= hi;\r
+}\r
+\r
+char charset_contains(const char* charset, char ch) {\r
+ while (*charset) {\r
+ if (*charset == ch) return ch;\r
+ charset++;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+i64 chars_match(char* ptr1, char* ptr2) {\r
+ i64 len = 0;\r
+ while (*ptr2 != '\0' && *ptr1 == *ptr2) ptr1++, ptr2++, len++;\r
+ return *ptr2 == '\0' ? len : 0;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// CUSTOM ALLOCATORS IMPLEMENTATION\r
+//-------------------------------------------------------------------------------------\r
+\r
+\r
+ptr bh_alloc(bh_allocator a, isize size) {\r
+ return bh_alloc_aligned(a, size, 16);\r
+}\r
+\r
+ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment) {\r
+ return a.proc(a.data, bh_allocator_action_alloc, size, alignment, NULL, 0);\r
+}\r
+\r
+ptr bh_resize(bh_allocator a, ptr data, isize new_size) {\r
+ return bh_resize_aligned(a, data, new_size, 16);\r
+}\r
+\r
+ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment) {\r
+ return a.proc(a.data, bh_allocator_action_resize, new_size, alignment, data, 0);\r
+}\r
+\r
+void bh_free(bh_allocator a, ptr data) {\r
+ if (data != NULL) a.proc(a.data, bh_allocator_action_free, 0, 0, data, 0);\r
+}\r
+\r
+\r
+\r
+// HEAP ALLOCATOR IMPLEMENTATION\r
+\r
+bh_allocator bh_heap_allocator(void) {\r
+ return (bh_allocator) {\r
+ .proc = bh_heap_allocator_proc,\r
+ .data = NULL\r
+ };\r
+}\r
+\r
+BH_ALLOCATOR_PROC(bh_heap_allocator_proc) {\r
+ ptr retval = NULL;\r
+\r
+ switch (action) {\r
+ case bh_allocator_action_alloc: {\r
+ retval = aligned_alloc(alignment, size);\r
+\r
+ if (flags & bh_allocator_flag_clear && retval != NULL) {\r
+ memset(retval, 0, size);\r
+ }\r
+ } break;\r
+\r
+ case bh_allocator_action_resize: {\r
+ // TODO: Maybe replace with better custom function\r
+ retval = realloc(prev_memory, size);\r
+ } break;\r
+\r
+ case bh_allocator_action_free: {\r
+ free(prev_memory);\r
+ } break;\r
+ }\r
+\r
+ return retval;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+// ARENA ALLOCATOR IMPLEMENTATION\r
+void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size) {\r
+ arena_size = bh_max(arena_size, sizeof(ptr));\r
+ ptr data = bh_alloc(backing, arena_size);\r
+\r
+ alloc->backing = backing;\r
+ alloc->arena_size = arena_size;\r
+ alloc->size = sizeof(ptr);\r
+ alloc->first_arena = data;\r
+ alloc->current_arena = data;\r
+\r
+ ((bh__arena_internal *)(alloc->first_arena))->next_arena = NULL;\r
+}\r
+\r
+void bh_arena_free(bh_arena* alloc) {\r
+ bh__arena_internal *walker = (bh__arena_internal *) alloc->first_arena;\r
+ bh__arena_internal *trailer = walker;\r
+ while (walker != NULL) {\r
+ walker = walker->next_arena;\r
+ bh_free(alloc->backing, trailer);\r
+ trailer = walker;\r
+ }\r
+\r
+ alloc->first_arena = NULL;\r
+ alloc->current_arena = NULL;\r
+ alloc->arena_size = 0;\r
+ alloc->size = 0;\r
+}\r
+\r
+bh_allocator bh_arena_allocator(bh_arena* alloc) {\r
+ return (bh_allocator) {\r
+ .proc = bh_arena_allocator_proc,\r
+ .data = alloc,\r
+ };\r
+}\r
+\r
+BH_ALLOCATOR_PROC(bh_arena_allocator_proc) {\r
+ bh_arena* alloc_arena = (bh_arena*) data;\r
+\r
+ ptr retval = NULL;\r
+\r
+ switch (action) {\r
+ case bh_allocator_action_alloc: {\r
+\r
+ // TODO: Do this better because right now bh__align is bad\r
+ // size = bh__align(size, alignment);\r
+ if (size > alloc_arena->arena_size - sizeof(ptr)) {\r
+ // Size too large for the arena\r
+ return NULL;\r
+ }\r
+\r
+ if (alloc_arena->size + size >= alloc_arena->arena_size) {\r
+ alloc_arena->size = sizeof(ptr);\r
+ bh__arena_internal* new_arena = (bh__arena_internal *) bh_alloc(alloc_arena->backing, alloc_arena->arena_size);\r
+\r
+ if (new_arena == NULL) {\r
+ bh_printf_err("Arena Allocator: couldn't allocate new arena");\r
+ return NULL;\r
+ }\r
+\r
+ new_arena->next_arena = NULL;\r
+ ((bh__arena_internal *)(alloc_arena->current_arena))->next_arena = new_arena;\r
+ alloc_arena->current_arena = new_arena;\r
+ }\r
+\r
+ retval = bh_pointer_add(alloc_arena->current_arena, alloc_arena->size);\r
+ alloc_arena->size += size;\r
+ } break;\r
+\r
+ case bh_allocator_action_resize: {\r
+ // Do nothing since this is a fixed allocator\r
+ } break;\r
+\r
+ case bh_allocator_action_free: {\r
+ // Do nothing since this allocator isn't made for freeing memory\r
+ } break;\r
+ }\r
+\r
+ return retval;\r
+}\r
+\r
+\r
+\r
+\r
+// SCRATCH ALLOCATOR IMPLEMENTATION\r
+void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size) {\r
+ ptr memory = bh_alloc(backing, scratch_size);\r
+\r
+ scratch->backing = backing;\r
+ scratch->memory = memory;\r
+ scratch->curr = memory;\r
+ scratch->end = memory + scratch_size;\r
+}\r
+\r
+void bh_scratch_free(bh_scratch* scratch) {\r
+ bh_free(scratch->backing, scratch->memory);\r
+\r
+ scratch->memory = NULL;\r
+ scratch->curr = NULL;\r
+ scratch->end = NULL;\r
+}\r
+\r
+bh_allocator bh_scratch_allocator(bh_scratch* scratch) {\r
+ return (bh_allocator) {\r
+ .proc = bh_scratch_allocator_proc,\r
+ .data = scratch,\r
+ };\r
+}\r
+\r
+BH_ALLOCATOR_PROC(bh_scratch_allocator_proc) {\r
+ bh_scratch* scratch = (bh_scratch*) data;\r
+ ptr retval = NULL;\r
+\r
+ switch (action) {\r
+ case bh_allocator_action_alloc: {\r
+ if (size > scratch->end - scratch->memory) {\r
+ return NULL;\r
+ }\r
+\r
+ retval = scratch->curr;\r
+ scratch->curr += size;\r
+\r
+ if (scratch->curr >= scratch->end) {\r
+ scratch->curr = scratch->memory;\r
+ retval = scratch->curr;\r
+ }\r
+ } break;\r
+\r
+ case bh_allocator_action_free:\r
+ case bh_allocator_action_resize:\r
+ // Do nothing\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+}\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// STRING IMPLEMENTATION (BROKEN)\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_STRING\r
+\r
+bh_string* bh_string_new_cap(unsigned long cap) {\r
+ bh__string* str;\r
+ str = (bh__string*) malloc(sizeof(*str) + sizeof(char) * cap + 1);\r
+ str[0] = 0;\r
+ return str + 1;\r
+}\r
+\r
+bh_string* bh_string_new_str(const char* cstr) {\r
+ const i32 len = strlen(cstr);\r
+ bh__string* str;\r
+ i32 i;\r
+\r
+ str = malloc(sizeof(*str) + sizeof(char) * len + 1);\r
+ char* data = (char*) (str + 1);\r
+ for (i = 0; i < len; i++) {\r
+ data[i] = cstr[i];\r
+ }\r
+\r
+ data[len] = 0; // Always null terminate the string\r
+\r
+ str->length = len;\r
+ str->capacity = len;\r
+ return str + 1;\r
+}\r
+\r
+b32 bh_string_delete(bh_string** str) {\r
+ bh__string* strptr = bh__stringhead(*str);\r
+ free(strptr);\r
+ str->length = 0;\r
+ str->capacity = 0;\r
+ return 1;\r
+}\r
+\r
+b32 bh_string_grow(bh_string** str, u64 cap) {\r
+ bh__string* strptr = bh__stringhead(*str);\r
+ if (strptr->capacity >= cap) return 1;\r
+\r
+ void* p;\r
+ p = realloc(strptr, sizeof(*strptr) + sizeof(char) * cap + 1);\r
+\r
+ strptr->capacity = cap;\r
+\r
+ return 1;\r
+}\r
+\r
+void bh_string_append_bh_string(bh_string** str1, bh_string** str2) {\r
+ if (!bh_string_ensure_capacity(str1, str1->length + str2->length)) return;\r
+\r
+ //TODO: Replace with custom memory management\r
+ memcpy(str1->data + str1->length, str2->data, str2->length);\r
+ str1->length += str2->length;\r
+}\r
+\r
+void bh_string_append_cstr(bh_string* str1, const char* str2) {\r
+ const i32 str2len = strlen(str2);\r
+ if (!bh_string_ensure_capacity(str1, str1->length + str2len)) return;\r
+\r
+ //TODO: Replace with custom memory management\r
+ memcpy(str1->data + str1->length, str2, str2len);\r
+ str1->length += str2len;\r
+}\r
+\r
+void bh_string_replace_at_bh_string(bh_string* dest, bh_string* src, u64 offset) {\r
+ if (offset > dest->length) return;\r
+ if (!bh_string_ensure_capacity(dest, offset + src->length)) return;\r
+\r
+ memcpy(dest->data + offset, src->data, src->length);\r
+ if (offset + src->length > dest->length)\r
+ dest->length = offset + src->length;\r
+}\r
+\r
+void bh_string_replace_at_cstr(bh_string* dest, const char* src, u64 offset) {\r
+ if (offset > dest->length) return;\r
+ const i32 srclen = strlen(src);\r
+ if (!bh_string_ensure_capacity(dest, offset + srclen)) return;\r
+\r
+ memcpy(dest->data + offset, src, srclen);\r
+ if (offset + srclen > dest->length)\r
+ dest->length = offset + srclen;\r
+}\r
+\r
+void bh_string_insert_at_bh_string(bh_string* dest, bh_string* src, u64 offset) {\r
+ if (!bh_string_ensure_capacity(dest, dest->length + src->length)) return;\r
+\r
+ memmove(dest->data + offset + src->length, dest->data + offset, dest->length + src->length - offset);\r
+ memcpy(dest->data + offset, src->data, src->length);\r
+ dest->length += src->length;\r
+}\r
+\r
+void bh_string_insert_at_cstr(bh_string* dest, const char* src, u64 offset) {\r
+ const i32 srclen = strlen(src);\r
+ if (!bh_string_ensure_capacity(dest, dest->length + srclen)) return;\r
+\r
+ // TODO: Use something better. This copies to a seperate buffer first\r
+ memmove(dest->data + offset + srclen, dest->data + offset, dest->length + srclen - offset);\r
+ memcpy(dest->data + offset, src, srclen);\r
+ dest->length += srclen;\r
+}\r
+\r
+\r
+void bh_string_trim_end(bh_string* str, const char* charset) {\r
+ while (charset_contains(charset, str->data[str->length - 1]))\r
+ str->length--;\r
+}\r
+\r
+void bh_string_trim_begin(bh_string* str, const char* charset) {\r
+ u32 off = 0, i;\r
+ while (charset_contains(charset, str->data[off])) off++;\r
+\r
+ if (off == 0) return;\r
+\r
+ for (i = 0; i < str->length - off; i++) {\r
+ str->data[i] = str->data[i + off];\r
+ }\r
+\r
+ str->length -= off;\r
+}\r
+\r
+void bh_string_trim_end_space(bh_string* str) {\r
+ bh_string_trim_end(str, " \t\n\r");\r
+}\r
+\r
+// TEMP\r
+void bh_string_print(bh_string* str) {\r
+ write(STDOUT_FILENO, str->data, str->length);\r
+}\r
+\r
+#endif // ifndef BH_NO_STRING\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// FILE IMPLEMENTATION\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_FILE\r
+\r
+bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand) {\r
+ i32 sd_fd = -1;\r
+ const char* filename = NULL;\r
+\r
+ switch (stand) {\r
+ case BH_FILE_STANDARD_INPUT:\r
+ sd_fd = STDIN_FILENO;\r
+ filename = "stdin"; // These are constants in the data section so everything should be okay\r
+ break;\r
+ case BH_FILE_STANDARD_OUTPUT:\r
+ sd_fd = STDOUT_FILENO;\r
+ filename = "stdout";\r
+ break;\r
+ case BH_FILE_STANDARD_ERROR:\r
+ sd_fd = STDERR_FILENO;\r
+ filename = "stderr";\r
+ break;\r
+ default:\r
+ return BH_FILE_ERROR_BAD_FD;\r
+ }\r
+\r
+ file->fd = sd_fd;\r
+ file->filename = filename;\r
+\r
+ return BH_FILE_ERROR_NONE;\r
+}\r
+\r
+bh_file_error bh_file_create(bh_file* file, const char* filename) {\r
+ // Need to do this to avoid compiler complaining about types\r
+ bh_file_mode write_rw = (bh_file_mode) (BH_FILE_MODE_WRITE | BH_FILE_MODE_RW);\r
+ return bh_file_open_mode(file, write_rw, filename);\r
+}\r
+\r
+bh_file_error bh_file_open(bh_file* file, const char* filename) {\r
+ return bh_file_open_mode(file, BH_FILE_MODE_READ, filename);\r
+}\r
+\r
+bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename) {\r
+\r
+ i32 os_mode = 0;\r
+\r
+ switch (mode & BH_FILE_MODE_MODES) {\r
+ case BH_FILE_MODE_READ: os_mode = O_RDONLY; break;\r
+ case BH_FILE_MODE_WRITE: os_mode = O_WRONLY | O_CREAT | O_TRUNC; break;\r
+ case BH_FILE_MODE_APPEND: os_mode = O_RDONLY | O_APPEND | O_CREAT; break;\r
+ case BH_FILE_MODE_READ | BH_FILE_MODE_RW: os_mode = O_RDWR; break;\r
+ case BH_FILE_MODE_WRITE | BH_FILE_MODE_RW: os_mode = O_RDWR | O_CREAT | O_TRUNC; break;\r
+ case BH_FILE_MODE_APPEND | BH_FILE_MODE_RW: os_mode = O_RDWR | O_APPEND | O_CREAT; break;\r
+ //default: // TODO Handle errors\r
+ }\r
+\r
+ file->fd = open(filename, os_mode,\r
+ S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP //+rw-rw-rw-\r
+ );\r
+ if (file->fd < 0) {\r
+ return BH_FILE_ERROR_INVALID;\r
+ }\r
+\r
+ // TODO: Set this using some allocator\r
+ file->filename = filename;\r
+\r
+ return BH_FILE_ERROR_NONE;\r
+}\r
+\r
+bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename) {\r
+ file->filename = filename; // This may be unsafe\r
+ file->fd = fd;\r
+ return BH_FILE_ERROR_NONE;\r
+}\r
+\r
+b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read) {\r
+ isize res = pread(file->fd, buffer, buff_size, offset);\r
+ if (res < 0) return 0;\r
+ if (bytes_read) *bytes_read = res;\r
+ return 1;\r
+}\r
+\r
+b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote) {\r
+ isize res;\r
+ i64 current_offset = 0;\r
+ bh__file_seek_wrapper(file->fd, offset, BH_FILE_WHENCE_CURRENT, ¤t_offset);\r
+ if (current_offset == offset) {\r
+ // Standard in and out do like pwrite()\r
+ res = write(file->fd, buffer, buff_size);\r
+ } else {\r
+ res = pwrite(file->fd, buffer, buff_size, offset);\r
+ }\r
+ if (res < 0) return 0;\r
+ if (bytes_wrote) *bytes_wrote = res;\r
+\r
+ return 1;\r
+}\r
+\r
+static b32 bh__file_seek_wrapper(i32 fd, i64 offset, bh_file_whence whence, i64* new_offset) {\r
+ i64 res = lseek(fd, offset, whence);\r
+ if (res < 0) return 0;\r
+ if (new_offset) *new_offset = res;\r
+ return 1;\r
+}\r
+\r
+// Returns new offset\r
+i64 bh_file_seek_to(bh_file* file, i64 offset) {\r
+ i64 new_offset = -1;\r
+ bh__file_seek_wrapper(file->fd, offset, BH_FILE_WHENCE_BEGIN, &new_offset);\r
+ return new_offset;\r
+}\r
+\r
+i64 bh_file_seek_to_end(bh_file* file) {\r
+ i64 new_offset = -1;\r
+ bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_END, &new_offset);\r
+ return new_offset;\r
+}\r
+\r
+i64 bh_file_skip(bh_file* file, i64 bytes) {\r
+ i64 new_offset = 0;\r
+ bh__file_seek_wrapper(file->fd, bytes, BH_FILE_WHENCE_CURRENT, &new_offset);\r
+ return new_offset;\r
+}\r
+\r
+i64 bh_file_tell(bh_file* file) {\r
+ i64 new_offset = 0;\r
+ bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_CURRENT, &new_offset);\r
+ return new_offset;\r
+}\r
+\r
+bh_file_error bh_file_close(bh_file* file) {\r
+ bh_file_error err = BH_FILE_ERROR_NONE;\r
+ i32 res = close(file->fd);\r
+ if (res < 0)\r
+ err = BH_FILE_ERROR_INVALID;\r
+\r
+ return err;\r
+}\r
+\r
+b32 bh_file_read(bh_file* file, void* buffer, isize buff_size) {\r
+ return bh_file_read_at(file, bh_file_tell(file), buffer, buff_size, NULL);\r
+}\r
+\r
+b32 bh_file_write(bh_file* file, void* buffer, isize buff_size) {\r
+ return bh_file_write_at(file, bh_file_tell(file), buffer, buff_size, NULL);\r
+}\r
+\r
+i64 bh_file_size(bh_file* file) {\r
+ i64 size = 0;\r
+ i64 prev = bh_file_tell(file);\r
+ bh_file_seek_to_end(file);\r
+ size = bh_file_tell(file);\r
+ bh_file_seek_to(file, prev);\r
+ return size;\r
+}\r
+\r
+bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file) {\r
+ bh_file_contents fc = {\r
+ .allocator = alloc,\r
+ .filename = file->filename,\r
+ .length = 0, .data = NULL\r
+ };\r
+\r
+ isize size = bh_file_size(file);\r
+ if (size <= 0) return fc;\r
+\r
+ fc.data = bh_alloc(alloc, size + 1);\r
+ fc.length = size;\r
+ bh_file_read_at(file, 0, fc.data, fc.length, NULL);\r
+ ((u8*) fc.data)[fc.length] = '\0';\r
+\r
+ return fc;\r
+}\r
+\r
+bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename) {\r
+ bh_file file;\r
+ bh_file_open(&file, filename);\r
+ bh_file_contents fc = bh_file_read_contents(alloc, &file);\r
+ bh_file_close(&file);\r
+ return fc;\r
+}\r
+\r
+b32 bh_file_contents_delete(bh_file_contents* contents) {\r
+ bh_free(contents->allocator, contents->data);\r
+ contents->length = 0;\r
+ return 1;\r
+}\r
+\r
+#endif // ifndef BH_NO_FILE\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// ALTERNATE PRINTF IMPLEMENTATION\r
+//-------------------------------------------------------------------------------------\r
+isize bh_printf(char const *fmt, ...) {\r
+ isize res;\r
+ va_list va;\r
+ va_start(va, fmt);\r
+ res = bh_printf_va(fmt, va);\r
+ va_end(va);\r
+ return res;\r
+}\r
+\r
+isize bh_printf_va(char const *fmt, va_list va) {\r
+ bh_file file;\r
+ bh_file_get_standard(&file, BH_FILE_STANDARD_OUTPUT);\r
+ return bh_fprintf_va(&file, fmt, va);\r
+}\r
+\r
+isize bh_printf_err(char const *fmt, ...) {\r
+ isize res;\r
+ va_list va;\r
+ va_start(va, fmt);\r
+ res = bh_printf_err_va(fmt, va);\r
+ va_end(va);\r
+ return res;\r
+}\r
+\r
+isize bh_printf_err_va(char const *fmt, va_list va) {\r
+ bh_file file;\r
+ bh_file_get_standard(&file, BH_FILE_STANDARD_ERROR);\r
+ return bh_fprintf_va(&file, fmt, va);\r
+}\r
+\r
+isize bh_fprintf(bh_file* f, char const *fmt, ...) {\r
+ isize res;\r
+ va_list va;\r
+ va_start(va, fmt);\r
+ res = bh_fprintf_va(f, fmt, va);\r
+ va_end(va);\r
+ return res;\r
+}\r
+\r
+isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va) {\r
+ static char buf[4096];\r
+ isize len = bh_snprintf_va(buf, sizeof(buf), fmt, va);\r
+ bh_file_write(f, buf, len - 1);\r
+ return len;\r
+}\r
+\r
+char* bh_bprintf(char const *fmt, ...) {\r
+ char* res;\r
+ va_list va;\r
+ va_start(va, fmt);\r
+ res = bh_bprintf_va(fmt, va);\r
+ va_end(va);\r
+ return res;\r
+}\r
+\r
+char* bh_bprintf_va(char const *fmt, va_list va) {\r
+ static char buffer[4096];\r
+ bh_snprintf_va(buffer, sizeof(buffer), fmt, va);\r
+ return buffer;\r
+}\r
+\r
+isize bh_snprintf(char *str, isize n, char const *fmt, ...) {\r
+ isize res;\r
+ va_list va;\r
+ va_start(va, fmt);\r
+ res = bh_snprintf_va(str, n, fmt, va);\r
+ va_end(va);\r
+ return res;\r
+}\r
+\r
+isize bh__print_string(char* dest, isize n, char* src) {\r
+ isize len = 0;\r
+ while (n-- && (*dest++ = *src++)) len++;\r
+ return len;\r
+}\r
+\r
+isize bh__printu64(char* str, isize n, bh__print_format format, u64 value) {\r
+ char buf[128];\r
+ buf[127] = 0;\r
+ char* walker = buf + 127;\r
+ u32 base = format.base ? format.base : 10, tmp;\r
+\r
+ while (value > 0) {\r
+ tmp = value % base;\r
+ if (tmp > 9) {\r
+ switch (tmp) {\r
+ case 10: tmp = 'a'; break;\r
+ case 11: tmp = 'b'; break;\r
+ case 12: tmp = 'c'; break;\r
+ case 13: tmp = 'd'; break;\r
+ case 14: tmp = 'e'; break;\r
+ case 15: tmp = 'f'; break;\r
+ }\r
+ } else {\r
+ tmp += '0';\r
+ }\r
+\r
+ *--walker = tmp;\r
+ value /= base;\r
+ }\r
+\r
+ if (format.base == 16) {\r
+ *--walker = 'x';\r
+ *--walker = '0';\r
+ }\r
+\r
+ return bh__print_string(str, n, walker);\r
+}\r
+\r
+isize bh__printi64(char* str, isize n, bh__print_format format, i64 value) {\r
+ char buf[128];\r
+ buf[127] = 0;\r
+ char* walker = buf + 127;\r
+ u32 base = format.base ? format.base : 10, tmp;\r
+\r
+ b32 negative = value < 0;\r
+ if (negative) value = -value;\r
+\r
+ if (value == 0) {\r
+ *--walker = '0';\r
+ } else {\r
+ while (value > 0) {\r
+ tmp = value % base;\r
+ if (tmp > 9) {\r
+ switch (tmp) {\r
+ case 10: tmp = 'a'; break;\r
+ case 11: tmp = 'b'; break;\r
+ case 12: tmp = 'c'; break;\r
+ case 13: tmp = 'd'; break;\r
+ case 14: tmp = 'e'; break;\r
+ case 15: tmp = 'f'; break;\r
+ }\r
+ } else {\r
+ tmp += '0';\r
+ }\r
+\r
+ *--walker = tmp;\r
+ value /= base;\r
+ }\r
+ }\r
+\r
+ if (negative) {\r
+ *--walker = '-';\r
+ }\r
+\r
+ if (format.base == 16) {\r
+ *--walker = 'x';\r
+ *--walker = '0';\r
+ }\r
+\r
+ return bh__print_string(str, n, walker);\r
+}\r
+\r
+// TODO: This is very hacked together but for now it will work.\r
+isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va) {\r
+ char const *text_start = str;\r
+ isize res;\r
+\r
+ while (*fmt) {\r
+ bh__print_format format = { 0 };\r
+ isize len = 0;\r
+\r
+ while (*fmt && *fmt != '%') {\r
+ *(str++) = *(fmt++);\r
+ }\r
+\r
+ if (!*fmt) goto end_of_format;\r
+\r
+ fmt++;\r
+\r
+ switch (*fmt++) {\r
+ case 'o': format.base = 8; break;\r
+ case 'x': format.base = 16; break;\r
+ default: fmt--;\r
+ }\r
+\r
+ switch (*fmt) {\r
+ case 'c': {\r
+ char c = (char) va_arg(va, int);\r
+ *(str++) = c;\r
+ } break;\r
+\r
+ case 'd': {\r
+ i64 value = (i64) va_arg(va, int);\r
+ len = bh__printi64(str, n, format, value);\r
+ } break;\r
+\r
+ case 'l': {\r
+ i64 value = (i64) va_arg(va, long);\r
+ len = bh__printi64(str, n, format, value);\r
+ } break;\r
+\r
+ case 'p': {\r
+ u64 value = (u64) va_arg(va, ptr);\r
+ format.base = 16;\r
+ len = bh__printu64(str, n, format, value);\r
+ } break;\r
+\r
+ case 's': {\r
+ char* s = va_arg(va, char *);\r
+ len = bh__print_string(str, n, s);\r
+ } break;\r
+\r
+ case 'b': { // String with a length (not null terminated)\r
+ char* s = va_arg(va, char *);\r
+ i32 l = va_arg(va, int);\r
+ len = bh__print_string(str, bh_min(l, n), s);\r
+ } break;\r
+\r
+ default: fmt--;\r
+ }\r
+\r
+ fmt++;\r
+\r
+end_of_format:\r
+ str += len;\r
+ n -= len;\r
+ }\r
+\r
+ return str - text_start + 1;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// ARRAY IMPLEMENTATION\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_ARRAY\r
+\r
+b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap) {\r
+ bh__arr* arrptr;\r
+\r
+ if (*arr == NULL) {\r
+ if (cap == 0 && elemsize == 0) return 1;\r
+\r
+ arrptr = (bh__arr *) bh_alloc(alloc, sizeof(*arrptr) + elemsize * cap);\r
+ if (arrptr == NULL) return 0;\r
+\r
+ arrptr->allocator = alloc;\r
+ arrptr->capacity = cap;\r
+ arrptr->length = 0;\r
+\r
+ } else {\r
+ arrptr = bh__arrhead(*arr);\r
+\r
+ if (arrptr->capacity < cap) {\r
+ void* p;\r
+ i32 newcap = arrptr->capacity;\r
+ while (newcap < cap) newcap = BH_ARR_GROW_FORMULA(newcap);\r
+\r
+ p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * newcap);\r
+\r
+ if (p) {\r
+ arrptr = (bh__arr *) p;\r
+ arrptr->capacity = newcap;\r
+ } else {\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ *arr = arrptr + 1;\r
+ return 1;\r
+}\r
+\r
+b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) {\r
+ if (*arr == NULL) return 0;\r
+\r
+ bh__arr* arrptr = bh__arrhead(*arr);\r
+ cap = bh_max(cap, arrptr->length);\r
+\r
+ if (arrptr->capacity > cap) {\r
+ void* p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * cap);\r
+\r
+ if (p) {\r
+ arrptr = (bh__arr *) p;\r
+ arrptr->capacity = cap;\r
+ } else {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ *arr = arrptr + 1;\r
+ return 1;\r
+}\r
+\r
+b32 bh__arr_free(void **arr) {\r
+ bh__arr* arrptr = bh__arrhead(*arr);\r
+ bh_free(arrptr->allocator, arrptr);\r
+ *arr = NULL;\r
+}\r
+\r
+void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize) {\r
+ bh__arr* arrptr = bh__arrhead(arr);\r
+\r
+ const i32 cap = arrptr->length;\r
+\r
+ void* newarr = NULL;\r
+ bh__arr_grow(alloc, &newarr, elemsize, cap);\r
+ bh__arrhead(newarr)->length = cap;\r
+ bh__arrhead(newarr)->capacity = cap;\r
+ memcpy(newarr, arr, elemsize * arrptr->length);\r
+\r
+ return newarr;\r
+}\r
+\r
+void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems) {\r
+ bh__arr* arrptr = bh__arrhead(*arr);\r
+\r
+ if (index >= arrptr->length) return; // Can't delete past the end of the array\r
+ if (numelems <= 0) return; // Can't delete nothing\r
+\r
+ memmove(\r
+ (char *)(*arr) + elemsize * index, // Target\r
+ (char *)(*arr) + elemsize * (index + numelems), // Source\r
+ elemsize * (arrptr->length - (index + numelems))); // Length\r
+ arrptr->length -= numelems;\r
+}\r
+\r
+void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) {\r
+ if (numelems) {\r
+ if (*arr == NULL) {\r
+ bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, numelems); // Making a new array\r
+ return;\r
+ }\r
+\r
+ bh__arr* arrptr = bh__arrhead(*arr);\r
+ if (!bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, arrptr->length + numelems)) return; // Fail case\r
+ memmove(\r
+ (char *)(*arr) + elemsize * (index + numelems),\r
+ (char *)(*arr) + elemsize * index,\r
+ elemsize * (arrptr->length - index));\r
+ arrptr->length += numelems;\r
+ }\r
+}\r
+\r
+#endif // ifndef BH_NO_ARRAY\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+// HASHTABLE IMPLEMENTATION\r
+//-------------------------------------------------------------------------------------\r
+#ifndef BH_NO_HASHTABLE\r
+\r
+b32 bh__hash_init(bh_allocator allocator, bh__hash **table) {\r
+ *table = bh_alloc(allocator, sizeof(bh__hash));\r
+ if (*table == NULL) return 0;\r
+\r
+ (*table)->allocator = allocator;\r
+\r
+ for (i32 i = 0; i < BH__HASH_MODULUS; i++) {\r
+ (*table)->arrs[i] = NULL;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+b32 bh__hash_free(bh__hash **table) {\r
+ for (i32 i = 0; i < BH__HASH_MODULUS; i++) {\r
+ if ((*table)->arrs[i] != NULL) {\r
+ bh_arr_free((*table)->arrs[i]);\r
+ }\r
+ }\r
+\r
+ bh_free((*table)->allocator, *table);\r
+ *table = NULL;\r
+}\r
+\r
+// Assumes NULL terminated string for key\r
+ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key) {\r
+ u64 index = bh__hash_function(key, 0);\r
+\r
+ elemsize += BH__HASH_STORED_KEY_SIZE;\r
+\r
+ ptr arrptr = table->arrs[index];\r
+ i32 len = bh_arr_length(arrptr);\r
+\r
+ while (len--) {\r
+ if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) goto found_matching;\r
+ arrptr = bh_pointer_add(arrptr, elemsize);\r
+ }\r
+\r
+ // Didn't find it in the array, make a new one\r
+ arrptr = table->arrs[index];\r
+ len = bh_arr_length(arrptr);\r
+ bh__arr_grow(table->allocator, &arrptr, elemsize, len + 1);\r
+ bh__arrhead(arrptr)->length++;\r
+ table->arrs[index] = arrptr;\r
+\r
+ arrptr = bh_pointer_add(arrptr, elemsize * len);\r
+ strncpy(arrptr, key, BH__HASH_STORED_KEY_SIZE);\r
+\r
+found_matching:\r
+ return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE);\r
+}\r
+\r
+b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key) {\r
+ u64 index = bh__hash_function(key, 0);\r
+\r
+ ptr arrptr = table->arrs[index];\r
+ if (arrptr == NULL) return 0;\r
+\r
+ i32 len = bh_arr_length(arrptr);\r
+ i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;\r
+\r
+ while (len--) {\r
+ if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) return 1;\r
+ arrptr = bh_pointer_add(arrptr, stride);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+ptr bh__hash_get(bh__hash *table, i32 elemsize, char *key) {\r
+ u64 index = bh__hash_function(key, 0);\r
+\r
+ ptr arrptr = table->arrs[index];\r
+ if (arrptr == NULL) return NULL;\r
+\r
+ i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;\r
+\r
+ i32 len = bh_arr_length(arrptr);\r
+ while (len--) {\r
+ if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) {\r
+ return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE);\r
+ }\r
+\r
+ arrptr = bh_pointer_add(arrptr, stride);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+void bh__hash_delete(bh__hash *table, i32 elemsize, char *key) {\r
+ u64 index = bh__hash_function(key, 0);\r
+\r
+ ptr arrptr = table->arrs[index], walker;\r
+ if (arrptr == NULL) return; // Didn't exist\r
+ walker = arrptr;\r
+\r
+ i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;\r
+ i32 i = 0;\r
+\r
+ i32 len = bh_arr_length(arrptr);\r
+ while (len && strncmp(key, (char *) walker, BH__HASH_STORED_KEY_SIZE) != 0) {\r
+ walker = bh_pointer_add(walker, stride);\r
+ i++, len--;\r
+ }\r
+\r
+ if (len == 0) return; // Didn't exist\r
+\r
+ bh__arr_deleten((void **) &arrptr, stride, i, 1);\r
+ table->arrs[index] = arrptr;\r
+}\r
+\r
+bh_hash_iterator bh__hash_iter_setup(bh__hash *table, i32 elemsize) {\r
+ bh_hash_iterator it = {\r
+ .tab = table->arrs,\r
+ .endtab = table->arrs + BH__HASH_MODULUS,\r
+ .elemsize = elemsize,\r
+ .entry = NULL\r
+ };\r
+ return it;\r
+}\r
+\r
+b32 bh_hash_iter_next(bh_hash_iterator* it) {\r
+ if (it->tab == NULL) return 0;\r
+\r
+ if (it->entry != NULL) {\r
+ it->arrlen--;\r
+ if (it->arrlen <= 0) {\r
+ it->tab++;\r
+ goto step_to_next;\r
+ }\r
+\r
+ it->entry = (bh__hash_entry *)bh_pointer_add(it->entry, BH__HASH_STORED_KEY_SIZE + it->elemsize);\r
+ return 1;\r
+ }\r
+\r
+step_to_next:\r
+ // Step forward to find next valid\r
+ while (*it->tab == NULL && it->tab != it->endtab) {\r
+ it->tab++;\r
+ }\r
+\r
+ if (it->tab == it->endtab) return 0;\r
+\r
+ it->entry = *it->tab;\r
+ it->arrlen = bh_arr_length(it->entry);\r
+ if (it->arrlen <= 0) {\r
+ it->tab++;\r
+ goto step_to_next;\r
+ }\r
+ return 1;\r
+}\r
+\r
+#endif // ifndef BH_NO_HASHTABLE\r
+\r
+#endif // ifdef BH_DEFINE\r
+\r
+#endif // ifndef BH_H\r
-
-#include "onyxlex.h"
-#include "onyxparser.h"
-
-struct OnyxTypeInfo builtin_types[] = {
- { ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" },
- { ONYX_TYPE_INFO_KIND_VOID, 0, "void" },
-
- { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1 },
-
- { ONYX_TYPE_INFO_KIND_UINT8, 1, "u8", 1, 1, 0, 0 },
- { ONYX_TYPE_INFO_KIND_UINT16, 2, "u16", 1, 1, 0, 0 },
- { ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0 },
- { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0 },
-
- { ONYX_TYPE_INFO_KIND_INT8, 1, "i8", 1, 0, 0, 0 },
- { ONYX_TYPE_INFO_KIND_INT16, 2, "i16", 1, 0, 0, 0 },
- { ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0 },
- { ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0 },
-
- { ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0 },
- { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0 },
- { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0 },
-
- { 0xffffffff } // Sentinel
-};
-
-static OnyxAstNode error_node = { { ONYX_AST_NODE_KIND_ERROR, 0, NULL, &builtin_types[0], NULL, NULL, NULL } };
-
-static void parser_next_token(OnyxParser* parser) {
- parser->prev_token = parser->curr_token;
- parser->curr_token++;
- while (parser->curr_token->type == TOKEN_TYPE_COMMENT) parser->curr_token++;
-}
-
-static b32 is_terminating_token(OnyxTokenType token_type) {
- switch (token_type) {
- case TOKEN_TYPE_SYM_SEMICOLON:
- case TOKEN_TYPE_CLOSE_BRACE:
- case TOKEN_TYPE_OPEN_BRACE:
- case TOKEN_TYPE_END_STREAM:
- return 1;
- default:
- return 0;
- }
-}
-
-// Advances to next token no matter what
-static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type) {
- OnyxToken* token = parser->curr_token;
- parser_next_token(parser);
-
- if (token->type != token_type) {
- onyx_message_add(parser->msgs,
- ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
- token->pos,
- onyx_get_token_type_name(token_type), onyx_get_token_type_name(token->type));
- return NULL;
- }
-
- return token;
-}
-
-static OnyxAstNode* parse_factor(OnyxParser* parser) {
- return &error_node;
-}
-
-static OnyxAstNode* parse_expression(OnyxParser* parser) {
- return &error_node;
-}
-
-static OnyxAstNode* parse_if_stmt(OnyxParser* parser) {
- return &error_node;
-}
-
-static OnyxAstNode* parse_expression_statement(OnyxParser* parser) {
-
-}
-
-static OnyxAstNode* parse_return_statement(OnyxParser* parser) {
- expect(parser, TOKEN_TYPE_KEYWORD_RETURN);
-
- OnyxAstNode* return_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_RETURN);
- return_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_VOID];
- OnyxAstNode* expr = NULL;
-
- parser_next_token(parser);
- if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {
- expr = parse_expression(parser);
-
- if (expr == NULL || expr == &error_node) {
- return &error_node;
- }
- }
-
- return return_node;
-}
-
-static OnyxAstNodeBlock* parse_block(OnyxParser* parser);
-
-static OnyxAstNode* parse_statement(OnyxParser* parser) {
- switch (parser->curr_token->type) {
- case TOKEN_TYPE_KEYWORD_RETURN:
- return parse_return_statement(parser);
-
- case TOKEN_TYPE_OPEN_BRACE:
- return (OnyxAstNode *) parse_block(parser);
-
- case TOKEN_TYPE_SYMBOL:
- case TOKEN_TYPE_OPEN_PAREN:
- case TOKEN_TYPE_SYM_PLUS:
- case TOKEN_TYPE_SYM_MINUS:
- case TOKEN_TYPE_SYM_BANG:
- case TOKEN_TYPE_LITERAL_NUMERIC:
- case TOKEN_TYPE_LITERAL_STRING:
- return parse_expression_statement(parser);
-
- case TOKEN_TYPE_KEYWORD_IF:
- return parse_if_stmt(parser);
-
- case TOKEN_TYPE_SYM_SEMICOLON:
- return NULL;
-
- default:
- parser_next_token(parser);
- return NULL;
- }
-}
-
-static OnyxAstNodeBlock* parse_block(OnyxParser* parser) {
- // --- is for an empty block
- if (parser->curr_token->type == TOKEN_TYPE_SYM_MINUS) {
- expect(parser, TOKEN_TYPE_SYM_MINUS);
- expect(parser, TOKEN_TYPE_SYM_MINUS);
- expect(parser, TOKEN_TYPE_SYM_MINUS);
- return NULL;
- }
-
- expect(parser, TOKEN_TYPE_OPEN_BRACE);
-
- OnyxAstNodeBlock* block = (OnyxAstNodeBlock *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BLOCK);
-
- OnyxAstNode** next = &block->body;
- OnyxAstNode* stmt = NULL;
- while (parser->curr_token->type != TOKEN_TYPE_CLOSE_BRACE) {
- stmt = parse_statement(parser);
-
- if (stmt != NULL && stmt->kind != ONYX_AST_NODE_KIND_ERROR) {
- *next = stmt;
- next = &stmt->next;
- }
-
- expect(parser, TOKEN_TYPE_SYM_SEMICOLON);
- }
-
- return block;
-}
-
-static OnyxTypeInfo* parse_type(OnyxParser* parser) {
- OnyxTypeInfo* type_info = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];
-
- OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);
- if (symbol == NULL) return type_info;
-
- onyx_token_null_toggle(*symbol);
-
- if (!bh_hash_has(OnyxAstNode*, parser->identifiers, symbol->token)) {
- onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, symbol->pos, symbol->token);
- } else {
- OnyxAstNode* type_info_node = bh_hash_get(OnyxAstNode*, parser->identifiers, symbol->token);
-
- if (type_info_node->kind == ONYX_AST_NODE_KIND_TYPE) {
- type_info = type_info_node->type;
- }
- }
-
- onyx_token_null_toggle(*symbol);
- return type_info;
-}
-
-static OnyxAstNodeParam* parse_function_params(OnyxParser* parser) {
- expect(parser, TOKEN_TYPE_OPEN_PAREN);
-
- if (parser->curr_token->type == TOKEN_TYPE_CLOSE_PAREN) {
- parser_next_token(parser);
- return NULL;
- }
-
- OnyxAstNodeParam* first_param = NULL;
-
- OnyxAstNodeParam* curr_param = NULL;
- OnyxAstNodeParam* trailer = NULL;
-
- OnyxToken* symbol;
- while (parser->curr_token->type != TOKEN_TYPE_CLOSE_PAREN) {
- if (parser->curr_token->type == TOKEN_TYPE_SYM_COMMA) parser_next_token(parser);
-
- symbol = expect(parser, TOKEN_TYPE_SYMBOL);
-
- curr_param = (OnyxAstNodeParam *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PARAM);
- curr_param->token = symbol;
- curr_param->type = parse_type(parser);
-
- if (first_param == NULL) first_param = curr_param;
-
- curr_param->next = NULL;
- if (trailer) trailer->next = curr_param;
-
- trailer = curr_param;
- }
-
- parser_next_token(parser); // Skip the )
- return first_param;
-}
-
-static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) {
- expect(parser, TOKEN_TYPE_KEYWORD_PROC);
-
- OnyxAstNodeFuncDef* func_def = (OnyxAstNodeFuncDef *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_FUNCDEF);
- func_def->param_count = 0;
-
- OnyxAstNodeParam* params = parse_function_params(parser);
- func_def->params = params;
-
- for (OnyxAstNode* walker = (OnyxAstNode *) params; walker != NULL; walker = walker->next)
- func_def->param_count++;
-
- expect(parser, TOKEN_TYPE_RIGHT_ARROW);
-
- OnyxTypeInfo* return_type = parse_type(parser);
- func_def->return_type = return_type;
-
- func_def->body = parse_block(parser);
- return func_def;
-}
-
-static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) {
- switch (parser->curr_token->type) {
- case TOKEN_TYPE_KEYWORD_USE:
- assert(0);
- break;
-
- case TOKEN_TYPE_KEYWORD_EXPORT:
- assert(0);
- break;
-
- case TOKEN_TYPE_SYMBOL: {
- OnyxToken* symbol = parser->curr_token;
- parser_next_token(parser);
-
- expect(parser, TOKEN_TYPE_SYM_COLON);
- expect(parser, TOKEN_TYPE_SYM_COLON);
-
- if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {
- OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);
- func_def->token = symbol;
- return (OnyxAstNode *) func_def;
-
- } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {
- // Handle struct case
- assert(0);
- } else {
- onyx_message_add(parser->msgs,
- ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(parser->curr_token->type));
- }
- } break;
- }
-
- parser_next_token(parser);
- return NULL;
-}
-
-
-
-
-
-
-
-OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\
- OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode));
- node->kind = kind;
-
- return node;
-}
-
-OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) {
- OnyxParser parser;
-
- bh_hash_init(bh_heap_allocator(), parser.identifiers);
-
- OnyxTypeInfo* it = &builtin_types[0];
- while (it->kind != 0xffffffff) {
- OnyxAstNode* tmp = onyx_ast_node_new(alloc, ONYX_AST_NODE_KIND_TYPE);
- tmp->type = it;
- bh_hash_put(OnyxAstNode*, parser.identifiers, (char *)it->name, tmp);
- it++;
- }
-
- parser.allocator = alloc;
- parser.tokenizer = tokenizer;
- parser.curr_token = tokenizer->tokens;
- parser.prev_token = NULL;
- parser.msgs = msgs;
-
- return parser;
-}
-
-void onyx_parser_free(OnyxParser* parser) {
- bh_hash_free(parser->identifiers);
-}
-
-OnyxAstNode* onyx_parse(OnyxParser *parser) {
- OnyxAstNode* program = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PROGRAM);
-
- OnyxAstNode** prev_stmt = &program->next;
- OnyxAstNode* curr_stmt = NULL;
- while (parser->curr_token->type != TOKEN_TYPE_END_STREAM) {
- curr_stmt = parse_top_level_statement(parser);
-
- // Building a linked list of statements down the "next" chain
- if (curr_stmt != NULL && curr_stmt != &error_node) {
- *prev_stmt = curr_stmt;
- prev_stmt = &curr_stmt->next;
- }
- }
-
- return program;
-}
+\r
+#include "onyxlex.h"\r
+#include "onyxparser.h"\r
+\r
+static const char* ast_node_names[] = {\r
+ "ERROR",\r
+ "PROGRAM",\r
+\r
+ "FUNCDEF",\r
+ "BLOCK",\r
+ "SCOPE",\r
+ "LOCAL",\r
+\r
+ "ADD",\r
+ "MINUS",\r
+ "MULTIPLY",\r
+ "DIVIDE",\r
+ "MODULUS",\r
+ "NEGATE",\r
+\r
+ "TYPE",\r
+ "LITERAL",\r
+ "CAST",\r
+ "PARAM",\r
+ "CALL",\r
+ "ASSIGN",\r
+ "RETURN",\r
+\r
+ "EQUAL",\r
+ "NOT_EQUAL",\r
+ "GREATER",\r
+ "GREATER_EQUAL",\r
+ "LESS",\r
+ "LESS_EQUAL",\r
+ "NOT",\r
+\r
+ "IF",\r
+ "LOOP",\r
+\r
+ "ONYX_AST_NODE_KIND_COUNT",\r
+};\r
+\r
+struct OnyxTypeInfo builtin_types[] = {\r
+ { ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" },\r
+ { ONYX_TYPE_INFO_KIND_VOID, 0, "void" },\r
+\r
+ { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1 },\r
+\r
+ { ONYX_TYPE_INFO_KIND_UINT8, 1, "u8", 1, 1, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_UINT16, 2, "u16", 1, 1, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0 },\r
+\r
+ { ONYX_TYPE_INFO_KIND_INT8, 1, "i8", 1, 0, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_INT16, 2, "i16", 1, 0, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0 },\r
+ { ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0 },\r
+\r
+ { ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0 },\r
+ { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0 },\r
+ { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0 },\r
+\r
+ { 0xffffffff } // Sentinel\r
+};\r
+\r
+static OnyxAstNode error_node = { { ONYX_AST_NODE_KIND_ERROR, 0, NULL, &builtin_types[0], NULL, NULL, NULL } };\r
+\r
+// NOTE: Forward declarations\r
+static void parser_next_token(OnyxParser* parser);\r
+static void parser_prev_token(OnyxParser* parser);\r
+static b32 is_terminating_token(OnyxTokenType token_type);\r
+static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type);\r
+static OnyxAstNodeScope* enter_scope(OnyxParser* parser);\r
+static OnyxAstNodeScope* leave_scope(OnyxParser* parser);\r
+static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local);\r
+static OnyxAstNode* parse_factor(OnyxParser* parser);\r
+static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left);\r
+static OnyxAstNode* parse_expression(OnyxParser* parser);\r
+static OnyxAstNode* parse_if_stmt(OnyxParser* parser);\r
+static OnyxAstNode* parse_expression_statement(OnyxParser* parser);\r
+static OnyxAstNode* parse_return_statement(OnyxParser* parser);\r
+static OnyxAstNodeBlock* parse_block(OnyxParser* parser, b32 belongs_to_function);\r
+static OnyxAstNode* parse_statement(OnyxParser* parser);\r
+static OnyxTypeInfo* parse_type(OnyxParser* parser);\r
+static OnyxAstNodeParam* parse_function_params(OnyxParser* parser);\r
+static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser);\r
+static OnyxAstNode* parse_top_level_statement(OnyxParser* parser);\r
+\r
+static void parser_next_token(OnyxParser* parser) {\r
+ parser->prev_token = parser->curr_token;\r
+ parser->curr_token++;\r
+ while (parser->curr_token->type == TOKEN_TYPE_COMMENT) parser->curr_token++;\r
+}\r
+\r
+static void parser_prev_token(OnyxParser* parser) {\r
+ // TODO: This is probably wrong\r
+ parser->prev_token--;\r
+ while (parser->prev_token->type == TOKEN_TYPE_COMMENT) parser->prev_token--;\r
+ parser->curr_token = parser->prev_token;\r
+ parser->prev_token--;\r
+}\r
+\r
+static b32 is_terminating_token(OnyxTokenType token_type) {\r
+ switch (token_type) {\r
+ case TOKEN_TYPE_SYM_SEMICOLON:\r
+ case TOKEN_TYPE_CLOSE_BRACE:\r
+ case TOKEN_TYPE_OPEN_BRACE:\r
+ case TOKEN_TYPE_END_STREAM:\r
+ return 1;\r
+ default:\r
+ return 0;\r
+ }\r
+}\r
+\r
+// Advances to next token no matter what\r
+static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type) {\r
+ OnyxToken* token = parser->curr_token;\r
+ parser_next_token(parser);\r
+\r
+ if (token->type != token_type) {\r
+ onyx_message_add(parser->msgs,\r
+ ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,\r
+ token->pos,\r
+ onyx_get_token_type_name(token_type), onyx_get_token_type_name(token->type));\r
+ return NULL;\r
+ }\r
+\r
+ return token;\r
+}\r
+\r
+static OnyxAstNodeScope* enter_scope(OnyxParser* parser) {\r
+ OnyxAstNodeScope* scope = (OnyxAstNodeScope*) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_SCOPE);\r
+ scope->prev_scope = parser->curr_scope;\r
+ parser->curr_scope = scope;\r
+ return scope;\r
+}\r
+\r
+static OnyxAstNodeScope* leave_scope(OnyxParser* parser) {\r
+ // NOTE: Can't leave a scope if there is no scope\r
+ assert(parser->curr_scope != NULL);\r
+\r
+ for (OnyxAstNodeLocal *walker = parser->curr_scope->last_local; walker != NULL; walker = walker->prev_local) {\r
+ onyx_token_null_toggle(*walker->token);\r
+ bh_hash_delete(OnyxAstNode*, parser->identifiers, walker->token->token);\r
+ onyx_token_null_toggle(*walker->token);\r
+ }\r
+\r
+ parser->curr_scope = parser->curr_scope->prev_scope;\r
+ return parser->curr_scope;\r
+}\r
+\r
+static OnyxAstNode* lookup_identifier(OnyxParser* parser, OnyxToken* token) {\r
+ OnyxAstNode* ident = NULL;\r
+\r
+ onyx_token_null_toggle(*token);\r
+ if (bh_hash_has(OnyxAstNode*, parser->identifiers, token->token)) {\r
+ ident = bh_hash_get(OnyxAstNode*, parser->identifiers, token->token);\r
+ }\r
+ onyx_token_null_toggle(*token);\r
+\r
+ return ident;\r
+}\r
+\r
+static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local) {\r
+ OnyxAstNodeScope* scope = parser->curr_scope;\r
+ local->prev_local = scope->last_local;\r
+ scope->last_local = local;\r
+\r
+ onyx_token_null_toggle(*local->token);\r
+ bh_hash_put(OnyxAstNodeLocal*, parser->identifiers, local->token->token, local);\r
+ onyx_token_null_toggle(*local->token);\r
+}\r
+\r
+static OnyxAstNode* parse_factor(OnyxParser* parser) {\r
+ switch (parser->curr_token->type) {\r
+ case TOKEN_TYPE_OPEN_PAREN: {\r
+ parser_next_token(parser);\r
+ OnyxAstNode* expr = parse_expression(parser);\r
+ expect(parser, TOKEN_TYPE_CLOSE_PAREN);\r
+ return expr;\r
+ }\r
+\r
+ case TOKEN_TYPE_SYMBOL: {\r
+ OnyxToken* sym_token = expect(parser, TOKEN_TYPE_SYMBOL);\r
+ OnyxAstNode* sym_node = lookup_identifier(parser, sym_token);\r
+\r
+ // TODO: Handle calling a function\r
+ return sym_node;\r
+ }\r
+\r
+ case TOKEN_TYPE_LITERAL_NUMERIC: {\r
+ OnyxAstNode* lit_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);\r
+ lit_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_INT64];\r
+ lit_node->token = expect(parser, TOKEN_TYPE_LITERAL_NUMERIC);\r
+ return lit_node;\r
+ }\r
+\r
+ default:\r
+ onyx_message_add(parser->msgs,\r
+ ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,\r
+ parser->curr_token->pos,\r
+ onyx_get_token_type_name(parser->curr_token->type));\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left) {\r
+ OnyxAstNodeKind kind = -1;\r
+\r
+ switch (parser->curr_token->type) {\r
+ case TOKEN_TYPE_SYM_PLUS: kind = ONYX_AST_NODE_KIND_ADD; break;\r
+ case TOKEN_TYPE_SYM_MINUS: kind = ONYX_AST_NODE_KIND_MINUS; break;\r
+ case TOKEN_TYPE_SYM_STAR: kind = ONYX_AST_NODE_KIND_MULTIPLY; break;\r
+ case TOKEN_TYPE_SYM_FSLASH: kind = ONYX_AST_NODE_KIND_DIVIDE; break;\r
+ case TOKEN_TYPE_SYM_PERCENT: kind = ONYX_AST_NODE_KIND_MODULUS; break;\r
+ }\r
+\r
+ if (kind != -1) {\r
+ parser_next_token(parser);\r
+ OnyxAstNode* right = parse_factor(parser);\r
+\r
+ OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind);\r
+ bin_op->left = left;\r
+ bin_op->right = right;\r
+ return bin_op;\r
+ }\r
+\r
+ return &error_node;\r
+}\r
+\r
+static OnyxAstNode* parse_expression(OnyxParser* parser) {\r
+ OnyxAstNode* left = parse_factor(parser);\r
+\r
+ switch (parser->curr_token->type) {\r
+ case TOKEN_TYPE_SYM_PLUS:\r
+ case TOKEN_TYPE_SYM_MINUS:\r
+ case TOKEN_TYPE_SYM_STAR:\r
+ case TOKEN_TYPE_SYM_FSLASH:\r
+ case TOKEN_TYPE_SYM_PERCENT: {\r
+ OnyxAstNode* expr = parse_bin_op(parser, left);\r
+ return expr;\r
+ }\r
+ }\r
+\r
+ return left;\r
+}\r
+\r
+static OnyxAstNode* parse_if_stmt(OnyxParser* parser) {\r
+ return &error_node;\r
+}\r
+\r
+static OnyxAstNode* parse_expression_statement(OnyxParser* parser) {\r
+ if (parser->curr_token->type != TOKEN_TYPE_SYMBOL) return NULL;\r
+ OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);\r
+\r
+ switch (parser->curr_token->type) {\r
+ // NOTE: Declaration\r
+ case TOKEN_TYPE_SYM_COLON: {\r
+ parser_next_token(parser);\r
+ OnyxTypeInfo* type = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];\r
+\r
+ // NOTE: var: type\r
+ if (parser->curr_token->type == TOKEN_TYPE_SYMBOL) {\r
+ type = parse_type(parser);\r
+ }\r
+\r
+ OnyxAstNodeLocal* local = (OnyxAstNodeLocal*) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LOCAL);\r
+ local->token = symbol;\r
+ local->type = type;\r
+\r
+ insert_identifier(parser, local);\r
+\r
+ if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) {\r
+ parser_next_token(parser);\r
+\r
+ OnyxAstNode* expr = parse_expression(parser);\r
+ OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);\r
+ assignment->right = expr;\r
+ assignment->left = (OnyxAstNode*) local;\r
+ return assignment;\r
+ }\r
+ }\r
+\r
+ // NOTE: Assignment\r
+ case TOKEN_TYPE_SYM_EQUALS: {\r
+ parser_next_token(parser);\r
+\r
+ OnyxAstNode* lval = lookup_identifier(parser, symbol);\r
+\r
+ if (lval == NULL) {\r
+ // TODO: error handling\r
+ }\r
+\r
+ OnyxAstNode* rval = parse_expression(parser);\r
+ OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);\r
+ assignment->right = rval;\r
+ assignment->left = lval;\r
+ return assignment;\r
+ }\r
+\r
+ default:\r
+ parser_prev_token(parser);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+static OnyxAstNode* parse_return_statement(OnyxParser* parser) {\r
+ expect(parser, TOKEN_TYPE_KEYWORD_RETURN);\r
+\r
+ OnyxAstNode* return_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_RETURN);\r
+ return_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_VOID];\r
+ OnyxAstNode* expr = NULL;\r
+\r
+ if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {\r
+ expr = parse_expression(parser);\r
+\r
+ if (expr == NULL || expr == &error_node) {\r
+ return &error_node;\r
+ } else {\r
+ return_node->next = expr;\r
+ }\r
+ }\r
+\r
+ return return_node;\r
+}\r
+\r
+static OnyxAstNode* parse_statement(OnyxParser* parser) {\r
+ switch (parser->curr_token->type) {\r
+ case TOKEN_TYPE_KEYWORD_RETURN:\r
+ return parse_return_statement(parser);\r
+\r
+ case TOKEN_TYPE_OPEN_BRACE:\r
+ return (OnyxAstNode *) parse_block(parser, 0);\r
+\r
+ case TOKEN_TYPE_SYMBOL: {\r
+ OnyxAstNode* ret = parse_expression_statement(parser);\r
+ if (ret != NULL) return ret;\r
+ }\r
+\r
+ case TOKEN_TYPE_OPEN_PAREN:\r
+ case TOKEN_TYPE_SYM_PLUS:\r
+ case TOKEN_TYPE_SYM_MINUS:\r
+ case TOKEN_TYPE_SYM_BANG:\r
+ case TOKEN_TYPE_LITERAL_NUMERIC:\r
+ case TOKEN_TYPE_LITERAL_STRING:\r
+ return parse_expression(parser);\r
+\r
+ case TOKEN_TYPE_KEYWORD_IF:\r
+ return parse_if_stmt(parser);\r
+\r
+ default:\r
+ return NULL;\r
+ }\r
+}\r
+\r
+static OnyxAstNodeBlock* parse_block(OnyxParser* parser, b32 belongs_to_function) {\r
+ // --- is for an empty block\r
+ if (parser->curr_token->type == TOKEN_TYPE_SYM_MINUS) {\r
+ expect(parser, TOKEN_TYPE_SYM_MINUS);\r
+ expect(parser, TOKEN_TYPE_SYM_MINUS);\r
+ expect(parser, TOKEN_TYPE_SYM_MINUS);\r
+ return NULL;\r
+ }\r
+\r
+ expect(parser, TOKEN_TYPE_OPEN_BRACE);\r
+\r
+ OnyxAstNodeBlock* block = (OnyxAstNodeBlock *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BLOCK);\r
+ if (belongs_to_function) {\r
+ OnyxAstNodeScope* scope = enter_scope(parser);\r
+ block->scope = scope;\r
+ }\r
+\r
+ OnyxAstNode** next = &block->body;\r
+ OnyxAstNode* stmt = NULL;\r
+ while (parser->curr_token->type != TOKEN_TYPE_CLOSE_BRACE) {\r
+ stmt = parse_statement(parser);\r
+\r
+ if (stmt != NULL && stmt->kind != ONYX_AST_NODE_KIND_ERROR) {\r
+ *next = stmt;\r
+ next = &stmt->next;\r
+ }\r
+\r
+ if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {\r
+ onyx_message_add(parser->msgs,\r
+ ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,\r
+ parser->curr_token->pos,\r
+ onyx_get_token_type_name(TOKEN_TYPE_SYM_SEMICOLON),\r
+ onyx_get_token_type_name(parser->curr_token->type));\r
+ }\r
+ parser_next_token(parser);\r
+ }\r
+\r
+ expect(parser, TOKEN_TYPE_CLOSE_BRACE);\r
+\r
+ if (belongs_to_function) {\r
+ leave_scope(parser);\r
+ }\r
+\r
+ return block;\r
+}\r
+\r
+static OnyxTypeInfo* parse_type(OnyxParser* parser) {\r
+ OnyxTypeInfo* type_info = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];\r
+\r
+ OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);\r
+ if (symbol == NULL) return type_info;\r
+\r
+ onyx_token_null_toggle(*symbol);\r
+\r
+ if (!bh_hash_has(OnyxAstNode*, parser->identifiers, symbol->token)) {\r
+ onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, symbol->pos, symbol->token);\r
+ } else {\r
+ OnyxAstNode* type_info_node = bh_hash_get(OnyxAstNode*, parser->identifiers, symbol->token);\r
+\r
+ if (type_info_node->kind == ONYX_AST_NODE_KIND_TYPE) {\r
+ type_info = type_info_node->type;\r
+ }\r
+ }\r
+\r
+ onyx_token_null_toggle(*symbol);\r
+ return type_info;\r
+}\r
+\r
+static OnyxAstNodeParam* parse_function_params(OnyxParser* parser) {\r
+ expect(parser, TOKEN_TYPE_OPEN_PAREN);\r
+\r
+ if (parser->curr_token->type == TOKEN_TYPE_CLOSE_PAREN) {\r
+ parser_next_token(parser);\r
+ return NULL;\r
+ }\r
+\r
+ OnyxAstNodeParam* first_param = NULL;\r
+ u64 param_count = 0;\r
+\r
+ OnyxAstNodeParam* curr_param = NULL;\r
+ OnyxAstNodeParam* trailer = NULL;\r
+\r
+ OnyxToken* symbol;\r
+ while (parser->curr_token->type != TOKEN_TYPE_CLOSE_PAREN) {\r
+ if (parser->curr_token->type == TOKEN_TYPE_SYM_COMMA) parser_next_token(parser);\r
+ param_count++;\r
+\r
+ symbol = expect(parser, TOKEN_TYPE_SYMBOL);\r
+\r
+ curr_param = (OnyxAstNodeParam *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PARAM);\r
+ curr_param->token = symbol;\r
+ curr_param->type = parse_type(parser);\r
+\r
+ if (first_param == NULL) first_param = curr_param;\r
+\r
+ curr_param->next = NULL;\r
+ if (trailer) trailer->next = curr_param;\r
+\r
+ trailer = curr_param;\r
+ }\r
+\r
+ first_param->param_count = param_count;\r
+\r
+ parser_next_token(parser); // Skip the )\r
+ return first_param;\r
+}\r
+\r
+static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) {\r
+ expect(parser, TOKEN_TYPE_KEYWORD_PROC);\r
+\r
+ OnyxAstNodeFuncDef* func_def = (OnyxAstNodeFuncDef *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_FUNCDEF);\r
+\r
+ OnyxAstNodeParam* params = parse_function_params(parser);\r
+ func_def->params = params;\r
+\r
+ expect(parser, TOKEN_TYPE_RIGHT_ARROW);\r
+\r
+ OnyxTypeInfo* return_type = parse_type(parser);\r
+ func_def->return_type = return_type;\r
+\r
+ // TODO: Add params to parser.identifiers\r
+ for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {\r
+ onyx_token_null_toggle(*p->token);\r
+ bh_hash_put(OnyxAstNode*, parser->identifiers, p->token->token, (OnyxAstNode*) p);\r
+ onyx_token_null_toggle(*p->token);\r
+ }\r
+\r
+ func_def->body = parse_block(parser, 1);\r
+\r
+ // TODO: Remove params from parser.identifiers\r
+ for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {\r
+ onyx_token_null_toggle(*p->token);\r
+ bh_hash_delete(OnyxAstNode*, parser->identifiers, p->token->token);\r
+ onyx_token_null_toggle(*p->token);\r
+ }\r
+ return func_def;\r
+}\r
+\r
+static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) {\r
+ switch (parser->curr_token->type) {\r
+ case TOKEN_TYPE_KEYWORD_USE:\r
+ assert(0);\r
+ break;\r
+\r
+ case TOKEN_TYPE_KEYWORD_EXPORT: {\r
+ expect(parser, TOKEN_TYPE_KEYWORD_EXPORT);\r
+ if (parser->curr_token->type != TOKEN_TYPE_SYMBOL) {\r
+ onyx_message_add(parser->msgs,\r
+ ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,\r
+ parser->curr_token->pos,\r
+ onyx_get_token_type_name(TOKEN_TYPE_SYMBOL),\r
+ onyx_get_token_type_name(parser->curr_token->type));\r
+ break;\r
+ }\r
+\r
+ OnyxAstNode* top_level_decl = parse_top_level_statement(parser);\r
+ top_level_decl->flags |= ONYX_AST_FLAG_EXPORTED;\r
+ return top_level_decl;\r
+ } break;\r
+\r
+ case TOKEN_TYPE_SYMBOL: {\r
+ OnyxToken* symbol = parser->curr_token;\r
+ parser_next_token(parser);\r
+\r
+ expect(parser, TOKEN_TYPE_SYM_COLON);\r
+ expect(parser, TOKEN_TYPE_SYM_COLON);\r
+\r
+ if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {\r
+ OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);\r
+ func_def->token = symbol;\r
+ return (OnyxAstNode *) func_def;\r
+\r
+ } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {\r
+ // Handle struct case\r
+ assert(0);\r
+ } else {\r
+ onyx_message_add(parser->msgs,\r
+ ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,\r
+ parser->curr_token->pos,\r
+ onyx_get_token_type_name(parser->curr_token->type));\r
+ }\r
+ } break;\r
+ }\r
+\r
+ parser_next_token(parser);\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind) {\r
+ return ast_node_names[kind];\r
+}\r
+\r
+OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\\r
+ OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode));\r
+ node->kind = kind;\r
+ node->flags = 0;\r
+ node->token = NULL;\r
+ node->type = NULL;\r
+ node->next = NULL;\r
+ node->left = NULL;\r
+ node->right = NULL;\r
+\r
+ return node;\r
+}\r
+\r
+OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) {\r
+ OnyxParser parser;\r
+\r
+ bh_hash_init(bh_heap_allocator(), parser.identifiers);\r
+\r
+ OnyxTypeInfo* it = &builtin_types[0];\r
+ while (it->kind != 0xffffffff) {\r
+ OnyxAstNode* tmp = onyx_ast_node_new(alloc, ONYX_AST_NODE_KIND_TYPE);\r
+ tmp->type = it;\r
+ bh_hash_put(OnyxAstNode*, parser.identifiers, (char *)it->name, tmp);\r
+ it++;\r
+ }\r
+\r
+ parser.allocator = alloc;\r
+ parser.tokenizer = tokenizer;\r
+ parser.curr_token = tokenizer->tokens;\r
+ parser.prev_token = NULL;\r
+ parser.msgs = msgs;\r
+ parser.curr_scope = NULL;\r
+\r
+ return parser;\r
+}\r
+\r
+void onyx_parser_free(OnyxParser* parser) {\r
+ bh_hash_free(parser->identifiers);\r
+}\r
+\r
+OnyxAstNode* onyx_parse(OnyxParser *parser) {\r
+ OnyxAstNode* program = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PROGRAM);\r
+\r
+ OnyxAstNode** prev_stmt = &program->next;\r
+ OnyxAstNode* curr_stmt = NULL;\r
+ while (parser->curr_token->type != TOKEN_TYPE_END_STREAM) {\r
+ curr_stmt = parse_top_level_statement(parser);\r
+\r
+ // Building a linked list of statements down the "next" chain\r
+ if (curr_stmt != NULL && curr_stmt != &error_node) {\r
+ *prev_stmt = curr_stmt;\r
+ prev_stmt = &curr_stmt->next;\r
+ }\r
+ }\r
+\r
+ return program;\r
+}\r