More parse progress
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 23 May 2020 02:00:10 +0000 (21:00 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 23 May 2020 02:00:10 +0000 (21:00 -0500)
14 files changed:
Makefile
bh.h
docs/parse_grammar
onyx
onyx.c
onyxlex.c
onyxlex.h
onyxmsgs.c
onyxmsgs.h
onyxparser.c
onyxparser.h
onyxutils.c [new file with mode: 0644]
onyxutils.h [new file with mode: 0644]
progs/minimal.onyx

index b204645f96d8b26725ca9d3e28486da99aca77db..156ee28138533fea33f93d9da8d773a315bc9c8a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@ OBJ_FILES=\
        onyxlex.o \
        onyxparser.o \
        onyxmsgs.o \
+       onyxutils.o \
        onyx.o
 
 CC=gcc
diff --git a/bh.h b/bh.h
index 282608ae4674c64872014addb95f73247525b145..c3679f23c5c4647e034f5a95bf912e4cce5cb2f1 100644 (file)
--- a/bh.h
+++ b/bh.h
-#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, &current_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, &current_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
index 821b5120af9d4ccfdbca1b579eaa623f176ea9ac..610444a296b3e1c4776bdf26fc3333ed35f4206b 100644 (file)
@@ -1,78 +1,78 @@
-Note: ~ is empty
-Goal: Design the language to have no ambiguity (so a greedy algorithm can work)
-
-
-SOURCE_FILE = TOP_LEVEL_STATEMENT ; SOURCE_FILE | ~
-
-TOP_LEVEL_STATEMENT
-       = COMMENT -- Should comments not be passed to the parser? Depends if I need to look at them. Probably not
-       | USE_DECLARATION
-       | EXPORT_DECLARATION
-       | FOREIGN_DECLARATION
-       | TOP_LEVEL_DECLARATION
-
-COMMENT = TOKEN_TYPE_COMMENT
-
-USE_DECLARATION = use TOKEN_TYPE_LITERAL_STRING
-
-EXPORT_DECLARATION = export TOP_LEVEL_DECLARATION
-
-FOREIGN_DECLARATION = foreign TOKEN_TYPE_LITERAL_STRING TOKEN_TYPE_LITERAL_STRING :: TOP_LEVEL_VALUE
-
-TOP_LEVEL_DECLARATION = TOKEN_TYPE_SYMBOL :: TOP_LEVEL_VALUE
-
-TOP_LEVEL_VALUE
-       = FUNCTION_DECLARATION
-       | STRUCT_DECLARATION
-
-FUNCTION_DECLARATION = proc FUNCTION_TYPE BLOCK
-
-FUNCTION_TYPE = ( FUNCTION_PARAMS ) -> TOKEN_TYPE_SYMBOL
-
--- This may be too weird...
-BLOCK = { STATEMENTS | ---
-STATEMENTS = STATEMENT ; STATEMENTS | }
-
-STATEMENT
-       = ASSIGNMENT_STATEMENT
-       | IF_STATEMENT
-       | FOR_STATEMENT
-       | RETURN_STATEMENT
-       | EXPRESSION
-
-ASSIGNMENT_STATEMENT = TOKEN_TYPE_SYMBOL = EXPRESSION
-
-IF_STATEMENT
-       = if EXPRESSION BLOCK ELSE_IF_STATEMENT ELSE_STATEMENT
-
-ELSEIF_STATEMENT = elseif EXPRESSION BLOCK ELSEIF_STATEMENT | ~
-
-ELSE_STATEMENT = else BLOCK | ~
-
--- This needs to be better
-FOR_STATEMENT = for STATEMENT ; EXPRESSION ; STATEMENT BLOCK
-
-RETURN_STATEMENT = return EXPRESSION
-
--- Remove abiguity in implementation
-EXPRESSION
-       = EXPRESSION + EXPRESSION
-       | EXPRESSION - EXPRESSION
-       | EXPRESSION * EXPRESSION
-       | EXPRESSION / EXPRESSION
-       | EXPRESSION % EXPRESSION
-       | do BLOCK
-       | FUNCTION_CALL -- This could have some abiguity with just the symbol
-       | ( EXPRESSION )
-       | TOKEN_TYPE_SYMBOL
-
-FUNCTION_CALL = TOKEN_TYPE_SYMBOL ( EXPRESSION_LIST )
-
--- Implement just using a loop
-COMMA_LIST(T) = T | T , COMMA_LIST(T)
-
-FUNCTION_PARAMS = COMMA_LIST(TOKEN_TYPE_SYMBOL :: TOKEN_TYPE_SYMBOL)
-EXPRESSION_LIST = COMMA_LIST(EXPRESSION)
-
-STRUCT_DECLARATION = struct { STRUCT_MEMBERS }
+Note: ~ is empty\r
+Goal: Design the language to have no ambiguity (so a greedy algorithm can work)\r
+\r
+\r
+SOURCE_FILE = TOP_LEVEL_STATEMENT ; SOURCE_FILE | ~\r
+\r
+TOP_LEVEL_STATEMENT\r
+       = COMMENT -- Should comments not be passed to the parser? Depends if I need to look at them. Probably not\r
+       | USE_DECLARATION\r
+       | EXPORT_DECLARATION\r
+       | FOREIGN_DECLARATION\r
+       | TOP_LEVEL_DECLARATION\r
+\r
+COMMENT = TOKEN_TYPE_COMMENT\r
+\r
+USE_DECLARATION = use TOKEN_TYPE_LITERAL_STRING\r
+\r
+EXPORT_DECLARATION = export TOP_LEVEL_DECLARATION\r
+\r
+FOREIGN_DECLARATION = foreign TOKEN_TYPE_LITERAL_STRING TOKEN_TYPE_LITERAL_STRING :: TOP_LEVEL_VALUE\r
+\r
+TOP_LEVEL_DECLARATION = TOKEN_TYPE_SYMBOL :: TOP_LEVEL_VALUE\r
+\r
+TOP_LEVEL_VALUE\r
+       = FUNCTION_DECLARATION\r
+       | STRUCT_DECLARATION\r
+\r
+FUNCTION_DECLARATION = proc FUNCTION_TYPE BLOCK\r
+\r
+FUNCTION_TYPE = ( FUNCTION_PARAMS ) -> TOKEN_TYPE_SYMBOL\r
+\r
+-- This may be too weird...\r
+BLOCK = { STATEMENTS | ---\r
+STATEMENTS = STATEMENT ; STATEMENTS | }\r
+\r
+STATEMENT\r
+       = ASSIGNMENT_STATEMENT\r
+       | IF_STATEMENT\r
+       | FOR_STATEMENT\r
+       | RETURN_STATEMENT\r
+       | EXPRESSION\r
+\r
+ASSIGNMENT_STATEMENT = TOKEN_TYPE_SYMBOL = EXPRESSION\r
+\r
+IF_STATEMENT\r
+       = if EXPRESSION BLOCK ELSE_IF_STATEMENT ELSE_STATEMENT\r
+\r
+ELSEIF_STATEMENT = elseif EXPRESSION BLOCK ELSEIF_STATEMENT | ~\r
+\r
+ELSE_STATEMENT = else BLOCK | ~\r
+\r
+-- This needs to be better\r
+FOR_STATEMENT = for STATEMENT ; EXPRESSION ; STATEMENT BLOCK\r
+\r
+RETURN_STATEMENT = return EXPRESSION\r
+\r
+-- Remove abiguity in implementation\r
+EXPRESSION\r
+       = EXPRESSION + EXPRESSION\r
+       | EXPRESSION - EXPRESSION\r
+       | EXPRESSION * EXPRESSION\r
+       | EXPRESSION / EXPRESSION\r
+       | EXPRESSION % EXPRESSION\r
+       | do BLOCK\r
+       | FUNCTION_CALL -- This could have some abiguity with just the symbol\r
+       | ( EXPRESSION )\r
+       | TOKEN_TYPE_SYMBOL\r
+\r
+FUNCTION_CALL = TOKEN_TYPE_SYMBOL ( EXPRESSION_LIST )\r
+\r
+-- Implement just using a loop\r
+COMMA_LIST(T) = T | T , COMMA_LIST(T)\r
+\r
+FUNCTION_PARAMS = COMMA_LIST(TOKEN_TYPE_SYMBOL :: TOKEN_TYPE_SYMBOL)\r
+EXPRESSION_LIST = COMMA_LIST(EXPRESSION)\r
+\r
+STRUCT_DECLARATION = struct { STRUCT_MEMBERS }\r
 STRUCT_MEMBERS = COMMA_LIST(TOKEN_TYPE_SYMBOL :: TOKEN_TYPE_SYMBOL)
\ No newline at end of file
diff --git a/onyx b/onyx
index 53dfc750a1dc8812c5d94fbc5b338c236053f2a9..3394ad0fe51e85ab2c41ca2c14cd02e966b8dc20 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/onyx.c b/onyx.c
index 1c494b9bb22e177c18e4b8b8decd899c629143d0..9c3b424a38b888c138bdf0d7dd76399784739d86 100644 (file)
--- a/onyx.c
+++ b/onyx.c
@@ -1,59 +1,61 @@
-#define BH_NO_STRING
-// #define BH_DEBUG
-#define BH_DEFINE
-#include "bh.h"
-
-#include "onyxlex.h"
-#include "onyxmsgs.h"
-#include "onyxparser.h"
-
-int main(int argc, char *argv[]) {
-       bh_file source_file;
-       bh_file_error err = bh_file_open(&source_file, argv[1]);
-       if (err != BH_FILE_ERROR_NONE) {
-               bh_printf_err("Failed to open file %s\n", argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       bh_allocator alloc = bh_heap_allocator();
-
-       bh_file_contents fc = bh_file_read_contents(alloc, &source_file);
-       bh_file_close(&source_file);
-
-       OnyxTokenizer tokenizer = onyx_tokenizer_create(alloc, &fc);
-       onyx_lex_tokens(&tokenizer);
-       bh_arr(OnyxToken) token_arr = tokenizer.tokens;
-
-       // printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));
-
-       // for (OnyxToken* it = token_arr; !bh_arr_end(token_arr, it); it++) {
-       //      onyx_token_null_toggle(*it);
-       //      printf("%s (%s:%ld:%ld)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);
-       //      onyx_token_null_toggle(*it);
-       // }
-
-       bh_arena msg_arena;
-       bh_arena_init(&msg_arena, alloc, 4096);
-       bh_allocator msg_alloc = bh_arena_allocator(&msg_arena);
-
-       OnyxMessages msgs;
-       onyx_message_create(msg_alloc, &msgs);
-
-       bh_arena ast_arena;
-       bh_arena_init(&ast_arena, alloc, 16 * 1024 * 1024); // 16MB
-       bh_allocator ast_alloc = bh_arena_allocator(&ast_arena);
-
-       OnyxParser parser = onyx_parser_create(ast_alloc, &tokenizer, &msgs);
-       OnyxAstNode* program = onyx_parse(&parser);
-
-       onyx_message_print(&msgs);
-
-       bh_file_contents_delete(&fc);
-       onyx_tokenizer_free(&tokenizer);
-       onyx_parser_free(&parser);
-       bh_arena_free(&msg_arena);
-       bh_arena_free(&ast_arena);
-
-
-       return 0;
-}
+#define BH_NO_STRING\r
+// #define BH_DEBUG\r
+#define BH_DEFINE\r
+#include "bh.h"\r
+\r
+#include "onyxlex.h"\r
+#include "onyxmsgs.h"\r
+#include "onyxparser.h"\r
+#include "onyxutils.h"\r
+\r
+int main(int argc, char *argv[]) {\r
+       bh_file source_file;\r
+       bh_file_error err = bh_file_open(&source_file, argv[1]);\r
+       if (err != BH_FILE_ERROR_NONE) {\r
+               bh_printf_err("Failed to open file %s\n", argv[1]);\r
+               return EXIT_FAILURE;\r
+       }\r
+\r
+       bh_allocator alloc = bh_heap_allocator();\r
+\r
+       bh_file_contents fc = bh_file_read_contents(alloc, &source_file);\r
+       bh_file_close(&source_file);\r
+\r
+       OnyxTokenizer tokenizer = onyx_tokenizer_create(alloc, &fc);\r
+       onyx_lex_tokens(&tokenizer);\r
+       bh_arr(OnyxToken) token_arr = tokenizer.tokens;\r
+\r
+       // bh_printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));\r
+\r
+       // for (OnyxToken* it = token_arr; !bh_arr_end(token_arr, it); it++) {\r
+       //      onyx_token_null_toggle(*it);\r
+       //      bh_printf("%s (%s:%l:%l)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);\r
+       //      onyx_token_null_toggle(*it);\r
+       // }\r
+\r
+       bh_arena msg_arena;\r
+       bh_arena_init(&msg_arena, alloc, 4096);\r
+       bh_allocator msg_alloc = bh_arena_allocator(&msg_arena);\r
+\r
+       OnyxMessages msgs;\r
+       onyx_message_create(msg_alloc, &msgs);\r
+\r
+       bh_arena ast_arena;\r
+       bh_arena_init(&ast_arena, alloc, 16 * 1024 * 1024); // 16MB\r
+       bh_allocator ast_alloc = bh_arena_allocator(&ast_arena);\r
+\r
+       OnyxParser parser = onyx_parser_create(ast_alloc, &tokenizer, &msgs);\r
+       OnyxAstNode* program = onyx_parse(&parser);\r
+\r
+       onyx_message_print(&msgs);\r
+       onyx_ast_print(program);\r
+\r
+       bh_file_contents_delete(&fc);\r
+       onyx_tokenizer_free(&tokenizer);\r
+       onyx_parser_free(&parser);\r
+       bh_arena_free(&msg_arena);\r
+       bh_arena_free(&ast_arena);\r
+\r
+\r
+       return 0;\r
+}\r
index ca877d6c70547382fae56cafbcd60bcd6b7cc887..69b3d3148cc16cff02ffffe54ecbb2a518e5f875 100644 (file)
--- a/onyxlex.c
+++ b/onyxlex.c
-#include "bh.h"
-#include "onyxlex.h"
-
-static const char* onyx_token_type_names[] = {
-       "TOKEN_TYPE_UNKNOWN",
-       "TOKEN_TYPE_END_STREAM",
-
-       "TOKEN_TYPE_COMMENT",
-
-       "struct",               //"TOKEN_TYPE_KEYWORD_STRUCT",
-       "use",                  //"TOKEN_TYPE_KEYWORD_USE",
-       "export",               //"TOKEN_TYPE_KEYWORD_EXPORT",
-       "if",                   //"TOKEN_TYPE_KEYWORD_IF",
-       "else",                 //"TOKEN_TYPE_KEYWORD_ELSE",
-       "for",                  //"TOKEN_TYPE_KEYWORD_FOR",
-       "do",                   //"TOKEN_TYPE_KEYWORD_DO",
-       "return",               //"TOKEN_TYPE_KEYWORD_RETURN",
-       "foreign",              //"TOKEN_TYPE_KEYWORD_FOREIGN",
-       "proc",                 //"TOKEN_TYPE_KEYWORD_PROC",
-       "global",               //"TOKEN_TYPE_KEYWORD_GLOBAL",
-
-       "->", //"TOKEN_TYPE_RIGHT_ARROW",
-       "<-", //"TOKEN_TYPE_LEFT_ARROW",
-       "(",  //"TOKEN_TYPE_OPEN_PAREN",
-       ")",  //"TOKEN_TYPE_CLOSE_PAREN",
-       "{",  //"TOKEN_TYPE_OPEN_BRACE",
-       "}",  //"TOKEN_TYPE_CLOSE_BRACE",
-       "[",  //"TOKEN_TYPE_OPEN_BRACKET",
-       "]",  //"TOKEN_TYPE_CLOSE_BRACKET",
-       "<",  //"TOKEN_TYPE_OPEN_ANGLE",
-       ">",  //"TOKEN_TYPE_CLOSE_ANGLE",
-
-       "+",  // "TOKEN_TYPE_SYM_PLUS",
-       "-",  // "TOKEN_TYPE_SYM_MINUS",
-       "*",  // "TOKEN_TYPE_SYM_STAR",
-       "%",  // "TOKEN_TYPE_SYM_PERCENT",
-       ".",  // "TOKEN_TYPE_SYM_DOT",
-       "/",  // "TOKEN_TYPE_SYM_FSLASH",
-       "\\", // "TOKEN_TYPE_SYM_BSLASH",
-       ":",  // "TOKEN_TYPE_SYM_COLON",
-       ";",  // "TOKEN_TYPE_SYM_SEMICOLON",
-       ",",  // "TOKEN_TYPE_SYM_COMMA",
-       "=",  // "TOKEN_TYPE_SYM_EQUALS",
-       "`",  // "TOKEN_TYPE_SYM_GRAVE",
-       "~",  // "TOKEN_TYPE_SYM_TILDE",
-       "!",  // "TOKEN_TYPE_SYM_BANG",
-       "^",  // "TOKEN_TYPE_SYM_CARET",
-       "&",  // "TOKEN_TYPE_SYM_AMPERSAND",
-
-       "TOKEN_TYPE_SYMBOL",
-       "TOKEN_TYPE_LITERAL_STRING",
-       "TOKEN_TYPE_LITERAL_NUMERIC",
-
-       "TOKEN_TYPE_COUNT"
-};
-
-#ifndef LITERAL_TOKEN
-#define LITERAL_TOKEN(token, token_type) \
-       if (token_lit(tokenizer, &tk, token, token_type)) goto token_parsed;
-#endif
-
-#ifndef INCREMENT_CURR_TOKEN
-#define INCREMENT_CURR_TOKEN(tkn) { \
-       if (*(tkn)->curr == '\n') { \
-               (tkn)->line_number++; \
-               (tkn)->line_start = (tkn)->curr + 1; \
-       } \
-       (tkn)->curr++; \
-}
-#endif
-
-static b32 token_lit(OnyxTokenizer* tokenizer, OnyxToken* tk, char* lit, OnyxTokenType type) {
-       i64 len = chars_match(tokenizer->curr, lit);
-       if (len > 0) {
-               tk->type = type;
-               tk->token = tokenizer->curr;
-               tk->length = len;
-               tk->pos.line = tokenizer->line_number;
-               tk->pos.column = (i32)(tokenizer->curr - tokenizer->line_start) + 1;
-
-               tokenizer->curr += len;
-
-               return 1;
-       }
-       return 0;
-}
-
-const char* onyx_get_token_type_name(OnyxTokenType tkn_type) {
-       return onyx_token_type_names[tkn_type];
-}
-
-void onyx_token_null_toggle(OnyxToken tkn) {
-       static char backup = 0;
-       char tmp = tkn.token[tkn.length];
-       tkn.token[tkn.length] = backup;
-       backup = tmp;
-}
-
-OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
-       OnyxToken tk;
-
-       // Skip whitespace
-       while (char_is_whitespace(*tokenizer->curr) && tokenizer->curr != tokenizer->end)
-               INCREMENT_CURR_TOKEN(tokenizer)
-
-       tk.type = TOKEN_TYPE_UNKNOWN;
-       tk.token = tokenizer->curr;
-       tk.length = 1;
-       tk.pos.filename = tokenizer->filename;
-       tk.pos.line = tokenizer->line_number;
-       tk.pos.column = (i32)(tokenizer->curr - tokenizer->line_start) + 1;
-
-       if (tokenizer->curr == tokenizer->end) {
-               tk.type = TOKEN_TYPE_END_STREAM;
-               goto token_parsed;
-       }
-
-       // Comments
-       if (*tokenizer->curr == '/' && *(tokenizer->curr + 1) == '*') {
-               tokenizer->curr += 2;
-               tk.type = TOKEN_TYPE_COMMENT;
-               tk.token = tokenizer->curr;
-               u16 layers = 1;
-
-               while (layers >= 1) {
-                       INCREMENT_CURR_TOKEN(tokenizer);
-
-                       if (tokenizer->curr == tokenizer->end) {
-                               tk.type = TOKEN_TYPE_END_STREAM;
-                               break;
-                       }
-
-                       if (*tokenizer->curr == '/' && *(tokenizer->curr + 1) == '*') {
-                               layers++;
-                               INCREMENT_CURR_TOKEN(tokenizer);
-                       }
-
-                       if (*tokenizer->curr == '*' && *(tokenizer->curr + 1) == '/') {
-                               layers--;
-                               INCREMENT_CURR_TOKEN(tokenizer);
-                       }
-               }
-
-               INCREMENT_CURR_TOKEN(tokenizer);
-
-               tk.length = tokenizer->curr - tk.token - 2;
-               goto token_parsed;
-       }
-
-       LITERAL_TOKEN("struct", TOKEN_TYPE_KEYWORD_STRUCT);
-       LITERAL_TOKEN("export", TOKEN_TYPE_KEYWORD_EXPORT);
-       LITERAL_TOKEN("use", TOKEN_TYPE_KEYWORD_USE);
-       LITERAL_TOKEN("if", TOKEN_TYPE_KEYWORD_IF);
-       LITERAL_TOKEN("else", TOKEN_TYPE_KEYWORD_ELSE);
-       LITERAL_TOKEN("foreign", TOKEN_TYPE_KEYWORD_FOREIGN);
-       LITERAL_TOKEN("for", TOKEN_TYPE_KEYWORD_FOR);
-       LITERAL_TOKEN("return", TOKEN_TYPE_KEYWORD_RETURN);
-       LITERAL_TOKEN("do", TOKEN_TYPE_KEYWORD_DO);
-       LITERAL_TOKEN("proc", TOKEN_TYPE_KEYWORD_PROC);
-       LITERAL_TOKEN("global", TOKEN_TYPE_KEYWORD_GLOBAL);
-       LITERAL_TOKEN("->", TOKEN_TYPE_RIGHT_ARROW);
-       LITERAL_TOKEN("<-", TOKEN_TYPE_RIGHT_ARROW);
-       LITERAL_TOKEN("(", TOKEN_TYPE_OPEN_PAREN);
-       LITERAL_TOKEN(")", TOKEN_TYPE_CLOSE_PAREN);
-       LITERAL_TOKEN("{", TOKEN_TYPE_OPEN_BRACE);
-       LITERAL_TOKEN("}", TOKEN_TYPE_CLOSE_BRACE);
-       LITERAL_TOKEN("[", TOKEN_TYPE_OPEN_BRACKET);
-       LITERAL_TOKEN("]", TOKEN_TYPE_CLOSE_BRACKET);
-       LITERAL_TOKEN("<", TOKEN_TYPE_OPEN_ANGLE);
-       LITERAL_TOKEN(">", TOKEN_TYPE_CLOSE_ANGLE);
-       LITERAL_TOKEN("+", TOKEN_TYPE_SYM_PLUS);
-       LITERAL_TOKEN("-", TOKEN_TYPE_SYM_MINUS);
-       LITERAL_TOKEN("*", TOKEN_TYPE_SYM_STAR);
-       LITERAL_TOKEN(".", TOKEN_TYPE_SYM_DOT);
-       LITERAL_TOKEN("%", TOKEN_TYPE_SYM_PERCENT);
-       LITERAL_TOKEN("/", TOKEN_TYPE_SYM_FSLASH);
-       LITERAL_TOKEN("\\", TOKEN_TYPE_SYM_BSLASH);
-       LITERAL_TOKEN(":", TOKEN_TYPE_SYM_COLON);
-       LITERAL_TOKEN(";", TOKEN_TYPE_SYM_SEMICOLON);
-       LITERAL_TOKEN(",", TOKEN_TYPE_SYM_COMMA);
-       LITERAL_TOKEN("=", TOKEN_TYPE_SYM_EQUALS);
-       LITERAL_TOKEN("`", TOKEN_TYPE_SYM_GRAVE);
-       LITERAL_TOKEN("~", TOKEN_TYPE_SYM_TILDE);
-       LITERAL_TOKEN("!", TOKEN_TYPE_SYM_BANG);
-       LITERAL_TOKEN("^", TOKEN_TYPE_SYM_CARET);
-       LITERAL_TOKEN("&", TOKEN_TYPE_SYM_AMPERSAND);
-
-       // Symbols
-       if (char_is_alpha(*tk.token)) {
-               u64 len = 0;
-               while (char_is_alphanum(*tokenizer->curr) || charset_contains("_$", *tokenizer->curr)) {
-                       len++;
-                       INCREMENT_CURR_TOKEN(tokenizer);
-               }
-
-               tk.length = len;
-               tk.type = TOKEN_TYPE_SYMBOL;
-               goto token_parsed;
-       }
-
-       // String literal
-       if (*tk.token == '"') {
-               u64 len = 0;
-               u64 slash_count = 0;
-
-               INCREMENT_CURR_TOKEN(tokenizer);
-
-               while (!(*tokenizer->curr == '"' && slash_count == 0)) {
-                       len++;
-
-                       if (*tokenizer->curr == '\\') {
-                               slash_count += 1;
-                               slash_count %= 2;
-                       } else {
-                               slash_count = 0;
-                       }
-
-                       INCREMENT_CURR_TOKEN(tokenizer);
-               }
-
-               INCREMENT_CURR_TOKEN(tokenizer);
-
-               tk.token++;
-               tk.type = TOKEN_TYPE_LITERAL_STRING;
-               tk.length = len;
-               goto token_parsed;
-       }
-
-       // Number literal
-       if (char_is_num(*tokenizer->curr)) {
-               u64 len = 0;
-               while (char_is_num(*(tokenizer->curr + 1)) || *(tokenizer->curr + 1) == '.') {
-                       len++;
-                       INCREMENT_CURR_TOKEN(tokenizer);
-               }
-
-               tk.type = TOKEN_TYPE_LITERAL_NUMERIC;
-               tk.length = len;
-       }
-
-       INCREMENT_CURR_TOKEN(tokenizer);
-
-token_parsed:
-       bh_arr_push(tokenizer->tokens, tk);
-
-       return &tokenizer->tokens[bh_arr_length(tokenizer->tokens) - 1];
-}
-
-OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc) {
-       OnyxTokenizer tknizer = {
-               .start                  = fc->data,
-               .curr                   = fc->data,
-               .end                    = fc->data + fc->length,
-
-               .filename               = fc->filename,
-
-               .line_number    = 1,
-               .line_start     = fc->data,
-               .tokens                 = NULL,
-       };
-
-       bh_arr_new(allocator, tknizer.tokens, 512);
-       return tknizer;
-}
-
-void onyx_tokenizer_free(OnyxTokenizer* tokenizer) {
-       bh_arr_free(tokenizer->tokens);
-}
-
-void onyx_lex_tokens(OnyxTokenizer* tokenizer) {
-       OnyxToken* tk;
-       do {
-               tk = onyx_get_token(tokenizer);
-       } while (tk->type != TOKEN_TYPE_END_STREAM);
-}
+#include "bh.h"\r
+#include "onyxlex.h"\r
+\r
+static const char* onyx_token_type_names[] = {\r
+       "TOKEN_TYPE_UNKNOWN",\r
+       "TOKEN_TYPE_END_STREAM",\r
+\r
+       "TOKEN_TYPE_COMMENT",\r
+\r
+       "struct",               //"TOKEN_TYPE_KEYWORD_STRUCT",\r
+       "use",                  //"TOKEN_TYPE_KEYWORD_USE",\r
+       "export",               //"TOKEN_TYPE_KEYWORD_EXPORT",\r
+       "if",                   //"TOKEN_TYPE_KEYWORD_IF",\r
+       "else",                 //"TOKEN_TYPE_KEYWORD_ELSE",\r
+       "for",                  //"TOKEN_TYPE_KEYWORD_FOR",\r
+       "do",                   //"TOKEN_TYPE_KEYWORD_DO",\r
+       "return",               //"TOKEN_TYPE_KEYWORD_RETURN",\r
+       "foreign",              //"TOKEN_TYPE_KEYWORD_FOREIGN",\r
+       "proc",                 //"TOKEN_TYPE_KEYWORD_PROC",\r
+       "global",               //"TOKEN_TYPE_KEYWORD_GLOBAL",\r
+\r
+       "->", //"TOKEN_TYPE_RIGHT_ARROW",\r
+       "<-", //"TOKEN_TYPE_LEFT_ARROW",\r
+       "(",  //"TOKEN_TYPE_OPEN_PAREN",\r
+       ")",  //"TOKEN_TYPE_CLOSE_PAREN",\r
+       "{",  //"TOKEN_TYPE_OPEN_BRACE",\r
+       "}",  //"TOKEN_TYPE_CLOSE_BRACE",\r
+       "[",  //"TOKEN_TYPE_OPEN_BRACKET",\r
+       "]",  //"TOKEN_TYPE_CLOSE_BRACKET",\r
+       "<",  //"TOKEN_TYPE_OPEN_ANGLE",\r
+       ">",  //"TOKEN_TYPE_CLOSE_ANGLE",\r
+\r
+       "+",  // "TOKEN_TYPE_SYM_PLUS",\r
+       "-",  // "TOKEN_TYPE_SYM_MINUS",\r
+       "*",  // "TOKEN_TYPE_SYM_STAR",\r
+       "%",  // "TOKEN_TYPE_SYM_PERCENT",\r
+       ".",  // "TOKEN_TYPE_SYM_DOT",\r
+       "/",  // "TOKEN_TYPE_SYM_FSLASH",\r
+       "\\", // "TOKEN_TYPE_SYM_BSLASH",\r
+       ":",  // "TOKEN_TYPE_SYM_COLON",\r
+       ";",  // "TOKEN_TYPE_SYM_SEMICOLON",\r
+       ",",  // "TOKEN_TYPE_SYM_COMMA",\r
+       "=",  // "TOKEN_TYPE_SYM_EQUALS",\r
+       "`",  // "TOKEN_TYPE_SYM_GRAVE",\r
+       "~",  // "TOKEN_TYPE_SYM_TILDE",\r
+       "!",  // "TOKEN_TYPE_SYM_BANG",\r
+       "^",  // "TOKEN_TYPE_SYM_CARET",\r
+       "&",  // "TOKEN_TYPE_SYM_AMPERSAND",\r
+\r
+       "TOKEN_TYPE_SYMBOL",\r
+       "TOKEN_TYPE_LITERAL_STRING",\r
+       "TOKEN_TYPE_LITERAL_NUMERIC",\r
+\r
+       "TOKEN_TYPE_COUNT"\r
+};\r
+\r
+#ifndef LITERAL_TOKEN\r
+#define LITERAL_TOKEN(token, token_type) \\r
+       if (token_lit(tokenizer, &tk, token, token_type)) goto token_parsed;\r
+#endif\r
+\r
+#ifndef INCREMENT_CURR_TOKEN\r
+#define INCREMENT_CURR_TOKEN(tkn) { \\r
+       if (*(tkn)->curr == '\n') { \\r
+               (tkn)->line_number++; \\r
+               (tkn)->line_start = (tkn)->curr + 1; \\r
+       } \\r
+       (tkn)->curr++; \\r
+}\r
+#endif\r
+\r
+static b32 token_lit(OnyxTokenizer* tokenizer, OnyxToken* tk, char* lit, OnyxTokenType type) {\r
+       i64 len = chars_match(tokenizer->curr, lit);\r
+       if (len > 0) {\r
+               tk->type = type;\r
+               tk->token = tokenizer->curr;\r
+               tk->length = len;\r
+               tk->pos.line = tokenizer->line_number;\r
+               tk->pos.column = (i32)(tokenizer->curr - tokenizer->line_start) + 1;\r
+\r
+               tokenizer->curr += len;\r
+\r
+               return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+const char* onyx_get_token_type_name(OnyxTokenType tkn_type) {\r
+       return onyx_token_type_names[tkn_type];\r
+}\r
+\r
+void onyx_token_null_toggle(OnyxToken tkn) {\r
+       static char backup = 0;\r
+       char tmp = tkn.token[tkn.length];\r
+       tkn.token[tkn.length] = backup;\r
+       backup = tmp;\r
+}\r
+\r
+OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {\r
+       OnyxToken tk;\r
+\r
+       // Skip whitespace\r
+       while (char_is_whitespace(*tokenizer->curr) && tokenizer->curr != tokenizer->end)\r
+               INCREMENT_CURR_TOKEN(tokenizer)\r
+\r
+       tk.type = TOKEN_TYPE_UNKNOWN;\r
+       tk.token = tokenizer->curr;\r
+       tk.length = 1;\r
+       tk.pos.filename = tokenizer->filename;\r
+       tk.pos.line = tokenizer->line_number;\r
+       tk.pos.column = (i32)(tokenizer->curr - tokenizer->line_start) + 1;\r
+\r
+       if (tokenizer->curr == tokenizer->end) {\r
+               tk.type = TOKEN_TYPE_END_STREAM;\r
+               goto token_parsed;\r
+       }\r
+\r
+       // Comments\r
+       if (*tokenizer->curr == '/' && *(tokenizer->curr + 1) == '*') {\r
+               tokenizer->curr += 2;\r
+               tk.type = TOKEN_TYPE_COMMENT;\r
+               tk.token = tokenizer->curr;\r
+               u16 layers = 1;\r
+\r
+               while (layers >= 1) {\r
+                       INCREMENT_CURR_TOKEN(tokenizer);\r
+\r
+                       if (tokenizer->curr == tokenizer->end) {\r
+                               tk.type = TOKEN_TYPE_END_STREAM;\r
+                               break;\r
+                       }\r
+\r
+                       if (*tokenizer->curr == '/' && *(tokenizer->curr + 1) == '*') {\r
+                               layers++;\r
+                               INCREMENT_CURR_TOKEN(tokenizer);\r
+                       }\r
+\r
+                       if (*tokenizer->curr == '*' && *(tokenizer->curr + 1) == '/') {\r
+                               layers--;\r
+                               INCREMENT_CURR_TOKEN(tokenizer);\r
+                       }\r
+               }\r
+\r
+               INCREMENT_CURR_TOKEN(tokenizer);\r
+\r
+               tk.length = tokenizer->curr - tk.token - 2;\r
+               goto token_parsed;\r
+       }\r
+\r
+       LITERAL_TOKEN("struct", TOKEN_TYPE_KEYWORD_STRUCT);\r
+       LITERAL_TOKEN("export", TOKEN_TYPE_KEYWORD_EXPORT);\r
+       LITERAL_TOKEN("use", TOKEN_TYPE_KEYWORD_USE);\r
+       LITERAL_TOKEN("if", TOKEN_TYPE_KEYWORD_IF);\r
+       LITERAL_TOKEN("else", TOKEN_TYPE_KEYWORD_ELSE);\r
+       LITERAL_TOKEN("foreign", TOKEN_TYPE_KEYWORD_FOREIGN);\r
+       LITERAL_TOKEN("for", TOKEN_TYPE_KEYWORD_FOR);\r
+       LITERAL_TOKEN("return", TOKEN_TYPE_KEYWORD_RETURN);\r
+       LITERAL_TOKEN("do", TOKEN_TYPE_KEYWORD_DO);\r
+       LITERAL_TOKEN("proc", TOKEN_TYPE_KEYWORD_PROC);\r
+       LITERAL_TOKEN("global", TOKEN_TYPE_KEYWORD_GLOBAL);\r
+       LITERAL_TOKEN("->", TOKEN_TYPE_RIGHT_ARROW);\r
+       LITERAL_TOKEN("<-", TOKEN_TYPE_RIGHT_ARROW);\r
+       LITERAL_TOKEN("(", TOKEN_TYPE_OPEN_PAREN);\r
+       LITERAL_TOKEN(")", TOKEN_TYPE_CLOSE_PAREN);\r
+       LITERAL_TOKEN("{", TOKEN_TYPE_OPEN_BRACE);\r
+       LITERAL_TOKEN("}", TOKEN_TYPE_CLOSE_BRACE);\r
+       LITERAL_TOKEN("[", TOKEN_TYPE_OPEN_BRACKET);\r
+       LITERAL_TOKEN("]", TOKEN_TYPE_CLOSE_BRACKET);\r
+       LITERAL_TOKEN("<", TOKEN_TYPE_OPEN_ANGLE);\r
+       LITERAL_TOKEN(">", TOKEN_TYPE_CLOSE_ANGLE);\r
+       LITERAL_TOKEN("+", TOKEN_TYPE_SYM_PLUS);\r
+       LITERAL_TOKEN("-", TOKEN_TYPE_SYM_MINUS);\r
+       LITERAL_TOKEN("*", TOKEN_TYPE_SYM_STAR);\r
+       LITERAL_TOKEN(".", TOKEN_TYPE_SYM_DOT);\r
+       LITERAL_TOKEN("%", TOKEN_TYPE_SYM_PERCENT);\r
+       LITERAL_TOKEN("/", TOKEN_TYPE_SYM_FSLASH);\r
+       LITERAL_TOKEN("\\", TOKEN_TYPE_SYM_BSLASH);\r
+       LITERAL_TOKEN(":", TOKEN_TYPE_SYM_COLON);\r
+       LITERAL_TOKEN(";", TOKEN_TYPE_SYM_SEMICOLON);\r
+       LITERAL_TOKEN(",", TOKEN_TYPE_SYM_COMMA);\r
+       LITERAL_TOKEN("=", TOKEN_TYPE_SYM_EQUALS);\r
+       LITERAL_TOKEN("`", TOKEN_TYPE_SYM_GRAVE);\r
+       LITERAL_TOKEN("~", TOKEN_TYPE_SYM_TILDE);\r
+       LITERAL_TOKEN("!", TOKEN_TYPE_SYM_BANG);\r
+       LITERAL_TOKEN("^", TOKEN_TYPE_SYM_CARET);\r
+       LITERAL_TOKEN("&", TOKEN_TYPE_SYM_AMPERSAND);\r
+\r
+       // Symbols\r
+       if (char_is_alpha(*tk.token)) {\r
+               u64 len = 0;\r
+               while (char_is_alphanum(*tokenizer->curr) || charset_contains("_$", *tokenizer->curr)) {\r
+                       len++;\r
+                       INCREMENT_CURR_TOKEN(tokenizer);\r
+               }\r
+\r
+               tk.length = len;\r
+               tk.type = TOKEN_TYPE_SYMBOL;\r
+               goto token_parsed;\r
+       }\r
+\r
+       // String literal\r
+       if (*tk.token == '"') {\r
+               u64 len = 0;\r
+               u64 slash_count = 0;\r
+\r
+               INCREMENT_CURR_TOKEN(tokenizer);\r
+\r
+               while (!(*tokenizer->curr == '"' && slash_count == 0)) {\r
+                       len++;\r
+\r
+                       if (*tokenizer->curr == '\\') {\r
+                               slash_count += 1;\r
+                               slash_count %= 2;\r
+                       } else {\r
+                               slash_count = 0;\r
+                       }\r
+\r
+                       INCREMENT_CURR_TOKEN(tokenizer);\r
+               }\r
+\r
+               INCREMENT_CURR_TOKEN(tokenizer);\r
+\r
+               tk.token++;\r
+               tk.type = TOKEN_TYPE_LITERAL_STRING;\r
+               tk.length = len;\r
+               goto token_parsed;\r
+       }\r
+\r
+       // Number literal\r
+       if (char_is_num(*tokenizer->curr)) {\r
+               u64 len = 0;\r
+               while (char_is_num(*(tokenizer->curr + 1)) || *(tokenizer->curr + 1) == '.') {\r
+                       len++;\r
+                       INCREMENT_CURR_TOKEN(tokenizer);\r
+               }\r
+\r
+               tk.type = TOKEN_TYPE_LITERAL_NUMERIC;\r
+               tk.length = len;\r
+       }\r
+\r
+       INCREMENT_CURR_TOKEN(tokenizer);\r
+\r
+token_parsed:\r
+       bh_arr_push(tokenizer->tokens, tk);\r
+\r
+       return &tokenizer->tokens[bh_arr_length(tokenizer->tokens) - 1];\r
+}\r
+\r
+OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc) {\r
+       OnyxTokenizer tknizer = {\r
+               .start                  = fc->data,\r
+               .curr                   = fc->data,\r
+               .end                    = fc->data + fc->length,\r
+\r
+               .filename               = fc->filename,\r
+\r
+               .line_number    = 1,\r
+               .line_start     = fc->data,\r
+               .tokens                 = NULL,\r
+       };\r
+\r
+       bh_arr_new(allocator, tknizer.tokens, 512);\r
+       return tknizer;\r
+}\r
+\r
+void onyx_tokenizer_free(OnyxTokenizer* tokenizer) {\r
+       bh_arr_free(tokenizer->tokens);\r
+}\r
+\r
+void onyx_lex_tokens(OnyxTokenizer* tokenizer) {\r
+       OnyxToken* tk;\r
+       do {\r
+               tk = onyx_get_token(tokenizer);\r
+       } while (tk->type != TOKEN_TYPE_END_STREAM);\r
+}\r
index 1fbce3a91569b2e88d3ce0c7891551b6755e9f14..d2c07771bd7065ca62d2f14dc137613c046e11e1 100644 (file)
--- a/onyxlex.h
+++ b/onyxlex.h
@@ -1,89 +1,89 @@
-#ifndef ONYXLEX_H
-#define ONYXLEX_H
-
-#include "bh.h"
-
-typedef enum OnyxTokenType {
-       TOKEN_TYPE_UNKNOWN,
-       TOKEN_TYPE_END_STREAM,
-
-       TOKEN_TYPE_COMMENT,
-
-       TOKEN_TYPE_KEYWORD_STRUCT,
-       TOKEN_TYPE_KEYWORD_USE,
-       TOKEN_TYPE_KEYWORD_EXPORT,
-       TOKEN_TYPE_KEYWORD_IF,
-       TOKEN_TYPE_KEYWORD_ELSE,
-       TOKEN_TYPE_KEYWORD_FOR,
-       TOKEN_TYPE_KEYWORD_DO,
-       TOKEN_TYPE_KEYWORD_RETURN,
-       TOKEN_TYPE_KEYWORD_FOREIGN,
-       TOKEN_TYPE_KEYWORD_PROC,
-       TOKEN_TYPE_KEYWORD_GLOBAL,
-
-       TOKEN_TYPE_RIGHT_ARROW,
-       TOKEN_TYPE_LEFT_ARROW,
-       TOKEN_TYPE_OPEN_PAREN,
-       TOKEN_TYPE_CLOSE_PAREN,
-       TOKEN_TYPE_OPEN_BRACE,
-       TOKEN_TYPE_CLOSE_BRACE,
-       TOKEN_TYPE_OPEN_BRACKET,
-       TOKEN_TYPE_CLOSE_BRACKET,
-       TOKEN_TYPE_OPEN_ANGLE,
-       TOKEN_TYPE_CLOSE_ANGLE,
-
-       TOKEN_TYPE_SYM_PLUS,
-       TOKEN_TYPE_SYM_MINUS,
-       TOKEN_TYPE_SYM_STAR,
-       TOKEN_TYPE_SYM_PERCENT,
-       TOKEN_TYPE_SYM_DOT,
-       TOKEN_TYPE_SYM_FSLASH,
-       TOKEN_TYPE_SYM_BSLASH,
-       TOKEN_TYPE_SYM_COLON,
-       TOKEN_TYPE_SYM_SEMICOLON,
-       TOKEN_TYPE_SYM_COMMA,
-       TOKEN_TYPE_SYM_EQUALS,
-       TOKEN_TYPE_SYM_GRAVE,
-       TOKEN_TYPE_SYM_TILDE,
-       TOKEN_TYPE_SYM_BANG,
-       TOKEN_TYPE_SYM_CARET,
-       TOKEN_TYPE_SYM_AMPERSAND,
-
-       TOKEN_TYPE_SYMBOL,
-       TOKEN_TYPE_LITERAL_STRING,
-       TOKEN_TYPE_LITERAL_NUMERIC,
-
-       TOKEN_TYPE_COUNT
-} OnyxTokenType;
-
-typedef struct OnyxFilePos {
-       const char* filename;
-       u64 line, column;
-} OnyxFilePos;
-
-typedef struct OnyxToken {
-       OnyxTokenType type;
-       isize length;
-       char* token;
-       OnyxFilePos pos;
-} OnyxToken;
-
-typedef struct OnyxTokenizer {
-       char *start, *curr, *end;
-
-       const char* filename;
-
-       char* line_start;
-       u64 line_number;
-
-       bh_arr(OnyxToken) tokens;
-} OnyxTokenizer;
-
-const char* onyx_get_token_type_name(OnyxTokenType tkn_type);
-void onyx_token_null_toggle(OnyxToken tkn);
-OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer);
-OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc);
-void onyx_tokenizer_free(OnyxTokenizer* tokenizer);
-void onyx_lex_tokens(OnyxTokenizer* tokenizer);
-
-#endif
+#ifndef ONYXLEX_H\r
+#define ONYXLEX_H\r
+\r
+#include "bh.h"\r
+\r
+typedef enum OnyxTokenType {\r
+       TOKEN_TYPE_UNKNOWN,\r
+       TOKEN_TYPE_END_STREAM,\r
+\r
+       TOKEN_TYPE_COMMENT,\r
+\r
+       TOKEN_TYPE_KEYWORD_STRUCT,\r
+       TOKEN_TYPE_KEYWORD_USE,\r
+       TOKEN_TYPE_KEYWORD_EXPORT,\r
+       TOKEN_TYPE_KEYWORD_IF,\r
+       TOKEN_TYPE_KEYWORD_ELSE,\r
+       TOKEN_TYPE_KEYWORD_FOR,\r
+       TOKEN_TYPE_KEYWORD_DO,\r
+       TOKEN_TYPE_KEYWORD_RETURN,\r
+       TOKEN_TYPE_KEYWORD_FOREIGN,\r
+       TOKEN_TYPE_KEYWORD_PROC,\r
+       TOKEN_TYPE_KEYWORD_GLOBAL,\r
+\r
+       TOKEN_TYPE_RIGHT_ARROW,\r
+       TOKEN_TYPE_LEFT_ARROW,\r
+       TOKEN_TYPE_OPEN_PAREN,\r
+       TOKEN_TYPE_CLOSE_PAREN,\r
+       TOKEN_TYPE_OPEN_BRACE,\r
+       TOKEN_TYPE_CLOSE_BRACE,\r
+       TOKEN_TYPE_OPEN_BRACKET,\r
+       TOKEN_TYPE_CLOSE_BRACKET,\r
+       TOKEN_TYPE_OPEN_ANGLE,\r
+       TOKEN_TYPE_CLOSE_ANGLE,\r
+\r
+       TOKEN_TYPE_SYM_PLUS,\r
+       TOKEN_TYPE_SYM_MINUS,\r
+       TOKEN_TYPE_SYM_STAR,\r
+       TOKEN_TYPE_SYM_PERCENT,\r
+       TOKEN_TYPE_SYM_DOT,\r
+       TOKEN_TYPE_SYM_FSLASH,\r
+       TOKEN_TYPE_SYM_BSLASH,\r
+       TOKEN_TYPE_SYM_COLON,\r
+       TOKEN_TYPE_SYM_SEMICOLON,\r
+       TOKEN_TYPE_SYM_COMMA,\r
+       TOKEN_TYPE_SYM_EQUALS,\r
+       TOKEN_TYPE_SYM_GRAVE,\r
+       TOKEN_TYPE_SYM_TILDE,\r
+       TOKEN_TYPE_SYM_BANG,\r
+       TOKEN_TYPE_SYM_CARET,\r
+       TOKEN_TYPE_SYM_AMPERSAND,\r
+\r
+       TOKEN_TYPE_SYMBOL,\r
+       TOKEN_TYPE_LITERAL_STRING,\r
+       TOKEN_TYPE_LITERAL_NUMERIC,\r
+\r
+       TOKEN_TYPE_COUNT\r
+} OnyxTokenType;\r
+\r
+typedef struct OnyxFilePos {\r
+       const char* filename;\r
+       u64 line, column;\r
+} OnyxFilePos;\r
+\r
+typedef struct OnyxToken {\r
+       OnyxTokenType type;\r
+       isize length;\r
+       char* token;\r
+       OnyxFilePos pos;\r
+} OnyxToken;\r
+\r
+typedef struct OnyxTokenizer {\r
+       char *start, *curr, *end;\r
+\r
+       const char* filename;\r
+\r
+       char* line_start;\r
+       u64 line_number;\r
+\r
+       bh_arr(OnyxToken) tokens;\r
+} OnyxTokenizer;\r
+\r
+const char* onyx_get_token_type_name(OnyxTokenType tkn_type);\r
+void onyx_token_null_toggle(OnyxToken tkn);\r
+OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer);\r
+OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc);\r
+void onyx_tokenizer_free(OnyxTokenizer* tokenizer);\r
+void onyx_lex_tokens(OnyxTokenizer* tokenizer);\r
+\r
+#endif\r
index 53b35975f613c75734dcbfa27810ea4c99bd12b9..42cb3266be69569791669f66194babbdfd0b067b 100644 (file)
@@ -1,44 +1,44 @@
-
-#include "onyxmsgs.h"
-
-static const char* msg_formats[] = {
-       "expected token '%s', got '%s'",
-       "unexpected token '%s'",
-       "unknown type '%s'"
-};
-
-void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...) {
-       OnyxMessage* msg = bh_alloc_item(msgs->allocator, OnyxMessage);
-       msg->type = type;
-       msg->pos = pos;
-
-       va_list arg_list;
-       va_start(arg_list, pos);
-       bh_snprintf_va(msg->text, ONYX_MSG_BUFFER_SIZE, msg_formats[type], arg_list);
-       va_end(arg_list);
-
-       OnyxMessage** walker = &msgs->first;
-       while (*walker && (*walker)->pos.line < pos.line) walker = &(*walker)->next;
-       while (*walker && (*walker)->pos.line == pos.line && (*walker)->pos.column < pos.column) walker = &(*walker)->next;
-
-       msg->next = *walker;
-       *walker = msg;
-}
-
-void onyx_message_print(OnyxMessages* msgs) {
-       OnyxMessage* msg = msgs->first;
-
-       while (msg) {
-               if (msg->pos.filename) {
-                       bh_printf("(%s:%l:%l) %s\n", msg->pos.filename, msg->pos.line, msg->pos.column, msg->text);
-               } else {
-                       bh_printf("(%l:%l) %s\n", msg->pos.line, msg->pos.column, msg->text);
-               }
-               msg = msg->next;
-       }
-}
-
-void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs) {
-       msgs->allocator = allocator;
-       msgs->first = NULL;
-}
+\r
+#include "onyxmsgs.h"\r
+\r
+static const char* msg_formats[] = {\r
+       "expected token '%s', got '%s'",\r
+       "unexpected token '%s'",\r
+       "unknown type '%s'"\r
+};\r
+\r
+void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...) {\r
+       OnyxMessage* msg = bh_alloc_item(msgs->allocator, OnyxMessage);\r
+       msg->type = type;\r
+       msg->pos = pos;\r
+\r
+       va_list arg_list;\r
+       va_start(arg_list, pos);\r
+       bh_snprintf_va(msg->text, ONYX_MSG_BUFFER_SIZE, msg_formats[type], arg_list);\r
+       va_end(arg_list);\r
+\r
+       OnyxMessage** walker = &msgs->first;\r
+       while (*walker && (*walker)->pos.line < pos.line) walker = &(*walker)->next;\r
+       while (*walker && (*walker)->pos.line == pos.line && (*walker)->pos.column < pos.column) walker = &(*walker)->next;\r
+\r
+       msg->next = *walker;\r
+       *walker = msg;\r
+}\r
+\r
+void onyx_message_print(OnyxMessages* msgs) {\r
+       OnyxMessage* msg = msgs->first;\r
+\r
+       while (msg) {\r
+               if (msg->pos.filename) {\r
+                       bh_printf("(%s:%l:%l) %s\n", msg->pos.filename, msg->pos.line, msg->pos.column, msg->text);\r
+               } else {\r
+                       bh_printf("(%l:%l) %s\n", msg->pos.line, msg->pos.column, msg->text);\r
+               }\r
+               msg = msg->next;\r
+       }\r
+}\r
+\r
+void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs) {\r
+       msgs->allocator = allocator;\r
+       msgs->first = NULL;\r
+}\r
index db3a22ce2dae637a54089a0316d21236e8a921af..9d615d98224a7790d156af45e6082e02eea11949 100644 (file)
@@ -1,36 +1,36 @@
-#ifndef ONYXMSGS_H
-#define ONYXMSGS_H
-
-#include "bh.h"
-#include "onyxlex.h"
-
-#include <stdarg.h>
-
-#define ONYX_MSG_BUFFER_SIZE 256
-
-typedef enum OnyxMessageType {
-       ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
-       ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
-       ONYX_MESSAGE_TYPE_UNKNOWN_TYPE,
-
-       ONYX_MESSAGE_TYPE_COUNT,
-} OnyxMessageType;
-       
-typedef struct OnyxMessage {
-       OnyxMessageType type;
-       OnyxFilePos pos;
-       struct OnyxMessage* next;
-       char text[ONYX_MSG_BUFFER_SIZE];
-} OnyxMessage;
-
-typedef struct OnyxMessages {
-       bh_allocator allocator;
-
-       OnyxMessage* first;
-} OnyxMessages;
-
-void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...);
-void onyx_message_print(OnyxMessages* msgs);
-void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs);
-
+#ifndef ONYXMSGS_H\r
+#define ONYXMSGS_H\r
+\r
+#include "bh.h"\r
+#include "onyxlex.h"\r
+\r
+#include <stdarg.h>\r
+\r
+#define ONYX_MSG_BUFFER_SIZE 256\r
+\r
+typedef enum OnyxMessageType {\r
+       ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,\r
+       ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,\r
+       ONYX_MESSAGE_TYPE_UNKNOWN_TYPE,\r
+\r
+       ONYX_MESSAGE_TYPE_COUNT,\r
+} OnyxMessageType;\r
+       \r
+typedef struct OnyxMessage {\r
+       OnyxMessageType type;\r
+       OnyxFilePos pos;\r
+       struct OnyxMessage* next;\r
+       char text[ONYX_MSG_BUFFER_SIZE];\r
+} OnyxMessage;\r
+\r
+typedef struct OnyxMessages {\r
+       bh_allocator allocator;\r
+\r
+       OnyxMessage* first;\r
+} OnyxMessages;\r
+\r
+void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...);\r
+void onyx_message_print(OnyxMessages* msgs);\r
+void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs);\r
+\r
 #endif
