#include <stdio.h> // TODO: Replace with custom implementation of printf
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h> // TODO: Replace with needed functions
#include <assert.h>
#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);
//-------------------------------------------------------------------------------------
// 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))
+
//-------------------------------------------------------------------------------------
// Better strings
//-------------------------------------------------------------------------------------
typedef enum bh_file_error {
BH_FILE_ERROR_NONE,
- BH_FILE_ERROR_INVALID
+ BH_FILE_ERROR_INVALID,
+ BH_FILE_ERROR_BAD_FD,
} bh_file_error;
typedef enum bh_file_mode {
+//-------------------------------------------------------------------------------------
+// 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 %
+
+enum bh__print_format {
+ BH__PRINT_FORMAT_DECIMAL = BH_BIT(0),
+ BH__PRINT_FORMAT_OCTAL = BH_BIT(1),
+ BH__PRINT_FORMAT_HEXADECIMAL = BH_BIT(2),
+ BH__PRINT_FORMAT_UNSIGNED = BH_BIT(3),
+};
+
+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 dynamically-sized arrays
//-------------------------------------------------------------------------------------
sd_fd = STDERR_FILENO;
filename = "stderr";
break;
+ default:
+ return BH_FILE_ERROR_BAD_FD;
}
file->fd = sd_fd;
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// 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__printi64(char* str, isize n, enum bh__print_format format, i32 value) {
+ char buf[130];
+ buf[129] = 0;
+ char* walker = buf + 129;
+
+ while (value > 0) {
+ *--walker = '0' + (value % 10);
+ value /= 10;
+ }
+
+ return bh__print_string(str, n, walker);
+}
+
+
+isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va) {
+ char const *text_start = str;
+ isize res;
+
+ while (*fmt) {
+ i32 base = 10, size;
+ isize len = 0;
+
+ while (*fmt && *fmt != '%') {
+ *(str++) = *(fmt++);
+ len++;
+ }
+
+ fmt++;
+
+ switch (*fmt++) {
+ case 'o': base = 8; break;
+ case 'x': 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, 0, value);
+ } break;
+
+ default: fmt--;
+ }
+
+ fmt++;
+
+ str += len;
+ }
+
+ return str - text_start + 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
//-------------------------------------------------------------------------------------
// ARRAY IMPLEMENTATION
//-------------------------------------------------------------------------------------
struct OnyxTypeInfo builtin_types[] = {
{ ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" },
{ ONYX_TYPE_INFO_KIND_VOID, 0, "void" },
-
+
{ ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1 },
-
+
{ ONYX_TYPE_INFO_KIND_UINT8, 1, "u8", 1, 1, 0, 0 },
{ ONYX_TYPE_INFO_KIND_UINT16, 2, "u16", 1, 1, 0, 0 },
{ ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0 },
{ ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0 },
-
+
{ ONYX_TYPE_INFO_KIND_INT8, 1, "i8", 1, 0, 0, 0 },
{ ONYX_TYPE_INFO_KIND_INT16, 2, "i16", 1, 0, 0, 0 },
{ ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0 },
{ ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0 },
-
+
{ ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0 },
{ ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0 },
{ ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0 },
-
+
{ 0xffffffff } // Sentinel
};
static 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:
+ case TOKEN_TYPE_SYM_SEMICOLON:
+ case TOKEN_TYPE_CLOSE_BRACE:
+ case TOKEN_TYPE_OPEN_BRACE:
+ case TOKEN_TYPE_END_STREAM:
return 1;
- default:
+ default:
return 0;
}
}
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,
onyx_get_token_type_name(token_type), onyx_get_token_type_name(token->type));
return NULL;
}
-
+
return token;
}
+static OnyxAstNode* parse_factor(OnyxParser* parser) {
+ return &error_node;
+}
+
static OnyxAstNode* parse_expression(OnyxParser* parser) {
return &error_node;
}
}
static OnyxAstNode* parse_expression_statement(OnyxParser* parser) {
-
+
}
static OnyxAstNode* parse_return_statement(OnyxParser* parser) {
expect(parser, TOKEN_TYPE_KEYWORD_RETURN);
-
+
+ OnyxAstNode* return_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_RETURN);
+ return_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_VOID];
OnyxAstNode* expr = NULL;
-
+
parser_next_token(parser);
if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) {
expr = parse_expression(parser);
-
- if (expr == &error_node) {
+
+ if (expr == NULL || expr == &error_node) {
return &error_node;
}
}
+
+ return return_node;
}
static OnyxAstNodeBlock* parse_block(OnyxParser* parser);
static OnyxAstNode* parse_statement(OnyxParser* parser) {
switch (parser->curr_token->type) {
- case TOKEN_TYPE_KEYWORD_RETURN:
+ case TOKEN_TYPE_KEYWORD_RETURN:
return parse_return_statement(parser);
-
- case TOKEN_TYPE_OPEN_BRACE:
+
+ case TOKEN_TYPE_OPEN_BRACE:
return (OnyxAstNode *) parse_block(parser);
-
- case TOKEN_TYPE_SYMBOL:
- case TOKEN_TYPE_OPEN_PAREN:
- case TOKEN_TYPE_SYM_PLUS:
- case TOKEN_TYPE_SYM_MINUS:
- case TOKEN_TYPE_SYM_BANG:
- case TOKEN_TYPE_LITERAL_NUMERIC:
- case TOKEN_TYPE_LITERAL_STRING:
+
+ case TOKEN_TYPE_SYMBOL:
+ case TOKEN_TYPE_OPEN_PAREN:
+ case TOKEN_TYPE_SYM_PLUS:
+ case TOKEN_TYPE_SYM_MINUS:
+ case TOKEN_TYPE_SYM_BANG:
+ case TOKEN_TYPE_LITERAL_NUMERIC:
+ case TOKEN_TYPE_LITERAL_STRING:
return parse_expression_statement(parser);
-
- case TOKEN_TYPE_KEYWORD_IF:
+
+ case TOKEN_TYPE_KEYWORD_IF:
return parse_if_stmt(parser);
-
- case TOKEN_TYPE_SYM_SEMICOLON:
+
+ case TOKEN_TYPE_SYM_SEMICOLON:
return NULL;
-
- default:
+
+ default:
printf("ERROR\n");
parser_next_token(parser);
return NULL;
expect(parser, TOKEN_TYPE_SYM_MINUS);
return NULL;
}
-
+
expect(parser, TOKEN_TYPE_OPEN_BRACE);
-
+
OnyxAstNodeBlock* block = (OnyxAstNodeBlock *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BLOCK);
-
+
OnyxAstNode** next = &block->body;
OnyxAstNode* stmt = NULL;
while (parser->curr_token->type != TOKEN_TYPE_CLOSE_BRACE) {
stmt = parse_statement(parser);
-
+
if (stmt != NULL && stmt->kind != ONYX_AST_NODE_KIND_ERROR) {
*next = stmt;
next = &stmt->next;
}
-
+
expect(parser, TOKEN_TYPE_SYM_SEMICOLON);
}
-
+
return block;
}
static OnyxTypeInfo* parse_type(OnyxParser* parser) {
OnyxTypeInfo* type_info = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];
-
+
OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);
if (symbol == NULL) return type_info;
-
+
onyx_token_null_toggle(*symbol);
-
+
if (!bh_hash_has(OnyxAstNode*, parser->identifiers, symbol->token)) {
onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, symbol->pos, symbol->token);
} else {
OnyxAstNode* type_info_node = bh_hash_get(OnyxAstNode*, parser->identifiers, symbol->token);
-
+
if (type_info_node->kind == ONYX_AST_NODE_KIND_TYPE) {
type_info = type_info_node->type;
}
}
-
+
onyx_token_null_toggle(*symbol);
return type_info;
}
static OnyxAstNodeParam* parse_function_params(OnyxParser* parser) {
expect(parser, TOKEN_TYPE_OPEN_PAREN);
-
+
if (parser->curr_token->type == TOKEN_TYPE_CLOSE_PAREN) {
parser_next_token(parser);
return NULL;
}
-
+
OnyxAstNodeParam* first_param = NULL;
-
+
OnyxAstNodeParam* curr_param = NULL;
OnyxAstNodeParam* trailer = NULL;
-
+
OnyxToken* symbol;
while (parser->curr_token->type != TOKEN_TYPE_CLOSE_PAREN) {
if (parser->curr_token->type == TOKEN_TYPE_SYM_COMMA) parser_next_token(parser);
-
+
symbol = expect(parser, TOKEN_TYPE_SYMBOL);
-
+
curr_param = (OnyxAstNodeParam *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PARAM);
curr_param->token = symbol;
curr_param->type = parse_type(parser);
-
+
if (first_param == NULL) first_param = curr_param;
-
+
curr_param->next = NULL;
if (trailer) trailer->next = curr_param;
-
+
trailer = curr_param;
}
-
+
parser_next_token(parser); // Skip the )
return first_param;
}
static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) {
expect(parser, TOKEN_TYPE_KEYWORD_PROC);
-
+
OnyxAstNodeFuncDef* func_def = (OnyxAstNodeFuncDef *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_FUNCDEF);
func_def->param_count = 0;
-
+
OnyxAstNodeParam* params = parse_function_params(parser);
func_def->params = params;
-
+
for (OnyxAstNode* walker = (OnyxAstNode *) params; walker != NULL; walker = walker->next)
func_def->param_count++;
-
+
expect(parser, TOKEN_TYPE_RIGHT_ARROW);
-
+
OnyxTypeInfo* return_type = parse_type(parser);
func_def->return_type = return_type;
-
+
func_def->body = parse_block(parser);
return func_def;
}
-
static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) {
switch (parser->curr_token->type) {
- case TOKEN_TYPE_KEYWORD_USE:
+ case TOKEN_TYPE_KEYWORD_USE:
assert(0);
break;
-
- case TOKEN_TYPE_KEYWORD_EXPORT:
+
+ case TOKEN_TYPE_KEYWORD_EXPORT:
assert(0);
- break;
-
- case TOKEN_TYPE_SYMBOL: {
- OnyxToken* symbol = parser->curr_token;
- parser_next_token(parser);
-
- expect(parser, TOKEN_TYPE_SYM_COLON);
- expect(parser, TOKEN_TYPE_SYM_COLON);
-
- if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {
- OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);
- func_def->token = symbol;
- return (OnyxAstNode *) func_def;
-
- } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {
- // Handle struct case
- assert(0);
- } else {
- onyx_message_add(parser->msgs,
- ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(parser->curr_token->type));
- }
- } break;
+ break;
+
+ case TOKEN_TYPE_SYMBOL: {
+ OnyxToken* symbol = parser->curr_token;
+ parser_next_token(parser);
+
+ expect(parser, TOKEN_TYPE_SYM_COLON);
+ expect(parser, TOKEN_TYPE_SYM_COLON);
+
+ if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {
+ OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);
+ func_def->token = symbol;
+ return (OnyxAstNode *) func_def;
+
+ } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {
+ // Handle struct case
+ assert(0);
+ } else {
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
+ parser->curr_token->pos,
+ onyx_get_token_type_name(parser->curr_token->type));
+ }
+ } break;
}
-
+
parser_next_token(parser);
return NULL;
}
OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\
OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode));
node->kind = kind;
-
+
return node;
}
OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) {
OnyxParser parser;
-
+
bh_hash_init(bh_heap_allocator(), parser.identifiers);
-
+
OnyxTypeInfo* it = &builtin_types[0];
while (it->kind != 0xffffffff) {
OnyxAstNode* tmp = onyx_ast_node_new(alloc, ONYX_AST_NODE_KIND_TYPE);
bh_hash_put(OnyxAstNode*, parser.identifiers, (char *)it->name, tmp);
it++;
}
-
+
parser.allocator = alloc;
parser.tokenizer = tokenizer;
parser.curr_token = tokenizer->tokens;
parser.prev_token = NULL;
parser.msgs = msgs;
-
+
return parser;
}
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;
}