I hate windows line endings; other small changes; Implemented #11
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 23 May 2020 19:10:19 +0000 (14:10 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 23 May 2020 19:10:19 +0000 (14:10 -0500)
13 files changed:
bh.h
docs/parse_grammar
onyx
onyx.c
onyxlex.c
onyxlex.h
onyxmsgs.c
onyxmsgs.h
onyxparser.c
onyxparser.h
onyxutils.c
onyxutils.h
progs/minimal.onyx

diff --git a/bh.h b/bh.h
index c3679f23c5c4647e034f5a95bf912e4cce5cb2f1..95772a75b7f303fcc9acb3a098f590acd7a1302d 100644 (file)
--- a/bh.h
+++ b/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
+#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) {
+       arena_size = bh_max(arena_size, sizeof(ptr));
+       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 - sizeof(ptr)) {
+                       // 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;
+
+               case 'b': { // String with a length (not null terminated)
+                       char* s = va_arg(va, char *);
+                       i32 l = va_arg(va, int);
+                       len = bh__print_string(str, bh_min(l, 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);
+               }
+
+               arrptr = 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], walker;
+       if (arrptr == NULL) return; // Didn't exist
+       walker = arrptr;
+
+       i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE;
+       i32 i = 0;
+
+       i32 len = bh_arr_length(arrptr);
+       while (len && strncmp(key, (char *) walker, BH__HASH_STORED_KEY_SIZE) != 0) {
+               walker = bh_pointer_add(walker, stride);
+               i++, len--;
+       }
+
+       if (len == 0) return; // Didn't exist
+
+       bh__arr_deleten((void **) &arrptr, stride, i, 1);
+       table->arrs[index] = arrptr;
+}
+
+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);
+       if (it->arrlen <= 0) {
+               it->tab++;
+               goto step_to_next;
+       }
+       return 1;
+}
+
+#endif // ifndef BH_NO_HASHTABLE
+
+#endif // ifdef BH_DEFINE
+
+#endif // ifndef BH_H
index 610444a296b3e1c4776bdf26fc3333ed35f4206b..909fe1c9bccc85d0dc4cd6ea6d20978efd92d2b7 100644 (file)
@@ -1,78 +1,78 @@
-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
+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 }
+STRUCT_MEMBERS = COMMA_LIST(TOKEN_TYPE_SYMBOL :: TOKEN_TYPE_SYMBOL)
diff --git a/onyx b/onyx
index 3394ad0fe51e85ab2c41ca2c14cd02e966b8dc20..7759fcd93b530e775dfbe5c5d3faf33cff8f6c0d 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/onyx.c b/onyx.c
index 9c3b424a38b888c138bdf0d7dd76399784739d86..ebda7f6a23defc23e066c9ee757d5770a8fb7d4d 100644 (file)
--- a/onyx.c
+++ b/onyx.c
@@ -1,61 +1,61 @@
-#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
+#define BH_NO_STRING
+// #define BH_DEBUG
+#define BH_DEFINE
+#include "bh.h"
+
+#include "onyxlex.h"
+#include "onyxmsgs.h"
+#include "onyxparser.h"
+#include "onyxutils.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;
+
+       // bh_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);
+       //      bh_printf("%s (%s:%l:%l)\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);
+       onyx_ast_print(program);
+
+       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;
+}
index 69b3d3148cc16cff02ffffe54ecbb2a518e5f875..ca877d6c70547382fae56cafbcd60bcd6b7cc887 100644 (file)
--- a/onyxlex.c
+++ b/onyxlex.c
-#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
+#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);
+}
index d2c07771bd7065ca62d2f14dc137613c046e11e1..1fbce3a91569b2e88d3ce0c7891551b6755e9f14 100644 (file)
--- a/onyxlex.h
+++ b/onyxlex.h
@@ -1,89 +1,89 @@
-#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
+#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
index 42cb3266be69569791669f66194babbdfd0b067b..53b35975f613c75734dcbfa27810ea4c99bd12b9 100644 (file)
@@ -1,44 +1,44 @@
-\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
+
+#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;
+}
index 9d615d98224a7790d156af45e6082e02eea11949..1a2ae502a03d5b1621bee67fd40c82432bb47a30 100644 (file)
@@ -1,36 +1,36 @@
-#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
+#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);
+
+#endif
index 27d6f037e188b4e316f4beddda59793b70cc252f..475d38fc483824093f5225018944bc9f4712f078 100644 (file)
-\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
+
+#include "onyxlex.h"
+#include "onyxparser.h"
+
+static const char* ast_node_names[] = {
+       "ERROR",
+       "PROGRAM",
+
+       "FUNCDEF",
+       "BLOCK",
+       "SCOPE",
+       "LOCAL",
+
+       "ADD",
+       "MINUS",
+       "MULTIPLY",
+       "DIVIDE",
+       "MODULUS",
+       "NEGATE",
+
+       "TYPE",
+       "LITERAL",
+       "CAST",
+       "PARAM",
+       "CALL",
+       "ASSIGN",
+       "RETURN",
+
+       "EQUAL",
+       "NOT_EQUAL",
+       "GREATER",
+       "GREATER_EQUAL",
+       "LESS",
+       "LESS_EQUAL",
+       "NOT",
+
+       "IF",
+       "LOOP",
+
+       "ONYX_AST_NODE_KIND_COUNT",
+};
+
+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 } };
+
+// NOTE: Forward declarations
+static void parser_next_token(OnyxParser* parser);
+static void parser_prev_token(OnyxParser* parser);
+static b32 is_terminating_token(OnyxTokenType token_type);
+static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type);
+static OnyxAstNodeScope* enter_scope(OnyxParser* parser);
+static OnyxAstNodeScope* leave_scope(OnyxParser* parser);
+static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local);
+static OnyxAstNode* parse_factor(OnyxParser* parser);
+static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left);
+static OnyxAstNode* parse_expression(OnyxParser* parser);
+static OnyxAstNode* parse_if_stmt(OnyxParser* parser);
+static b32 parse_expression_statement(OnyxParser* parser, OnyxAstNode** ret);
+static OnyxAstNode* parse_return_statement(OnyxParser* parser);
+static OnyxAstNodeBlock* parse_block(OnyxParser* parser, b32 belongs_to_function);
+static OnyxAstNode* parse_statement(OnyxParser* parser);
+static OnyxTypeInfo* parse_type(OnyxParser* parser);
+static OnyxAstNodeParam* parse_function_params(OnyxParser* parser);
+static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser);
+static OnyxAstNode* parse_top_level_statement(OnyxParser* parser);
+
+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 void parser_prev_token(OnyxParser* parser) {
+       // TODO: This is probably wrong
+       parser->prev_token--;
+       while (parser->prev_token->type == TOKEN_TYPE_COMMENT) parser->prev_token--;
+       parser->curr_token = parser->prev_token;
+       parser->prev_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 OnyxAstNodeScope* enter_scope(OnyxParser* parser) {
+       OnyxAstNodeScope* scope = (OnyxAstNodeScope*) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_SCOPE);
+       scope->prev_scope = parser->curr_scope;
+       parser->curr_scope = scope;
+       return scope;
+}
+
+static OnyxAstNodeScope* leave_scope(OnyxParser* parser) {
+       // NOTE: Can't leave a scope if there is no scope
+       assert(parser->curr_scope != NULL);
+
+       for (OnyxAstNodeLocal *walker = parser->curr_scope->last_local; walker != NULL; walker = walker->prev_local) {
+               onyx_token_null_toggle(*walker->token);
+
+               if (walker->shadowed) {
+                       // NOTE: Restore shadowed variable
+                       bh_hash_put(OnyxAstNode*, parser->identifiers, walker->token->token, walker->shadowed);
+               } else {
+                       bh_hash_delete(OnyxAstNode*, parser->identifiers, walker->token->token);
+               }
+
+               onyx_token_null_toggle(*walker->token);
+       }
+
+       parser->curr_scope = parser->curr_scope->prev_scope;
+       return parser->curr_scope;
+}
+
+static OnyxAstNode* lookup_identifier(OnyxParser* parser, OnyxToken* token) {
+       OnyxAstNode* ident = NULL;
+
+       onyx_token_null_toggle(*token);
+       if (bh_hash_has(OnyxAstNode*, parser->identifiers, token->token)) {
+               ident = bh_hash_get(OnyxAstNode*, parser->identifiers, token->token);
+       }
+       onyx_token_null_toggle(*token);
+
+       return ident;
+}
+
+static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local) {
+       OnyxAstNodeScope* scope = parser->curr_scope;
+       local->prev_local = scope->last_local;
+       scope->last_local = local;
+
+       onyx_token_null_toggle(*local->token);
+       if (bh_hash_has(OnyxAstNodeLocal*, parser->identifiers, local->token->token)) {
+               local->shadowed = bh_hash_get(OnyxAstNode*, parser->identifiers, local->token->token);
+       }
+
+       bh_hash_put(OnyxAstNodeLocal*, parser->identifiers, local->token->token, local);
+       onyx_token_null_toggle(*local->token);
+}
+
+static OnyxAstNode* parse_factor(OnyxParser* parser) {
+       switch (parser->curr_token->type) {
+       case TOKEN_TYPE_OPEN_PAREN: {
+               parser_next_token(parser);
+               OnyxAstNode* expr = parse_expression(parser);
+               expect(parser, TOKEN_TYPE_CLOSE_PAREN);
+               return expr;
+       }
+
+       case TOKEN_TYPE_SYMBOL: {
+               OnyxToken* sym_token = expect(parser, TOKEN_TYPE_SYMBOL);
+               OnyxAstNode* sym_node = lookup_identifier(parser, sym_token);
+
+               // TODO: Handle calling a function
+               return sym_node;
+       }
+
+       case TOKEN_TYPE_LITERAL_NUMERIC: {
+               OnyxAstNode* lit_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);
+               lit_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_INT64];
+               lit_node->token = expect(parser, TOKEN_TYPE_LITERAL_NUMERIC);
+               return lit_node;
+       }
+
+       default:
+               onyx_message_add(parser->msgs,
+                       ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
+                       parser->curr_token->pos,
+                       onyx_get_token_type_name(parser->curr_token->type));
+       }
+
+       return NULL;
+}
+
+static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left) {
+       OnyxAstNodeKind kind = -1;
+
+       switch (parser->curr_token->type) {
+       case TOKEN_TYPE_SYM_PLUS:               kind = ONYX_AST_NODE_KIND_ADD; break;
+       case TOKEN_TYPE_SYM_MINUS:              kind = ONYX_AST_NODE_KIND_MINUS; break;
+       case TOKEN_TYPE_SYM_STAR:               kind = ONYX_AST_NODE_KIND_MULTIPLY; break;
+       case TOKEN_TYPE_SYM_FSLASH:             kind = ONYX_AST_NODE_KIND_DIVIDE; break;
+       case TOKEN_TYPE_SYM_PERCENT:    kind = ONYX_AST_NODE_KIND_MODULUS; break;
+       }
+
+       if (kind != -1) {
+               parser_next_token(parser);
+               OnyxAstNode* right = parse_factor(parser);
+
+               OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind);
+               bin_op->left = left;
+               bin_op->right = right;
+               return bin_op;
+       }
+
+       return &error_node;
+}
+
+static OnyxAstNode* parse_expression(OnyxParser* parser) {
+       OnyxAstNode* left = parse_factor(parser);
+
+       switch (parser->curr_token->type) {
+       case TOKEN_TYPE_SYM_PLUS:
+       case TOKEN_TYPE_SYM_MINUS:
+       case TOKEN_TYPE_SYM_STAR:
+       case TOKEN_TYPE_SYM_FSLASH:
+       case TOKEN_TYPE_SYM_PERCENT: {
+               OnyxAstNode* expr = parse_bin_op(parser, left);
+               return expr;
+       }
+       }
+
+       return left;
+}
+
+static OnyxAstNode* parse_if_stmt(OnyxParser* parser) {
+       return &error_node;
+}
+
+// Returns 1 if the symbol was consumed. Returns 0 otherwise
+// ret is set to the statement to insert
+static b32 parse_expression_statement(OnyxParser* parser, OnyxAstNode** ret) {
+       if (parser->curr_token->type != TOKEN_TYPE_SYMBOL) return 0;
+       OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);
+
+       switch (parser->curr_token->type) {
+       // NOTE: Declaration
+       case TOKEN_TYPE_SYM_COLON: {
+               parser_next_token(parser);
+               OnyxTypeInfo* type = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];
+
+               // NOTE: var: type
+               if (parser->curr_token->type == TOKEN_TYPE_SYMBOL) {
+                       type = parse_type(parser);
+               }
+
+               OnyxAstNodeLocal* local = (OnyxAstNodeLocal*) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LOCAL);
+               local->token = symbol;
+               local->type = type;
+
+               insert_identifier(parser, local);
+
+               if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) {
+                       parser_next_token(parser);
+
+                       OnyxAstNode* expr = parse_expression(parser);
+                       OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
+                       assignment->right = expr;
+                       assignment->left = (OnyxAstNode*) local;
+                       *ret = assignment;
+               }
+               return 1;
+       }
+
+       // NOTE: Assignment
+       case TOKEN_TYPE_SYM_EQUALS: {
+               parser_next_token(parser);
+
+               OnyxAstNode* lval = lookup_identifier(parser, symbol);
+
+               if (lval == NULL) {
+                       // TODO: error handling
+               }
+
+               OnyxAstNode* rval = parse_expression(parser);
+               OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
+               assignment->right = rval;
+               assignment->left = lval;
+               *ret = assignment;
+               return 1;
+       }
+
+       default:
+               parser_prev_token(parser);
+       }
+
+       return 0;
+}
+
+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;
+
+       if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {
+               expr = parse_expression(parser);
+
+               if (expr == NULL || expr == &error_node) {
+                       return &error_node;
+               } else {
+                       return_node->next = expr;
+               }
+       }
+
+       return return_node;
+}
+
+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, 0);
+
+       case TOKEN_TYPE_SYMBOL: {
+               OnyxAstNode* ret = NULL;
+               if (parse_expression_statement(parser, &ret)) return ret;
+               // fallthrough
+       }
+
+       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(parser);
+
+       case TOKEN_TYPE_KEYWORD_IF:
+               return parse_if_stmt(parser);
+
+       default:
+               return NULL;
+       }
+}
+
+static OnyxAstNodeBlock* parse_block(OnyxParser* parser, b32 belongs_to_function) {
+       // --- 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);
+       if (belongs_to_function) {
+               OnyxAstNodeScope* scope = enter_scope(parser);
+               block->scope = scope;
+       }
+
+       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;
+               }
+
+               if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {
+                       onyx_message_add(parser->msgs,
+                               ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
+                               parser->curr_token->pos,
+                               onyx_get_token_type_name(TOKEN_TYPE_SYM_SEMICOLON),
+                               onyx_get_token_type_name(parser->curr_token->type));
+               }
+               parser_next_token(parser);
+       }
+
+       expect(parser, TOKEN_TYPE_CLOSE_BRACE);
+
+       if (belongs_to_function) {
+               leave_scope(parser);
+       }
+
+       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;
+       u64 param_count = 0;
+
+       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);
+               param_count++;
+
+               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;
+       }
+
+       first_param->param_count = param_count;
+
+       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);
+
+       OnyxAstNodeParam* params = parse_function_params(parser);
+       func_def->params = params;
+
+       expect(parser, TOKEN_TYPE_RIGHT_ARROW);
+
+       OnyxTypeInfo* return_type = parse_type(parser);
+       func_def->return_type = return_type;
+
+       // TODO: Add params to parser.identifiers
+       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
+               onyx_token_null_toggle(*p->token);
+               bh_hash_put(OnyxAstNode*, parser->identifiers, p->token->token, (OnyxAstNode*) p);
+               onyx_token_null_toggle(*p->token);
+       }
+
+       func_def->body = parse_block(parser, 1);
+
+       // TODO: Remove params from parser.identifiers
+       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
+               onyx_token_null_toggle(*p->token);
+               bh_hash_delete(OnyxAstNode*, parser->identifiers, p->token->token);
+               onyx_token_null_toggle(*p->token);
+       }
+       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: {
+               expect(parser, TOKEN_TYPE_KEYWORD_EXPORT);
+               if (parser->curr_token->type != TOKEN_TYPE_SYMBOL) {
+                       onyx_message_add(parser->msgs,
+                               ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
+                               parser->curr_token->pos,
+                               onyx_get_token_type_name(TOKEN_TYPE_SYMBOL),
+                               onyx_get_token_type_name(parser->curr_token->type));
+                       break;
+               }
+
+               OnyxAstNode* top_level_decl = parse_top_level_statement(parser);
+               top_level_decl->flags |= ONYX_AST_FLAG_EXPORTED;
+               return top_level_decl;
+       } 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;
+}
+
+
+
+
+
+const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind) {
+       return ast_node_names[kind];
+}
+
+OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\
+       OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode));
+       node->kind = kind;
+       node->flags = 0;
+       node->token = NULL;
+       node->type = NULL;
+       node->next = NULL;
+       node->left = NULL;
+       node->right = NULL;
+
+       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;
+       parser.curr_scope = NULL;
+
+       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;
+}
index b8d04e5cb25f26d3e4161317276f1a9a921d0f6d..270deba3891d343752716857bbda03ac24af2d11 100644 (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
+#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 OnyxAstNodeLocal OnyxAstNodeLocal;
+typedef struct OnyxAstNodeScope OnyxAstNodeScope;
+typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
+typedef struct OnyxAstNodeParam OnyxAstNodeParam;
+typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;
+
+typedef struct OnyxParser {
+       OnyxTokenizer *tokenizer; // NOTE: not used since all tokens are lexed before parsing starts
+       OnyxToken *prev_token;
+       OnyxToken *curr_token;
+
+       // BUG: This way of handling identifiers will work for now,
+       // but it will not allow for shadowing. Also, variable names
+       // cannot be the same as any function or global variable.
+       // That will get annoying to program.
+       // NOTE: A table of the current identifiers in the current scope.
+       // If the identifier doesn't at the time of parsing, it is an error.
+       // Cleared at the end of a block.
+       bh_hash(OnyxAstNode*) identifiers;
+       OnyxAstNodeScope *curr_scope;
+
+       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_LOCAL,
+
+       ONYX_AST_NODE_KIND_ADD,
+       ONYX_AST_NODE_KIND_MINUS,
+       ONYX_AST_NODE_KIND_MULTIPLY,
+       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_ASSIGNMENT,
+       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[];
+
+// NOTE: Some of these flags will overlap since there are
+// only 32-bits of flags to play with
+typedef enum OnyxAstFlags {
+       // Top-level flags
+       ONYX_AST_FLAG_EXPORTED   = BH_BIT(1),
+} OnyxAstFlags;
+
+struct OnyxAstNodeLocal {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;
+       OnyxTypeInfo *type;
+       OnyxAstNodeLocal *prev_local;
+       OnyxAstNode *shadowed;
+       OnyxAstNode *unused2;
+};
+
+struct OnyxAstNodeScope {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;       // NOTE: UNUSED
+       OnyxTypeInfo *type; // NOTE: UNUSED
+       OnyxAstNodeScope *prev_scope;
+       OnyxAstNodeLocal *last_local;
+       OnyxAstNode *unused;
+};
+
+struct OnyxAstNodeBlock {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;
+       OnyxTypeInfo *return_type;
+       OnyxAstNode *next;
+       OnyxAstNode *body;
+       OnyxAstNodeScope *scope; // NOTE: Only set on blocks belonging to functions
+};
+
+struct OnyxAstNodeParam {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;                       // Symbol name i.e. 'a', 'b'
+       OnyxTypeInfo *type;
+       OnyxAstNodeParam *next;
+       u64 param_count;
+       OnyxAstNode *right;
+};
+
+struct OnyxAstNodeFuncDef {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token; // This will point to the symbol token to identify it
+       OnyxTypeInfo *return_type;
+       OnyxAstNode *next;
+       OnyxAstNodeBlock *body;
+       OnyxAstNodeParam *params;
+};
+
+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;
+       OnyxAstNodeLocal as_local;
+       OnyxAstNodeScope as_scope;
+};
+
+const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);
+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
index 74b96e6ba05e77006ef74ff8814fedbd6830cd8d..02d191f59189e4ed556416fedabfd66542e99cf4 100644 (file)
@@ -1,26 +1,27 @@
-#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
+#include "onyxutils.h"
+
+void onyx_ast_print(OnyxAstNode* node) {
+       if (node == NULL) return;
+
+       bh_printf("%s <%d> ", onyx_ast_node_kind_string(node->kind), node->flags);
+       if (node->token)
+               bh_printf("[%b] ", node->token->token, (int) node->token->length);
+
+       if ((i64) node->left > 10) { // HACK: but okay
+               bh_printf("(");
+               onyx_ast_print(node->left);
+               bh_printf(") ");
+       }
+       if ((i64) node->right > 10) { // HACK: but okay
+               bh_printf("(");
+               onyx_ast_print(node->right);
+               bh_printf(")");
+       }
+
+       if (node->next) {
+               bh_printf("{");
+               onyx_ast_print(node->next);
+               bh_printf("}");
+       }
+
+}
index a8e2e3a57e942d4c9eb0174ae4bedd66d70d1084..4da320b561560d2ba8955b6dd09d685396108042 100644 (file)
@@ -1,5 +1,5 @@
-#include "bh.h"\r
-\r
-#include "onyxparser.h"\r
-\r
-void onyx_ast_print(OnyxAstNode* program);\r
+#include "bh.h"
+
+#include "onyxparser.h"
+
+void onyx_ast_print(OnyxAstNode* program);
index 81dc7c8c23149b87138399d23e0528c0dda3c930..d4f55aca369b666df37b161cd4c8f124c0aee8cf 100644 (file)
@@ -1,14 +1,16 @@
-/* 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
+/* This is a comment */
+
+log :: proc (a i32, b i32) -> i32 ---;
+
+export add :: proc (a i32, b i32) -> i32 {
+       /* More comments */
+       return a + b;
+};
+
+export mul :: proc (a i32, b i32) -> i32 {
+       c: i32 = a - b;
+       d := a + 2;
+
+       e: i32;
+       return c * d;
+};