\ No newline at end of file
index e5cfe1e818a7599413be44ab9273b1bebce81e2a..27d6f037e188b4e316f4beddda59793b70cc252f 100644 (file)
-
-#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
index 54c2553c291dfe85c5653ce87240add29bae440c..b8d04e5cb25f26d3e4161317276f1a9a921d0f6d 100644 (file)
-#ifndef ONYXPARSER_H
-#define ONYXPARSER_H
-
-#define BH_NO_STRING
-#include "bh.h"
-
-#include "onyxlex.h"
-#include "onyxmsgs.h"
-
-typedef union OnyxAstNode OnyxAstNode;
-typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
-typedef struct OnyxAstNodeParam OnyxAstNodeParam;
-typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;
-
-typedef struct OnyxParser {
-       OnyxTokenizer *tokenizer;
-       OnyxToken *prev_token;
-       OnyxToken *curr_token;
-
-       bh_hash(OnyxAstNode*) identifiers;
-
-       OnyxMessages *msgs;
-
-       bh_allocator allocator;
-} OnyxParser;
-
-typedef enum OnyxAstNodeKind {
-       ONYX_AST_NODE_KIND_ERROR,
-       ONYX_AST_NODE_KIND_PROGRAM,
-
-       ONYX_AST_NODE_KIND_FUNCDEF,
-       ONYX_AST_NODE_KIND_BLOCK,
-       ONYX_AST_NODE_KIND_SCOPE,
-
-       ONYX_AST_NODE_KIND_ADD,
-       ONYX_AST_NODE_KIND_SUB,
-       ONYX_AST_NODE_KIND_MUL,
-       ONYX_AST_NODE_KIND_DIVIDE,
-       ONYX_AST_NODE_KIND_MODULUS,
-       ONYX_AST_NODE_KIND_NEGATE,
-
-       ONYX_AST_NODE_KIND_TYPE,
-       ONYX_AST_NODE_KIND_LITERAL,
-       ONYX_AST_NODE_KIND_CAST,
-       ONYX_AST_NODE_KIND_PARAM,
-       ONYX_AST_NODE_KIND_CALL,
-       ONYX_AST_NODE_KIND_RETURN,
-
-       ONYX_AST_NODE_KIND_EQUAL,
-       ONYX_AST_NODE_KIND_NOT_EQUAL,
-       ONYX_AST_NODE_KIND_GREATER,
-       ONYX_AST_NODE_KIND_GREATER_EQUAL,
-       ONYX_AST_NODE_KIND_LESS,
-       ONYX_AST_NODE_KIND_LESS_EQUAL,
-       ONYX_AST_NODE_KIND_NOT,
-
-       ONYX_AST_NODE_KIND_IF,
-       ONYX_AST_NODE_KIND_LOOP,
-
-       ONYX_AST_NODE_KIND_COUNT
-} OnyxAstNodeKind;
-
-typedef enum OnyxTypeInfoKind {
-       ONYX_TYPE_INFO_KIND_UNKNOWN,
-       ONYX_TYPE_INFO_KIND_VOID,
-       ONYX_TYPE_INFO_KIND_BOOL,
-
-       ONYX_TYPE_INFO_KIND_UINT8,
-       ONYX_TYPE_INFO_KIND_UINT16,
-       ONYX_TYPE_INFO_KIND_UINT32,
-       ONYX_TYPE_INFO_KIND_UINT64,
-
-       ONYX_TYPE_INFO_KIND_INT8,
-       ONYX_TYPE_INFO_KIND_INT16,
-       ONYX_TYPE_INFO_KIND_INT32,
-       ONYX_TYPE_INFO_KIND_INT64,
-
-       ONYX_TYPE_INFO_KIND_FLOAT32,    
-       ONYX_TYPE_INFO_KIND_FLOAT64,
-       ONYX_TYPE_INFO_KIND_SOFT_FLOAT, // 64-bits of data but could be treated as 32-bit
-} OnyxTypeInfoKind;
-
-typedef struct OnyxTypeInfo {
-       OnyxTypeInfoKind kind;
-       u32 size; // in bytes
-       const char* name;
-       u32 is_int : 1;
-       u32 is_unsigned : 1;
-       u32 is_float : 1;
-       u32 is_bool : 1;
-} OnyxTypeInfo;
-
-extern OnyxTypeInfo builtin_types[];
-
-typedef enum OnyxAstFlags {
-       ONYX_AST_BLOCK_FLAG_HAS_RETURN = BH_BIT(1),
-       ONYX_AST_BLOCK_FLAG_TOP_LEVEL  = BH_BIT(2),
-       ONYX_AST_BLOCK_FLAG_EXPORTED   = BH_BIT(3),
-} OnyxAstFlags;
-
-struct OnyxAstNodeBlock {
-       OnyxAstNodeKind kind;
-       u32 flags;
-       OnyxToken *token;
-       OnyxTypeInfo *return_type;
-       OnyxAstNode *next;
-       OnyxAstNode *body;
-       OnyxAstNode *unused1;
-};
-
-struct OnyxAstNodeParam {
-       OnyxAstNodeKind kind;
-       u32 flags;
-       OnyxToken *token;                       // Symbol name i.e. 'a', 'b'
-       OnyxTypeInfo *type;
-       OnyxAstNodeParam *next;
-       OnyxAstNode *left;
-       OnyxAstNode *right;     
-};
-
-struct OnyxAstNodeFuncDef {
-       OnyxAstNodeKind kind;
-       u32 flags;
-       OnyxToken *token; // This will point to the symbol token to identify it
-       OnyxTypeInfo *return_type;
-       OnyxAstNodeBlock *body;
-       OnyxAstNodeParam *params;
-       u64 param_count; // Same size as ptr
-};
-
-union OnyxAstNode {
-
-       // Generic node structure for capturing all binary ops and statements
-       struct {
-               OnyxAstNodeKind kind;
-               u32 flags;
-               OnyxToken *token;
-               OnyxTypeInfo *type;
-               OnyxAstNode *next;
-               OnyxAstNode *left;
-               OnyxAstNode *right;
-       };
-
-       OnyxAstNodeBlock as_block;
-       OnyxAstNodeFuncDef as_funcdef;
-       OnyxAstNodeParam as_param;
-};
-
-OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind);
-OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs);
-void onyx_parser_free(OnyxParser* parser);
-OnyxAstNode* onyx_parse(OnyxParser *parser);
-
-#endif // #ifndef ONYXPARSER_H
\ No newline at end of file
+#ifndef ONYXPARSER_H\r
+#define ONYXPARSER_H\r
+\r
+#define BH_NO_STRING\r
+#include "bh.h"\r
+\r
+#include "onyxlex.h"\r
+#include "onyxmsgs.h"\r
+\r
+typedef union OnyxAstNode OnyxAstNode;\r
+typedef struct OnyxAstNodeLocal OnyxAstNodeLocal;\r
+typedef struct OnyxAstNodeScope OnyxAstNodeScope;\r
+typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;\r
+typedef struct OnyxAstNodeParam OnyxAstNodeParam;\r
+typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;\r
+\r
+typedef struct OnyxParser {\r
+       OnyxTokenizer *tokenizer; // NOTE: not used since all tokens are lexed before parsing starts\r
+       OnyxToken *prev_token;\r
+       OnyxToken *curr_token;\r
+\r
+       // BUG: This way of handling identifiers will work for now,\r
+       // but it will not allow for shadowing. Also, variable names\r
+       // cannot be the same as any function or global variable.\r
+       // That will get annoying to program.\r
+       // NOTE: A table of the current identifiers in the current scope.\r
+       // If the identifier doesn't at the time of parsing, it is an error.\r
+       // Cleared at the end of a block.\r
+       bh_hash(OnyxAstNode*) identifiers;\r
+       OnyxAstNodeScope *curr_scope;\r
+\r
+       OnyxMessages *msgs;\r
+\r
+       bh_allocator allocator;\r
+} OnyxParser;\r
+\r
+typedef enum OnyxAstNodeKind {\r
+       ONYX_AST_NODE_KIND_ERROR,\r
+       ONYX_AST_NODE_KIND_PROGRAM,\r
+\r
+       ONYX_AST_NODE_KIND_FUNCDEF,\r
+       ONYX_AST_NODE_KIND_BLOCK,\r
+       ONYX_AST_NODE_KIND_SCOPE,\r
+       ONYX_AST_NODE_KIND_LOCAL,\r
+\r
+       ONYX_AST_NODE_KIND_ADD,\r
+       ONYX_AST_NODE_KIND_MINUS,\r
+       ONYX_AST_NODE_KIND_MULTIPLY,\r
+       ONYX_AST_NODE_KIND_DIVIDE,\r
+       ONYX_AST_NODE_KIND_MODULUS,\r
+       ONYX_AST_NODE_KIND_NEGATE,\r
+\r
+       ONYX_AST_NODE_KIND_TYPE,\r
+       ONYX_AST_NODE_KIND_LITERAL,\r
+       ONYX_AST_NODE_KIND_CAST,\r
+       ONYX_AST_NODE_KIND_PARAM,\r
+       ONYX_AST_NODE_KIND_CALL,\r
+       ONYX_AST_NODE_KIND_ASSIGNMENT,\r
+       ONYX_AST_NODE_KIND_RETURN,\r
+\r
+       ONYX_AST_NODE_KIND_EQUAL,\r
+       ONYX_AST_NODE_KIND_NOT_EQUAL,\r
+       ONYX_AST_NODE_KIND_GREATER,\r
+       ONYX_AST_NODE_KIND_GREATER_EQUAL,\r
+       ONYX_AST_NODE_KIND_LESS,\r
+       ONYX_AST_NODE_KIND_LESS_EQUAL,\r
+       ONYX_AST_NODE_KIND_NOT,\r
+\r
+       ONYX_AST_NODE_KIND_IF,\r
+       ONYX_AST_NODE_KIND_LOOP,\r
+\r
+       ONYX_AST_NODE_KIND_COUNT\r
+} OnyxAstNodeKind;\r
+\r
+typedef enum OnyxTypeInfoKind {\r
+       ONYX_TYPE_INFO_KIND_UNKNOWN,\r
+       ONYX_TYPE_INFO_KIND_VOID,\r
+       ONYX_TYPE_INFO_KIND_BOOL,\r
+\r
+       ONYX_TYPE_INFO_KIND_UINT8,\r
+       ONYX_TYPE_INFO_KIND_UINT16,\r
+       ONYX_TYPE_INFO_KIND_UINT32,\r
+       ONYX_TYPE_INFO_KIND_UINT64,\r
+\r
+       ONYX_TYPE_INFO_KIND_INT8,\r
+       ONYX_TYPE_INFO_KIND_INT16,\r
+       ONYX_TYPE_INFO_KIND_INT32,\r
+       ONYX_TYPE_INFO_KIND_INT64,\r
+\r
+       ONYX_TYPE_INFO_KIND_FLOAT32,\r
+       ONYX_TYPE_INFO_KIND_FLOAT64,\r
+       ONYX_TYPE_INFO_KIND_SOFT_FLOAT, // 64-bits of data but could be treated as 32-bit\r
+} OnyxTypeInfoKind;\r
+\r
+typedef struct OnyxTypeInfo {\r
+       OnyxTypeInfoKind kind;\r
+       u32 size; // in bytes\r
+       const char* name;\r
+       u32 is_int : 1;\r
+       u32 is_unsigned : 1;\r
+       u32 is_float : 1;\r
+       u32 is_bool : 1;\r
+} OnyxTypeInfo;\r
+\r
+extern OnyxTypeInfo builtin_types[];\r
+\r
+typedef enum OnyxAstFlags {\r
+       ONYX_AST_FLAG_HAS_RETURN = BH_BIT(1),\r
+       ONYX_AST_FLAG_TOP_LEVEL  = BH_BIT(2),\r
+       ONYX_AST_FLAG_EXPORTED   = BH_BIT(3),\r
+       ONYX_AST_FLAG_FUNCTION_PARAM = BH_BIT(3),\r
+} OnyxAstFlags;\r
+\r
+struct OnyxAstNodeLocal {\r
+       OnyxAstNodeKind kind;\r
+       u32 flags;\r
+       OnyxToken *token;\r
+       OnyxTypeInfo *type;\r
+       OnyxAstNodeLocal *prev_local;\r
+       OnyxAstNode *unused1;\r
+       OnyxAstNode *unused2;\r
+};\r
+\r
+struct OnyxAstNodeScope {\r
+       OnyxAstNodeKind kind;\r
+       u32 flags;\r
+       OnyxToken *token;       // NOTE: UNUSED\r
+       OnyxTypeInfo *type; // NOTE: UNUSED\r
+       OnyxAstNodeScope *prev_scope;\r
+       OnyxAstNodeLocal *last_local;\r
+       OnyxAstNode *unused;\r
+};\r
+\r
+struct OnyxAstNodeBlock {\r
+       OnyxAstNodeKind kind;\r
+       u32 flags;\r
+       OnyxToken *token;\r
+       OnyxTypeInfo *return_type;\r
+       OnyxAstNode *next;\r
+       OnyxAstNode *body;\r
+       OnyxAstNodeScope *scope; // NOTE: Only set on blocks belonging to functions\r
+};\r
+\r
+struct OnyxAstNodeParam {\r
+       OnyxAstNodeKind kind;\r
+       u32 flags;\r
+       OnyxToken *token;                       // Symbol name i.e. 'a', 'b'\r
+       OnyxTypeInfo *type;\r
+       OnyxAstNodeParam *next;\r
+       u64 param_count;\r
+       OnyxAstNode *right;\r
+};\r
+\r
+struct OnyxAstNodeFuncDef {\r
+       OnyxAstNodeKind kind;\r
+       u32 flags;\r
+       OnyxToken *token; // This will point to the symbol token to identify it\r
+       OnyxTypeInfo *return_type;\r
+       OnyxAstNode *next;\r
+       OnyxAstNodeBlock *body;\r
+       OnyxAstNodeParam *params;\r
+};\r
+\r
+union OnyxAstNode {\r
+\r
+       // Generic node structure for capturing all binary ops and statements\r
+       struct {\r
+               OnyxAstNodeKind kind;\r
+               u32 flags;\r
+               OnyxToken *token;\r
+               OnyxTypeInfo *type;\r
+               OnyxAstNode *next;\r
+               OnyxAstNode *left;\r
+               OnyxAstNode *right;\r
+       };\r
+\r
+       OnyxAstNodeBlock as_block;\r
+       OnyxAstNodeFuncDef as_funcdef;\r
+       OnyxAstNodeParam as_param;\r
+};\r
+\r
+const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);\r
+OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind);\r
+OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs);\r
+void onyx_parser_free(OnyxParser* parser);\r
+OnyxAstNode* onyx_parse(OnyxParser *parser);\r
+\r
+#endif // #ifndef ONYXPARSER_H\r
diff --git a/onyxutils.c b/onyxutils.c
new file mode 100644 (file)
index 0000000..74b96e6
--- /dev/null
@@ -0,0 +1,26 @@
+#include "onyxutils.h"\r
+\r
+void onyx_ast_print(OnyxAstNode* node) {\r
+       if (node == NULL) return;\r
+\r
+       bh_printf("%s <%d> ", onyx_ast_node_kind_string(node->kind), node->flags);\r
+       if (node->token)\r
+               bh_printf("[%b] ", node->token->token, (int) node->token->length);\r
+\r
+       if ((i64) node->left > 10) { // HACK: but okay\r
+               bh_printf("(");\r
+               onyx_ast_print(node->left);\r
+               bh_printf(") ");\r
+       }\r
+       if ((i64) node->right > 10) { // HACK: but okay\r
+               bh_printf("(");\r
+               onyx_ast_print(node->right);\r
+               bh_printf(")");\r
+       }\r
+\r
+       if (node->next) {\r
+               bh_printf("{");\r
+               onyx_ast_print(node->next);\r
+               bh_printf("}");\r
+       }\r
+}\r
diff --git a/onyxutils.h b/onyxutils.h
new file mode 100644 (file)
index 0000000..a8e2e3a
--- /dev/null
@@ -0,0 +1,5 @@
+#include "bh.h"\r
+\r
+#include "onyxparser.h"\r
+\r
+void onyx_ast_print(OnyxAstNode* program);\r
index bbb2d1c8803ef3d55af479de6e75523f6427b26b..81dc7c8c23149b87138399d23e0528c0dda3c930 100644 (file)
@@ -1,8 +1,14 @@
-/* This is a comment */
-
-log :: proc (a i32, b i32) -> i32 ---;
-
-add :: proc (a i32, b i32) -> i32 {
-       /* More comments */
-       return a + b;
-};
\ No newline at end of file
+/* This is a comment */\r
+\r
+log :: proc (a i32, b i32) -> i32 ---;\r
+\r
+export add :: proc (a i32, b i32) -> i32 {\r
+       /* More comments */\r
+       return a + b;\r
+};\r
+\r
+export mul :: proc (a i32, b i32) -> i32 {\r
+       c: i32 = a - b;\r
+       d := a + 2;\r
+       return c * d;\r
+};\r