Cleaning up directory structure
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Jun 2020 02:22:51 +0000 (21:22 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Jun 2020 02:22:51 +0000 (21:22 -0500)
22 files changed:
Makefile
bh.h [deleted file]
include/bh.h [new file with mode: 0644]
include/onyxlex.h [new file with mode: 0644]
include/onyxmsgs.h [new file with mode: 0644]
include/onyxparser.h [new file with mode: 0644]
include/onyxutils.h [new file with mode: 0644]
onyx
onyx.c [deleted file]
onyxlex.c [deleted file]
onyxlex.h [deleted file]
onyxmsgs.c [deleted file]
onyxmsgs.h [deleted file]
onyxparser.c [deleted file]
onyxparser.h [deleted file]
onyxutils.c [deleted file]
onyxutils.h [deleted file]
src/onyx.c [new file with mode: 0644]
src/onyxlex.c [new file with mode: 0644]
src/onyxmsgs.c [new file with mode: 0644]
src/onyxparser.c [new file with mode: 0644]
src/onyxutils.c [new file with mode: 0644]

index 156ee28138533fea33f93d9da8d773a315bc9c8a..e3213a833968f042fe98baf785fdd6bd3b056f43 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,16 @@
 OBJ_FILES=\
-       onyxlex.o \
-       onyxparser.o \
-       onyxmsgs.o \
-       onyxutils.o \
-       onyx.o
+       src/onyxlex.o \
+       src/onyxparser.o \
+       src/onyxmsgs.o \
+       src/onyxutils.o \
+       src/onyx.o
 
 CC=gcc
-INCLUDES=
+INCLUDES=-I./include
 LIBS=
 FLAGS=-g
 
-%.o: %.c bh.h
+%.o: %.c include/bh.h
        $(CC) $(FLAGS) -c $< -o $@ $(INCLUDES)
 
 onyx: $(OBJ_FILES)
diff --git a/bh.h b/bh.h
deleted file mode 100644 (file)
index 95772a7..0000000
--- a/bh.h
+++ /dev/null
@@ -1,1753 +0,0 @@
-#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
diff --git a/include/bh.h b/include/bh.h
new file mode 100644 (file)
index 0000000..95772a7
--- /dev/null
@@ -0,0 +1,1753 @@
+#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
diff --git a/include/onyxlex.h b/include/onyxlex.h
new file mode 100644 (file)
index 0000000..b1b5eb0
--- /dev/null
@@ -0,0 +1,91 @@
+#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_CONST,
+       TOKEN_TYPE_KEYWORD_FOREIGN,
+       TOKEN_TYPE_KEYWORD_PROC,
+       TOKEN_TYPE_KEYWORD_GLOBAL,
+       TOKEN_TYPE_KEYWORD_CAST,
+
+       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
diff --git a/include/onyxmsgs.h b/include/onyxmsgs.h
new file mode 100644 (file)
index 0000000..6c6a19e
--- /dev/null
@@ -0,0 +1,43 @@
+#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_NOT_LVAL,
+       ONYX_MESSAGE_TYPE_ASSIGN_CONST,
+       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+       ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
+       ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
+       ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
+
+       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);
+b32 onyx_message_has_errors(OnyxMessages* msgs);
+void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs);
+
+#endif
diff --git a/include/onyxparser.h b/include/onyxparser.h
new file mode 100644 (file)
index 0000000..b2496f6
--- /dev/null
@@ -0,0 +1,195 @@
+#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;
+       u32 is_known : 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(0),
+       ONYX_AST_FLAG_LVAL                      = BH_BIT(1),
+       ONYX_AST_FLAG_CONST                     = BH_BIT(2),
+       ONYX_AST_FLAG_COMPTIME          = BH_BIT(3),
+} OnyxAstFlags;
+
+struct OnyxAstNodeLocal {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;
+       OnyxTypeInfo *type;
+       OnyxAstNodeLocal *prev_local;
+       OnyxAstNode *shadowed;
+       OnyxAstNode *unused;
+};
+
+// NOTE: Needs to have shadowed in the same position as OnyxAstNodeLocal
+struct OnyxAstNodeParam {
+       OnyxAstNodeKind kind;
+       u32 flags;
+       OnyxToken *token;                       // Symbol name i.e. 'a', 'b'
+       OnyxTypeInfo *type;
+       OnyxAstNodeParam *next;
+       OnyxAstNode *shadowed;
+       u64 param_count;
+};
+
+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 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
diff --git a/include/onyxutils.h b/include/onyxutils.h
new file mode 100644 (file)
index 0000000..63b6f60
--- /dev/null
@@ -0,0 +1,5 @@
+#include "bh.h"
+
+#include "onyxparser.h"
+
+void onyx_ast_print(OnyxAstNode* program, i32 indent);
diff --git a/onyx b/onyx
index 37a1774ae70719ac06b4010caf3f5d73c76dd987..a16d7ae6f49c8a3d2cccc93c21a93ef230808e5d 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/onyx.c b/onyx.c
deleted file mode 100644 (file)
index ceb0970..0000000
--- a/onyx.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#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;
-
-#if 0
-       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);
-       }
-#endif
-
-       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);
-
-       // NOTE: if there are errors, assume the parse tree was generated wrong,
-       // even if it may have still been generated correctly.
-       if (onyx_message_has_errors(&msgs)) {
-               onyx_message_print(&msgs);
-               goto main_exit;
-       } else {
-               onyx_ast_print(program, 0);
-               bh_printf("\nNo errors.\n");
-       }
-
-
-main_exit: // NOTE: Cleanup, since C doesn't have defer
-       bh_arena_free(&msg_arena);
-       bh_arena_free(&ast_arena);
-       onyx_parser_free(&parser);
-       onyx_tokenizer_free(&tokenizer);
-       bh_file_contents_delete(&fc);
-
-       return 0;
-}
diff --git a/onyxlex.c b/onyxlex.c
deleted file mode 100644 (file)
index d76c93f..0000000
--- a/onyxlex.c
+++ /dev/null
@@ -1,279 +0,0 @@
-#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",
-       "const",                //"TOKEN_TYPE_KEYWORD_CONST",
-       "foreign",              //"TOKEN_TYPE_KEYWORD_FOREIGN",
-       "proc",                 //"TOKEN_TYPE_KEYWORD_PROC",
-       "global",               //"TOKEN_TYPE_KEYWORD_GLOBAL",
-       "as",                   //"TOKEN_TYPE_KEYWORD_CAST",
-
-       "->", //"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("const", TOKEN_TYPE_KEYWORD_CONST);
-       LITERAL_TOKEN("do", TOKEN_TYPE_KEYWORD_DO);
-       LITERAL_TOKEN("proc", TOKEN_TYPE_KEYWORD_PROC);
-       LITERAL_TOKEN("global", TOKEN_TYPE_KEYWORD_GLOBAL);
-       LITERAL_TOKEN("as", TOKEN_TYPE_KEYWORD_CAST);
-       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)) {
-               u32 len = 1;
-               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);
-}
diff --git a/onyxlex.h b/onyxlex.h
deleted file mode 100644 (file)
index b1b5eb0..0000000
--- a/onyxlex.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#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_CONST,
-       TOKEN_TYPE_KEYWORD_FOREIGN,
-       TOKEN_TYPE_KEYWORD_PROC,
-       TOKEN_TYPE_KEYWORD_GLOBAL,
-       TOKEN_TYPE_KEYWORD_CAST,
-
-       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
diff --git a/onyxmsgs.c b/onyxmsgs.c
deleted file mode 100644 (file)
index a2e5551..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#include "onyxmsgs.h"
-
-static const char* msg_formats[] = {
-       "expected token '%s', got '%s'",
-       "unexpected token '%s'",
-       "unknown type '%s'",
-       "expected lval '%s'",
-       "attempt to assign to constant '%s'",
-       "unknown symbol '%s'",
-       "redefinition of function '%s'",
-       "mismatched types for binary operator, '%s', '%s'",
-       "mismatched types on assignment, '%s', '%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;
-       }
-}
-
-b32 onyx_message_has_errors(OnyxMessages* msgs) {
-       return msgs->first != NULL;
-}
-
-void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs) {
-       msgs->allocator = allocator;
-       msgs->first = NULL;
-}
diff --git a/onyxmsgs.h b/onyxmsgs.h
deleted file mode 100644 (file)
index 6c6a19e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#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_NOT_LVAL,
-       ONYX_MESSAGE_TYPE_ASSIGN_CONST,
-       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-       ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
-       ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
-       ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
-
-       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);
-b32 onyx_message_has_errors(OnyxMessages* msgs);
-void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs);
-
-#endif
diff --git a/onyxparser.c b/onyxparser.c
deleted file mode 100644 (file)
index 103d8e3..0000000
+++ /dev/null
@@ -1,737 +0,0 @@
-
-#include "onyxlex.h"
-#include "onyxmsgs.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", 0, 0, 0, 0, 1 },
-
-       { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1, 1 },
-
-       { ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0, 1 },
-       { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0, 1 },
-
-       { ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0, 1 },
-       { ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0, 1 },
-
-       { ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0, 1 },
-       { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0, 1},
-       { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0, 1 },
-
-       { 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, OnyxAstNode* ident, b32 is_local);
-static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident);
-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_symbol_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;
-       }
-}
-
-static void find_token(OnyxParser* parser, OnyxTokenType token_type) {
-       while (parser->curr_token->type != token_type && !is_terminating_token(parser->curr_token->type)) {
-               parser_next_token(parser);
-       }
-}
-
-// 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) {
-               remove_identifier(parser, (OnyxAstNode *) walker);
-       }
-
-       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, OnyxAstNode* ident, b32 is_local) {
-       OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident;
-       if (is_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(OnyxAstNode*, 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 void remove_identifier(OnyxParser* parser, OnyxAstNode* ident) {
-       OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident;
-
-       onyx_token_null_toggle(*local->token);
-       if (local->shadowed) {
-               bh_hash_put(OnyxAstNode*, parser->identifiers, local->token->token, local->shadowed);
-       } else {
-               bh_hash_delete(OnyxAstNode*, parser->identifiers, local->token->token);
-       }
-       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);
-                               if (sym_node == NULL) {
-                                       onyx_token_null_toggle(*sym_token);
-                                       onyx_message_add(parser->msgs,
-                                                       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-                                                       sym_token->pos, sym_token->token);
-                                       onyx_token_null_toggle(*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);
-                               lit_node->flags |= ONYX_AST_FLAG_COMPTIME;
-                               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) {
-               OnyxToken* bin_op_tok = parser->curr_token;
-               parser_next_token(parser);
-
-               OnyxAstNode* right = parse_factor(parser);
-
-               // NOTE: Typechecking like this will not be here for long but
-               // want to start working on it early
-               if (left->type != right->type) {
-                       onyx_message_add(parser->msgs,
-                               ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
-                               bin_op_tok->pos,
-                               left->type->name, right->type->name);
-                       return &error_node;
-               }
-
-               OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind);
-               bin_op->left = left;
-               bin_op->right = right;
-               bin_op->type = left->type;
-               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;
-                       }
-               case TOKEN_TYPE_KEYWORD_CAST:
-                       {
-                               parser_next_token(parser);
-                               OnyxTypeInfo* type = parse_type(parser);
-
-                               // NOTE: This may be premature in the parser but a cast
-                               // node doesn't need to exist if the source and target
-                               // types are the same
-                               if (type == left->type) return left;
-
-                               OnyxAstNode* cast_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CAST);
-                               cast_node->type = type;
-                               cast_node->left = left;
-
-                               return cast_node;
-                       }
-       }
-
-       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_symbol_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];
-                               u32 flags = ONYX_AST_FLAG_LVAL;
-
-                               // NOTE: var: const ...
-                               if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_CONST) {
-                                       parser_next_token(parser);
-                                       flags |= ONYX_AST_FLAG_CONST;
-                               }
-
-                               // 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;
-                               local->flags |= flags;
-
-                               insert_identifier(parser, (OnyxAstNode *) local, 1);
-
-                               if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) {
-                                       OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
-                                       assignment->token = parser->curr_token;
-                                       parser_next_token(parser);
-
-                                       OnyxAstNode* expr = parse_expression(parser);
-                                       assignment->right = expr;
-                                       assignment->left = (OnyxAstNode*) local;
-
-                                       if (local->type->is_known && local->type != expr->type) {
-                                               onyx_message_add(parser->msgs,
-                                                               ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
-                                                               assignment->token->pos,
-                                                               local->type->name, expr->type->name);
-                                               return 1;
-                                       } else if (!local->type->is_known) {
-                                               local->type = expr->type;
-                                       }
-                                       *ret = assignment;
-                               }
-                               return 1;
-                       }
-
-                       // NOTE: Assignment
-               case TOKEN_TYPE_SYM_EQUALS:
-                       {
-                               parser_next_token(parser);
-
-                               OnyxAstNode* lval = lookup_identifier(parser, symbol);
-
-                               if (lval != NULL && lval->flags & ONYX_AST_FLAG_LVAL && (lval->flags & ONYX_AST_FLAG_CONST) == 0) {
-                                       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;
-                               }
-
-                               onyx_token_null_toggle(*symbol);
-                               if (lval == NULL) {
-                                       onyx_message_add(parser->msgs,
-                                                       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-                                                       symbol->pos, symbol->token);
-                               }
-
-                               else if ((lval->flags & ONYX_AST_FLAG_LVAL) == 0) {
-                                       onyx_message_add(parser->msgs,
-                                                       ONYX_MESSAGE_TYPE_NOT_LVAL,
-                                                       symbol->pos, symbol->token);
-                               }
-
-                               else if (lval->flags & ONYX_AST_FLAG_CONST) {
-                                       onyx_message_add(parser->msgs,
-                                                       ONYX_MESSAGE_TYPE_ASSIGN_CONST,
-                                                       symbol->pos, symbol->token);
-                               }
-                               onyx_token_null_toggle(*symbol);
-
-                               find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
-                               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_symbol_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));
-
-                       find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
-               }
-               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;
-
-       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
-               insert_identifier(parser, (OnyxAstNode *) p, 0);
-       }
-
-       func_def->body = parse_block(parser, 1);
-
-       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
-               remove_identifier(parser, (OnyxAstNode *) p);
-       }
-
-       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;
-                       }
-
-               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;
-
-                                       onyx_token_null_toggle(*symbol);
-
-                                       if (!bh_hash_has(OnyxAstNode *, parser->identifiers, symbol->token)) {
-                                               bh_hash_put(OnyxAstNode *, parser->identifiers, symbol->token, (OnyxAstNode *) func_def);
-                                       } else {
-                                               onyx_message_add(parser->msgs,
-                                                               ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
-                                                               symbol->pos,
-                                                               symbol->token);
-
-                                               // NOTE: I really wish C had defer...
-                                               onyx_token_null_toggle(*symbol);
-                                               return NULL;
-                                       }
-
-                                       onyx_token_null_toggle(*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;
-}
diff --git a/onyxparser.h b/onyxparser.h
deleted file mode 100644 (file)
index b2496f6..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-#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;
-       u32 is_known : 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(0),
-       ONYX_AST_FLAG_LVAL                      = BH_BIT(1),
-       ONYX_AST_FLAG_CONST                     = BH_BIT(2),
-       ONYX_AST_FLAG_COMPTIME          = BH_BIT(3),
-} OnyxAstFlags;
-
-struct OnyxAstNodeLocal {
-       OnyxAstNodeKind kind;
-       u32 flags;
-       OnyxToken *token;
-       OnyxTypeInfo *type;
-       OnyxAstNodeLocal *prev_local;
-       OnyxAstNode *shadowed;
-       OnyxAstNode *unused;
-};
-
-// NOTE: Needs to have shadowed in the same position as OnyxAstNodeLocal
-struct OnyxAstNodeParam {
-       OnyxAstNodeKind kind;
-       u32 flags;
-       OnyxToken *token;                       // Symbol name i.e. 'a', 'b'
-       OnyxTypeInfo *type;
-       OnyxAstNodeParam *next;
-       OnyxAstNode *shadowed;
-       u64 param_count;
-};
-
-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 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
diff --git a/onyxutils.c b/onyxutils.c
deleted file mode 100644 (file)
index e40e0cb..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#include "onyxutils.h"
-#include "onyxlex.h"
-#include "onyxparser.h"
-
-#define print_indent { if (indent > 0) bh_printf("\n"); for (int i = 0; i < indent; i++) bh_printf("  "); }
-
-void onyx_ast_print(OnyxAstNode* node, i32 indent) {
-       if (node == NULL) return;
-
-       print_indent;
-       bh_printf("(%d) %s ", node->flags, onyx_ast_node_kind_string(node->kind));
-
-       switch (node->kind) {
-       case ONYX_AST_NODE_KIND_PROGRAM: {
-               if (node->next)
-                       onyx_ast_print(node->next, indent + 1);
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_FUNCDEF: {
-               bh_printf("(%b) ", node->token->token, node->token->length);
-               OnyxAstNodeFuncDef* fd = &node->as_funcdef;
-
-               print_indent;
-               bh_printf("Params ");
-               if (fd->params)
-                       onyx_ast_print((OnyxAstNode *) fd->params, 0);
-
-               print_indent;
-               bh_printf("Returns %s", fd->return_type->name);
-
-               print_indent;
-               bh_printf("Body");
-               if (fd->body)
-                       onyx_ast_print((OnyxAstNode *) fd->body, indent + 1);
-
-               if (fd->next)
-                       onyx_ast_print((OnyxAstNode *) fd->next, indent);
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_PARAM: {
-               OnyxAstNodeParam* param = &node->as_param;
-               bh_printf("%b %s", param->token->token, param->token->length, param->type->name);
-               if (param->next && indent == 0) {
-                       bh_printf(", ");
-                       onyx_ast_print((OnyxAstNode *) param->next, 0);
-               }
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_BLOCK: {
-               OnyxAstNodeBlock* block = &node->as_block;
-               if (block->scope) {
-                       onyx_ast_print((OnyxAstNode *) block->scope, indent + 1);
-               }
-
-               if (block->body) {
-                       onyx_ast_print((OnyxAstNode *) block->body, indent + 1);
-               }
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_SCOPE: {
-               OnyxAstNodeScope* scope = &node->as_scope;
-               if (scope->last_local) {
-                       onyx_ast_print((OnyxAstNode *) scope->last_local, 0);
-               }
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_LOCAL: {
-               OnyxAstNodeLocal* local = &node->as_local;
-               bh_printf("%b %s", local->token->token, local->token->length, local->type->name);
-               if (local->prev_local && indent == 0) {
-                       bh_printf(", ");
-                       onyx_ast_print((OnyxAstNode *) local->prev_local, 0);
-               }
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_RETURN: {
-               if (node->next) {
-                       onyx_ast_print(node->next, indent + 1);
-               }
-
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_LITERAL: {
-               bh_printf("%b", node->token->token, node->token->length);
-               break;
-       }
-
-       case ONYX_AST_NODE_KIND_CAST: {
-               bh_printf("to %s ", node->type->name);
-               onyx_ast_print(node->left, indent + 1);
-               if (node->next) {
-                       onyx_ast_print(node->next, indent);
-               }
-               break;
-       }
-
-       default: {
-               onyx_ast_print(node->left, indent + 1);
-               onyx_ast_print(node->right, indent + 1);
-               if (node->next) {
-                       onyx_ast_print(node->next, indent);
-               }
-               break;
-       }
-       }
-}
diff --git a/onyxutils.h b/onyxutils.h
deleted file mode 100644 (file)
index 63b6f60..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "bh.h"
-
-#include "onyxparser.h"
-
-void onyx_ast_print(OnyxAstNode* program, i32 indent);
diff --git a/src/onyx.c b/src/onyx.c
new file mode 100644 (file)
index 0000000..ceb0970
--- /dev/null
@@ -0,0 +1,71 @@
+#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;
+
+#if 0
+       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);
+       }
+#endif
+
+       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);
+
+       // NOTE: if there are errors, assume the parse tree was generated wrong,
+       // even if it may have still been generated correctly.
+       if (onyx_message_has_errors(&msgs)) {
+               onyx_message_print(&msgs);
+               goto main_exit;
+       } else {
+               onyx_ast_print(program, 0);
+               bh_printf("\nNo errors.\n");
+       }
+
+
+main_exit: // NOTE: Cleanup, since C doesn't have defer
+       bh_arena_free(&msg_arena);
+       bh_arena_free(&ast_arena);
+       onyx_parser_free(&parser);
+       onyx_tokenizer_free(&tokenizer);
+       bh_file_contents_delete(&fc);
+
+       return 0;
+}
diff --git a/src/onyxlex.c b/src/onyxlex.c
new file mode 100644 (file)
index 0000000..d76c93f
--- /dev/null
@@ -0,0 +1,279 @@
+#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",
+       "const",                //"TOKEN_TYPE_KEYWORD_CONST",
+       "foreign",              //"TOKEN_TYPE_KEYWORD_FOREIGN",
+       "proc",                 //"TOKEN_TYPE_KEYWORD_PROC",
+       "global",               //"TOKEN_TYPE_KEYWORD_GLOBAL",
+       "as",                   //"TOKEN_TYPE_KEYWORD_CAST",
+
+       "->", //"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("const", TOKEN_TYPE_KEYWORD_CONST);
+       LITERAL_TOKEN("do", TOKEN_TYPE_KEYWORD_DO);
+       LITERAL_TOKEN("proc", TOKEN_TYPE_KEYWORD_PROC);
+       LITERAL_TOKEN("global", TOKEN_TYPE_KEYWORD_GLOBAL);
+       LITERAL_TOKEN("as", TOKEN_TYPE_KEYWORD_CAST);
+       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)) {
+               u32 len = 1;
+               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);
+}
diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c
new file mode 100644 (file)
index 0000000..a2e5551
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include "onyxmsgs.h"
+
+static const char* msg_formats[] = {
+       "expected token '%s', got '%s'",
+       "unexpected token '%s'",
+       "unknown type '%s'",
+       "expected lval '%s'",
+       "attempt to assign to constant '%s'",
+       "unknown symbol '%s'",
+       "redefinition of function '%s'",
+       "mismatched types for binary operator, '%s', '%s'",
+       "mismatched types on assignment, '%s', '%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;
+       }
+}
+
+b32 onyx_message_has_errors(OnyxMessages* msgs) {
+       return msgs->first != NULL;
+}
+
+void onyx_message_create(bh_allocator allocator, OnyxMessages* msgs) {
+       msgs->allocator = allocator;
+       msgs->first = NULL;
+}
diff --git a/src/onyxparser.c b/src/onyxparser.c
new file mode 100644 (file)
index 0000000..103d8e3
--- /dev/null
@@ -0,0 +1,737 @@
+
+#include "onyxlex.h"
+#include "onyxmsgs.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", 0, 0, 0, 0, 1 },
+
+       { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1, 1 },
+
+       { ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0, 1 },
+       { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0, 1 },
+
+       { ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0, 1 },
+       { ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0, 1 },
+
+       { ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0, 1 },
+       { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0, 1},
+       { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0, 1 },
+
+       { 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, OnyxAstNode* ident, b32 is_local);
+static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident);
+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_symbol_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;
+       }
+}
+
+static void find_token(OnyxParser* parser, OnyxTokenType token_type) {
+       while (parser->curr_token->type != token_type && !is_terminating_token(parser->curr_token->type)) {
+               parser_next_token(parser);
+       }
+}
+
+// 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) {
+               remove_identifier(parser, (OnyxAstNode *) walker);
+       }
+
+       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, OnyxAstNode* ident, b32 is_local) {
+       OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident;
+       if (is_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(OnyxAstNode*, 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 void remove_identifier(OnyxParser* parser, OnyxAstNode* ident) {
+       OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident;
+
+       onyx_token_null_toggle(*local->token);
+       if (local->shadowed) {
+               bh_hash_put(OnyxAstNode*, parser->identifiers, local->token->token, local->shadowed);
+       } else {
+               bh_hash_delete(OnyxAstNode*, parser->identifiers, local->token->token);
+       }
+       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);
+                               if (sym_node == NULL) {
+                                       onyx_token_null_toggle(*sym_token);
+                                       onyx_message_add(parser->msgs,
+                                                       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+                                                       sym_token->pos, sym_token->token);
+                                       onyx_token_null_toggle(*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);
+                               lit_node->flags |= ONYX_AST_FLAG_COMPTIME;
+                               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) {
+               OnyxToken* bin_op_tok = parser->curr_token;
+               parser_next_token(parser);
+
+               OnyxAstNode* right = parse_factor(parser);
+
+               // NOTE: Typechecking like this will not be here for long but
+               // want to start working on it early
+               if (left->type != right->type) {
+                       onyx_message_add(parser->msgs,
+                               ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
+                               bin_op_tok->pos,
+                               left->type->name, right->type->name);
+                       return &error_node;
+               }
+
+               OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind);
+               bin_op->left = left;
+               bin_op->right = right;
+               bin_op->type = left->type;
+               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;
+                       }
+               case TOKEN_TYPE_KEYWORD_CAST:
+                       {
+                               parser_next_token(parser);
+                               OnyxTypeInfo* type = parse_type(parser);
+
+                               // NOTE: This may be premature in the parser but a cast
+                               // node doesn't need to exist if the source and target
+                               // types are the same
+                               if (type == left->type) return left;
+
+                               OnyxAstNode* cast_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CAST);
+                               cast_node->type = type;
+                               cast_node->left = left;
+
+                               return cast_node;
+                       }
+       }
+
+       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_symbol_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];
+                               u32 flags = ONYX_AST_FLAG_LVAL;
+
+                               // NOTE: var: const ...
+                               if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_CONST) {
+                                       parser_next_token(parser);
+                                       flags |= ONYX_AST_FLAG_CONST;
+                               }
+
+                               // 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;
+                               local->flags |= flags;
+
+                               insert_identifier(parser, (OnyxAstNode *) local, 1);
+
+                               if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) {
+                                       OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
+                                       assignment->token = parser->curr_token;
+                                       parser_next_token(parser);
+
+                                       OnyxAstNode* expr = parse_expression(parser);
+                                       assignment->right = expr;
+                                       assignment->left = (OnyxAstNode*) local;
+
+                                       if (local->type->is_known && local->type != expr->type) {
+                                               onyx_message_add(parser->msgs,
+                                                               ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
+                                                               assignment->token->pos,
+                                                               local->type->name, expr->type->name);
+                                               return 1;
+                                       } else if (!local->type->is_known) {
+                                               local->type = expr->type;
+                                       }
+                                       *ret = assignment;
+                               }
+                               return 1;
+                       }
+
+                       // NOTE: Assignment
+               case TOKEN_TYPE_SYM_EQUALS:
+                       {
+                               parser_next_token(parser);
+
+                               OnyxAstNode* lval = lookup_identifier(parser, symbol);
+
+                               if (lval != NULL && lval->flags & ONYX_AST_FLAG_LVAL && (lval->flags & ONYX_AST_FLAG_CONST) == 0) {
+                                       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;
+                               }
+
+                               onyx_token_null_toggle(*symbol);
+                               if (lval == NULL) {
+                                       onyx_message_add(parser->msgs,
+                                                       ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+                                                       symbol->pos, symbol->token);
+                               }
+
+                               else if ((lval->flags & ONYX_AST_FLAG_LVAL) == 0) {
+                                       onyx_message_add(parser->msgs,
+                                                       ONYX_MESSAGE_TYPE_NOT_LVAL,
+                                                       symbol->pos, symbol->token);
+                               }
+
+                               else if (lval->flags & ONYX_AST_FLAG_CONST) {
+                                       onyx_message_add(parser->msgs,
+                                                       ONYX_MESSAGE_TYPE_ASSIGN_CONST,
+                                                       symbol->pos, symbol->token);
+                               }
+                               onyx_token_null_toggle(*symbol);
+
+                               find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
+                               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_symbol_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));
+
+                       find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
+               }
+               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;
+
+       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
+               insert_identifier(parser, (OnyxAstNode *) p, 0);
+       }
+
+       func_def->body = parse_block(parser, 1);
+
+       for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
+               remove_identifier(parser, (OnyxAstNode *) p);
+       }
+
+       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;
+                       }
+
+               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;
+
+                                       onyx_token_null_toggle(*symbol);
+
+                                       if (!bh_hash_has(OnyxAstNode *, parser->identifiers, symbol->token)) {
+                                               bh_hash_put(OnyxAstNode *, parser->identifiers, symbol->token, (OnyxAstNode *) func_def);
+                                       } else {
+                                               onyx_message_add(parser->msgs,
+                                                               ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
+                                                               symbol->pos,
+                                                               symbol->token);
+
+                                               // NOTE: I really wish C had defer...
+                                               onyx_token_null_toggle(*symbol);
+                                               return NULL;
+                                       }
+
+                                       onyx_token_null_toggle(*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;
+}
diff --git a/src/onyxutils.c b/src/onyxutils.c
new file mode 100644 (file)
index 0000000..e40e0cb
--- /dev/null
@@ -0,0 +1,118 @@
+#include "onyxutils.h"
+#include "onyxlex.h"
+#include "onyxparser.h"
+
+#define print_indent { if (indent > 0) bh_printf("\n"); for (int i = 0; i < indent; i++) bh_printf("  "); }
+
+void onyx_ast_print(OnyxAstNode* node, i32 indent) {
+       if (node == NULL) return;
+
+       print_indent;
+       bh_printf("(%d) %s ", node->flags, onyx_ast_node_kind_string(node->kind));
+
+       switch (node->kind) {
+       case ONYX_AST_NODE_KIND_PROGRAM: {
+               if (node->next)
+                       onyx_ast_print(node->next, indent + 1);
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_FUNCDEF: {
+               bh_printf("(%b) ", node->token->token, node->token->length);
+               OnyxAstNodeFuncDef* fd = &node->as_funcdef;
+
+               print_indent;
+               bh_printf("Params ");
+               if (fd->params)
+                       onyx_ast_print((OnyxAstNode *) fd->params, 0);
+
+               print_indent;
+               bh_printf("Returns %s", fd->return_type->name);
+
+               print_indent;
+               bh_printf("Body");
+               if (fd->body)
+                       onyx_ast_print((OnyxAstNode *) fd->body, indent + 1);
+
+               if (fd->next)
+                       onyx_ast_print((OnyxAstNode *) fd->next, indent);
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_PARAM: {
+               OnyxAstNodeParam* param = &node->as_param;
+               bh_printf("%b %s", param->token->token, param->token->length, param->type->name);
+               if (param->next && indent == 0) {
+                       bh_printf(", ");
+                       onyx_ast_print((OnyxAstNode *) param->next, 0);
+               }
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_BLOCK: {
+               OnyxAstNodeBlock* block = &node->as_block;
+               if (block->scope) {
+                       onyx_ast_print((OnyxAstNode *) block->scope, indent + 1);
+               }
+
+               if (block->body) {
+                       onyx_ast_print((OnyxAstNode *) block->body, indent + 1);
+               }
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_SCOPE: {
+               OnyxAstNodeScope* scope = &node->as_scope;
+               if (scope->last_local) {
+                       onyx_ast_print((OnyxAstNode *) scope->last_local, 0);
+               }
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_LOCAL: {
+               OnyxAstNodeLocal* local = &node->as_local;
+               bh_printf("%b %s", local->token->token, local->token->length, local->type->name);
+               if (local->prev_local && indent == 0) {
+                       bh_printf(", ");
+                       onyx_ast_print((OnyxAstNode *) local->prev_local, 0);
+               }
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_RETURN: {
+               if (node->next) {
+                       onyx_ast_print(node->next, indent + 1);
+               }
+
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_LITERAL: {
+               bh_printf("%b", node->token->token, node->token->length);
+               break;
+       }
+
+       case ONYX_AST_NODE_KIND_CAST: {
+               bh_printf("to %s ", node->type->name);
+               onyx_ast_print(node->left, indent + 1);
+               if (node->next) {
+                       onyx_ast_print(node->next, indent);
+               }
+               break;
+       }
+
+       default: {
+               onyx_ast_print(node->left, indent + 1);
+               onyx_ast_print(node->right, indent + 1);
+               if (node->next) {
+                       onyx_ast_print(node->next, indent);
+               }
+               break;
+       }
+       }
+}