AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
// NOTE: Forward declarations
-static void parser_next_token(OnyxParser* parser);
-static void parser_prev_token(OnyxParser* parser);
+static void consume_token(OnyxParser* parser);
+static void unconsume_token(OnyxParser* parser);
static b32 is_terminating_token(TokenType token_type);
-static OnyxToken* expect(OnyxParser* parser, TokenType token_type);
+static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type);
static AstNumLit* parse_numeric_literal(OnyxParser* parser);
static AstTyped* parse_factor(OnyxParser* parser);
static AstType* parse_type(OnyxParser* parser);
static AstLocal* parse_function_params(OnyxParser* parser);
static AstFunction* parse_function_definition(OnyxParser* parser);
+static AstTyped* parse_global_declaration(OnyxParser* parser);
+static AstTyped* parse_top_level_expression(OnyxParser* parser);
static AstNode* 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 consume_token(OnyxParser* parser) {
+ parser->prev = parser->curr;
+ parser->curr++;
+ while (parser->curr->type == Token_Type_Comment) parser->curr++;
}
-static void parser_prev_token(OnyxParser* parser) {
+static void unconsume_token(OnyxParser* parser) {
// TODO: This is probably wrong
- while (parser->prev_token->type == Token_Type_Comment) parser->prev_token--;
- parser->curr_token = parser->prev_token;
- parser->prev_token--;
+ while (parser->prev->type == Token_Type_Comment) parser->prev--;
+ parser->curr = parser->prev;
+ parser->prev--;
}
static b32 is_terminating_token(TokenType token_type) {
}
static void find_token(OnyxParser* parser, TokenType token_type) {
- while (parser->curr_token->type != token_type && !is_terminating_token(parser->curr_token->type)) {
- parser_next_token(parser);
+ while (parser->curr->type != token_type && !is_terminating_token(parser->curr->type)) {
+ consume_token(parser);
}
}
// Advances to next token no matter what
-static OnyxToken* expect(OnyxParser* parser, TokenType token_type) {
- OnyxToken* token = parser->curr_token;
- parser_next_token(parser);
+static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type) {
+ OnyxToken* token = parser->curr;
+ consume_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));
+ token_name(token_type), token_name(token->type));
return NULL;
}
static AstNumLit* parse_numeric_literal(OnyxParser* parser) {
AstNumLit* lit_node = make_node(AstNumLit, Ast_Kind_Literal);
- lit_node->base.token = expect(parser, Token_Type_Literal_Numeric);
+ lit_node->base.token = expect_token(parser, Token_Type_Literal_Numeric);
lit_node->base.flags |= Ast_Flag_Comptime;
lit_node->value.l = 0ll;
AstType* type;
- onyx_token_null_toggle(lit_node->base.token);
+ token_toggle_end(lit_node->base.token);
char* tok = lit_node->base.token->text;
// NOTE: charset_contains() behaves more like string_contains()
}
lit_node->base.type_node = type;
- onyx_token_null_toggle(lit_node->base.token);
+ token_toggle_end(lit_node->base.token);
return lit_node;
}
+// ( <expr> )
+// - <factor>
+// ! <factor>
+// proc ...
+// <symbol> ( '(' <exprlist> ')' )?
+// <numlit>
+// 'true'
+// 'false'
+// All of these could be followed by a cast
static AstTyped* parse_factor(OnyxParser* parser) {
AstTyped* retval = NULL;
- switch ((u16) parser->curr_token->type) {
+ switch ((u16) parser->curr->type) {
case '(':
{
- parser_next_token(parser);
+ consume_token(parser);
AstTyped* expr = parse_expression(parser);
- expect(parser, ')');
+ expect_token(parser, ')');
retval = expr;
break;
}
case '-':
{
- parser_next_token(parser);
+ consume_token(parser);
AstTyped* factor = parse_factor(parser);
AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
{
AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
not_node->operation = Unary_Op_Not;
- not_node->base.token = expect(parser, '!');
+ not_node->base.token = expect_token(parser, '!');
not_node->expr = parse_factor(parser);
if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
case Token_Type_Symbol:
{
- OnyxToken* sym_token = expect(parser, Token_Type_Symbol);
+ OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
sym_node->token = sym_token;
- if (parser->curr_token->type != '(') {
+ if (parser->curr->type != '(') {
retval = sym_node;
break;
}
// NOTE: Function call
AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
- call_node->base.token = expect(parser, '(');
+ call_node->base.token = expect_token(parser, '(');
call_node->callee = (AstNode *) sym_node;
AstArgument** prev = &call_node->arguments;
AstArgument* curr = NULL;
- while (parser->curr_token->type != ')') {
+ while (parser->curr->type != ')') {
curr = make_node(AstArgument, Ast_Kind_Argument);
- curr->base.token = parser->curr_token;
+ curr->base.token = parser->curr;
curr->value = parse_expression(parser);
if (curr != NULL && curr->base.kind != Ast_Kind_Error) {
prev = (AstArgument **) &curr->base.next;
}
- if (parser->curr_token->type == ')')
+ if (parser->curr->type == ')')
break;
- if (parser->curr_token->type != ',') {
+ if (parser->curr->type != ',') {
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(','),
- onyx_get_token_type_name(parser->curr_token->type));
+ parser->curr->pos,
+ token_name(','),
+ token_name(parser->curr->type));
return (AstTyped *) &error_node;
}
- parser_next_token(parser);
+ consume_token(parser);
}
- parser_next_token(parser);
+ consume_token(parser);
retval = (AstTyped *) call_node;
break;
{
AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
bool_node->base.type_node = (AstType *) &basic_type_bool;
- bool_node->base.token = expect(parser, Token_Type_Literal_True);
+ bool_node->base.token = expect_token(parser, Token_Type_Literal_True);
bool_node->value.i = 1;
retval = (AstTyped *) bool_node;
break;
{
AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
bool_node->base.type_node = (AstType *) &basic_type_bool;
- bool_node->base.token = expect(parser, Token_Type_Literal_False);
+ bool_node->base.token = expect_token(parser, Token_Type_Literal_False);
bool_node->value.i = 0;
retval = (AstTyped *) bool_node;
break;
}
- case Token_Type_Keyword_Proc:
- {
- AstFunction* func_node = parse_function_definition(parser);
-
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node);
-
- retval = (AstTyped *) func_node;
- break;
- }
-
default:
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(parser->curr_token->type));
+ parser->curr->pos,
+ token_name(parser->curr->type));
return NULL;
}
- while (parser->curr_token->type == Token_Type_Keyword_Cast) {
- parser_next_token(parser);
+ while (parser->curr->type == Token_Type_Keyword_Cast) {
+ consume_token(parser);
AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
cast_node->base.type_node = parse_type(parser);
}
}
+// <factor> + <factor>
+// <factor> - <factor>
+// <factor> * <factor>
+// <factor> / <factor>
+// <factor> % <factor>
+// <factor> == <factor>
+// <factor> != <factor>
+// <factor> <= <factor>
+// <factor> >= <factor>
+// <factor> < <factor>
+// <factor> > <factor>
+// With expected precedence rules
static AstTyped* parse_expression(OnyxParser* parser) {
bh_arr(AstBinaryOp*) tree_stack = NULL;
bh_arr_new(global_scratch_allocator, tree_stack, 4);
while (1) {
bin_op_kind = -1;
- switch ((u16) parser->curr_token->type) {
+ switch ((u16) parser->curr->type) {
case Token_Type_Equal_Equal: bin_op_kind = Binary_Op_Equal; break;
case Token_Type_Not_Equal: bin_op_kind = Binary_Op_Not_Equal; break;
case Token_Type_Less_Equal: bin_op_kind = Binary_Op_Less_Equal; break;
}
if (bin_op_kind != -1) {
- bin_op_tok = parser->curr_token;
- parser_next_token(parser);
+ bin_op_tok = parser->curr;
+ consume_token(parser);
AstBinaryOp* bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
bin_op->operation = bin_op_kind;
return root;
}
+// 'if' <expr> <block> ('elseif' <cond> <block>)* ('else' <block>)?
static AstIf* parse_if_stmt(OnyxParser* parser) {
- expect(parser, Token_Type_Keyword_If);
+ expect_token(parser, Token_Type_Keyword_If);
AstTyped* cond = parse_expression(parser);
AstBlock* true_block = parse_block(parser);
if (true_block != NULL)
if_node->true_block.as_block = true_block;
- while (parser->curr_token->type == Token_Type_Keyword_Elseif) {
- parser_next_token(parser);
+ while (parser->curr->type == Token_Type_Keyword_Elseif) {
+ consume_token(parser);
AstIf* elseif_node = make_node(AstIf, Ast_Kind_If);
cond = parse_expression(parser);
if_node = elseif_node;
}
- if (parser->curr_token->type == Token_Type_Keyword_Else) {
- parser_next_token(parser);
+ if (parser->curr->type == Token_Type_Keyword_Else) {
+ consume_token(parser);
AstBlock* false_block = parse_block(parser);
if (false_block != NULL)
return root_if;
}
+// 'while' <expr> <block>
static AstWhile* parse_while_stmt(OnyxParser* parser) {
- OnyxToken* while_token = expect(parser, Token_Type_Keyword_While);
+ OnyxToken* while_token = expect_token(parser, Token_Type_Keyword_While);
AstTyped* cond = parse_expression(parser);
AstBlock* body = parse_block(parser);
// Returns 1 if the symbol was consumed. Returns 0 otherwise
// ret is set to the statement to insert
+// <symbol> : <type> = <expr>
+// <symbol> : <type> : <expr>
+// <symbol> := <expr>
+// <symbol> :: <expr>
+// <symbol> = <expr>
+// <symbol> += <expr>
+// <symbol> -= <expr>
+// <symbol> *= <expr>
+// <symbol> /= <expr>
+// <symbol> %= <expr>
static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
- if (parser->curr_token->type != Token_Type_Symbol) return 0;
- OnyxToken* symbol = expect(parser, Token_Type_Symbol);
+ if (parser->curr->type != Token_Type_Symbol) return 0;
+ OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
- switch ((u16) parser->curr_token->type) {
+ switch ((u16) parser->curr->type) {
// NOTE: Declaration
case ':':
{
- parser_next_token(parser);
+ consume_token(parser);
AstType* type_node = NULL;
// NOTE: var: type
- if (parser->curr_token->type != ':'
- && parser->curr_token->type != '=') {
+ if (parser->curr->type != ':'
+ && parser->curr->type != '=') {
type_node = parse_type(parser);
}
local->base.flags |= Ast_Flag_Lval; // NOTE: DELETE
*ret = (AstNode *) local;
- if (parser->curr_token->type == '=' || parser->curr_token->type == ':') {
- if (parser->curr_token->type == ':') {
+ if (parser->curr->type == '=' || parser->curr->type == ':') {
+ if (parser->curr->type == ':') {
local->base.flags |= Ast_Flag_Const;
}
AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
local->base.next = (AstNode *) assignment;
- assignment->base.token = parser->curr_token;
- parser_next_token(parser);
+ assignment->base.token = parser->curr;
+ consume_token(parser);
AstTyped* expr = parse_expression(parser);
if (expr == NULL) {
- onyx_token_null_toggle(parser->curr_token);
+ token_toggle_end(parser->curr);
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION,
assignment->base.token->pos,
- parser->curr_token->text);
- onyx_token_null_toggle(parser->curr_token);
+ parser->curr->text);
+ token_toggle_end(parser->curr);
return 1;
}
assignment->expr = expr;
case '=':
{
AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
- assignment->base.token = parser->curr_token;
- parser_next_token(parser);
+ assignment->base.token = parser->curr;
+ consume_token(parser);
AstNode* lval = make_node(AstNode, Ast_Kind_Symbol);
lval->token = symbol;
case Token_Type_Percent_Equal:
{
BinaryOp bin_op;
- if (parser->curr_token->type == Token_Type_Plus_Equal) bin_op = Binary_Op_Add;
- else if (parser->curr_token->type == Token_Type_Minus_Equal) bin_op = Binary_Op_Minus;
- else if (parser->curr_token->type == Token_Type_Star_Equal) bin_op = Binary_Op_Multiply;
- else if (parser->curr_token->type == Token_Type_Fslash_Equal) bin_op = Binary_Op_Divide;
- else if (parser->curr_token->type == Token_Type_Percent_Equal) bin_op = Binary_Op_Modulus;
+ if (parser->curr->type == Token_Type_Plus_Equal) bin_op = Binary_Op_Add;
+ else if (parser->curr->type == Token_Type_Minus_Equal) bin_op = Binary_Op_Minus;
+ else if (parser->curr->type == Token_Type_Star_Equal) bin_op = Binary_Op_Multiply;
+ else if (parser->curr->type == Token_Type_Fslash_Equal) bin_op = Binary_Op_Divide;
+ else if (parser->curr->type == Token_Type_Percent_Equal) bin_op = Binary_Op_Modulus;
AstBinaryOp* bin_op_node = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
bin_op_node->operation = bin_op;
- bin_op_node->base.token = parser->curr_token;
+ bin_op_node->base.token = parser->curr;
- parser_next_token(parser);
+ consume_token(parser);
AstTyped* expr = parse_expression(parser);
AstNode* bin_op_left = make_node(AstNode, Ast_Kind_Symbol);
}
default:
- parser_prev_token(parser);
+ unconsume_token(parser);
}
return 0;
}
+// 'return' <expr>?
static AstReturn* parse_return_statement(OnyxParser* parser) {
AstReturn* return_node = make_node(AstReturn, Ast_Kind_Return);
- return_node->base.token = expect(parser, Token_Type_Keyword_Return);
+ return_node->base.token = expect_token(parser, Token_Type_Keyword_Return);
AstTyped* expr = NULL;
- if (parser->curr_token->type != ';') {
+ if (parser->curr->type != ';') {
expr = parse_expression(parser);
if (expr == NULL || expr == (AstTyped *) &error_node) {
return return_node;
}
+// <return> ;
+// <block>
+// <symbol_statement> ;
+// <expr> ;
+// <if>
+// <while>
+// 'break' ;
+// 'continue' ;
static AstNode* parse_statement(OnyxParser* parser) {
b32 needs_semicolon = 1;
AstNode* retval = NULL;
- switch ((u16) parser->curr_token->type) {
+ switch ((u16) parser->curr->type) {
case Token_Type_Keyword_Return:
retval = (AstNode *) parse_return_statement(parser);
break;
case Token_Type_Keyword_Break:
retval = make_node(AstNode, Ast_Kind_Break);
- retval->token = expect(parser, Token_Type_Keyword_Break);
+ retval->token = expect_token(parser, Token_Type_Keyword_Break);
break;
case Token_Type_Keyword_Continue:
retval = make_node(AstNode, Ast_Kind_Break);
- retval->token = expect(parser, Token_Type_Keyword_Continue);
+ retval->token = expect_token(parser, Token_Type_Keyword_Continue);
break;
default:
}
if (needs_semicolon) {
- if (parser->curr_token->type != ';') {
+ if (parser->curr->type != ';') {
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(';'),
- onyx_get_token_type_name(parser->curr_token->type));
+ parser->curr->pos,
+ token_name(';'),
+ token_name(parser->curr->type));
find_token(parser, ';');
}
- parser_next_token(parser);
+ consume_token(parser);
}
return retval;
}
+// '---'
+// '{' <stmtlist> '}'
static AstBlock* parse_block(OnyxParser* parser) {
AstBlock* block = make_node(AstBlock, Ast_Kind_Block);
AstLocalGroup* lg = make_node(AstLocalGroup, Ast_Kind_Local_Group);
block->locals = lg;
// NOTE: --- is for an empty block
- if (parser->curr_token->type == Token_Type_Empty_Block) {
- expect(parser, Token_Type_Empty_Block);
+ if (parser->curr->type == Token_Type_Empty_Block) {
+ expect_token(parser, Token_Type_Empty_Block);
return block;
}
- expect(parser, '{');
+ expect_token(parser, '{');
AstNode** next = &block->body;
AstNode* stmt = NULL;
- while (parser->curr_token->type != '}') {
+ while (parser->curr->type != '}') {
stmt = parse_statement(parser);
if (stmt != NULL && stmt->kind != Ast_Kind_Error) {
}
}
- expect(parser, '}');
+ expect_token(parser, '}');
return block;
}
+// <symbol>
+// '^' <type>
static AstType* parse_type(OnyxParser* parser) {
AstType* root = NULL;
AstType** next_insertion = &root;
while (1) {
- if (parser->curr_token->type == '^') {
- parser_next_token(parser);
+ if (parser->curr->type == '^') {
+ consume_token(parser);
AstPointerType* new = make_node(AstPointerType, Ast_Kind_Pointer_Type);
new->base.flags |= Basic_Flag_Pointer;
*next_insertion = (AstType *) new;
next_insertion = &new->elem;
}
- else if (parser->curr_token->type == Token_Type_Symbol) {
+ else if (parser->curr->type == Token_Type_Symbol) {
AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
- symbol_node->token = expect(parser, Token_Type_Symbol);
+ symbol_node->token = expect_token(parser, Token_Type_Symbol);
*next_insertion = (AstType *) symbol_node;
next_insertion = NULL;
}
else {
- onyx_token_null_toggle(parser->curr_token);
+ token_toggle_end(parser->curr);
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
- parser->curr_token->pos,
- parser->curr_token->text);
- onyx_token_null_toggle(parser->curr_token);
+ parser->curr->pos,
+ parser->curr->text);
+ token_toggle_end(parser->curr);
- parser_next_token(parser);
+ consume_token(parser);
break;
}
return root;
}
+// e
+// '(' (<symbol>: <type>,?)* ')'
static AstLocal* parse_function_params(OnyxParser* parser) {
- if (parser->curr_token->type != '(')
+ if (parser->curr->type != '(')
return NULL;
- expect(parser, '(');
+ expect_token(parser, '(');
- if (parser->curr_token->type == ')') {
- parser_next_token(parser);
+ if (parser->curr->type == ')') {
+ consume_token(parser);
return NULL;
}
AstLocal* trailer = NULL;
OnyxToken* symbol;
- while (parser->curr_token->type != ')') {
- if (parser->curr_token->type == ',') parser_next_token(parser);
+ while (parser->curr->type != ')') {
+ if (parser->curr->type == ',') consume_token(parser);
- symbol = expect(parser, Token_Type_Symbol);
- expect(parser, ':');
+ symbol = expect_token(parser, Token_Type_Symbol);
+ expect_token(parser, ':');
curr_param = make_node(AstLocal, Ast_Kind_Param);
curr_param->base.token = symbol;
trailer = curr_param;
}
- parser_next_token(parser); // Skip the )
+ consume_token(parser); // Skip the )
return first_param;
}
+// e
+// '#' <symbol>
static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
- if (parser->curr_token->type != '#') return 0;
+ if (parser->curr->type != '#') return 0;
- expect(parser, '#');
- OnyxToken* sym = expect(parser, Token_Type_Symbol);
+ expect_token(parser, '#');
+ OnyxToken* sym = expect_token(parser, Token_Type_Symbol);
b32 match = (strlen(dir) == sym->length) && (strncmp(dir, sym->text, sym->length) == 0);
if (!match) {
- parser_prev_token(parser);
- parser_prev_token(parser);
+ unconsume_token(parser);
+ unconsume_token(parser);
}
return match;
}
+// 'proc' <directive>* <func_params> ('->' <type>)? <block>
static AstFunction* parse_function_definition(OnyxParser* parser) {
AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
- func_def->base.token = expect(parser, Token_Type_Keyword_Proc);
+ func_def->base.token = expect_token(parser, Token_Type_Keyword_Proc);
- while (parser->curr_token->type == '#') {
+ while (parser->curr->type == '#') {
if (parse_possible_directive(parser, "intrinsic")) {
func_def->base.flags |= Ast_Flag_Intrinsic;
- if (parser->curr_token->type == Token_Type_Literal_String) {
- OnyxToken* str_token = expect(parser, Token_Type_Literal_String);
+ if (parser->curr->type == Token_Type_Literal_String) {
+ OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
func_def->intrinsic_name = str_token;
}
}
}
else if (parse_possible_directive(parser, "foreign")) {
- func_def->foreign_module = expect(parser, Token_Type_Literal_String);
- func_def->foreign_name = expect(parser, Token_Type_Literal_String);
+ func_def->foreign_module = expect_token(parser, Token_Type_Literal_String);
+ func_def->foreign_name = expect_token(parser, Token_Type_Literal_String);
func_def->base.flags |= Ast_Flag_Foreign;
}
else if (parse_possible_directive(parser, "export")) {
func_def->base.flags |= Ast_Flag_Exported;
- if (parser->curr_token->type == Token_Type_Literal_String) {
- OnyxToken* str_token = expect(parser, Token_Type_Literal_String);
+ if (parser->curr->type == Token_Type_Literal_String) {
+ OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
func_def->exported_name = str_token;
}
}
else {
- OnyxToken* directive_token = expect(parser, '#');
- OnyxToken* symbol_token = expect(parser, Token_Type_Symbol);
+ OnyxToken* directive_token = expect_token(parser, '#');
+ OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_UNKNOWN_DIRECTIVE,
func_def->params = params;
AstType* return_type = (AstType *) &basic_type_void;
- if (parser->curr_token->type == Token_Type_Right_Arrow) {
- expect(parser, Token_Type_Right_Arrow);
+ if (parser->curr->type == Token_Type_Right_Arrow) {
+ expect_token(parser, Token_Type_Right_Arrow);
return_type = parse_type(parser);
}
return func_def;
}
-// static AstNode* parse_foreign(OnyxParser* parser) {
-// expect(parser, Token_Type_Keyword_Foreign);
-//
-// AstForeign* foreign = make_node(AstForeign, Ast_Kind_Foreign);
-// foreign->mod_token = expect(parser, Token_Type_Literal_String);
-// foreign->name_token = expect(parser, Token_Type_Literal_String);
-//
-// if (parser->curr_token->type == Token_Type_Keyword_Proc) {
-// foreign->import = (AstNode *) parse_function_definition(parser);
-//
-// } else {
-// AstType* type = parse_type(parser);
-//
-// AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
-// global->base.type_node = type;
-// global->base.flags |= Ast_Flag_Lval;
-//
-// foreign->import = (AstNode *) global;
-// }
-//
-// return (AstNode *) foreign;
-// }
-
-static AstTyped* parse_top_level_constant_symbol(OnyxParser* parser) {
-// if (parser->curr_token->type == Token_Type_Keyword_Proc) {
-// return (AstNode *) parse_function_definition(parser);
-//
-// } else if (parser->curr_token->type == Token_Type_Keyword_Struct) {
-// // Handle struct case
-// assert(0);
-//
-// } else if (parser->curr_token->type == Token_Type_Keyword_Foreign) {
-// return (AstNode *) parse_foreign(parser);
-//
-// } else {
-// // Global constant with initial value
-// AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
-// global->initial_value = parse_expression(parser);
-// global->base.flags |= Ast_Flag_Const;
-// global->base.flags |= Ast_Flag_Lval;
-// global->base.flags |= Ast_Flag_Comptime;
-//
-// return (AstNode *) global;
-// }
-
- return parse_expression(parser);
+// 'global' <type>
+static AstTyped* parse_global_declaration(OnyxParser* parser) {
+ AstGlobal* global_node = make_node(AstGlobal, Ast_Kind_Global);
+ global_node->base.token = expect_token(parser, Token_Type_Keyword_Global);
+
+ while (parser->curr->type == '#') {
+ if (parse_possible_directive(parser, "foreign")) {
+ global_node->foreign_module = expect_token(parser, Token_Type_Literal_String);
+ global_node->foreign_name = expect_token(parser, Token_Type_Literal_String);
+
+ global_node->base.flags |= Ast_Flag_Foreign;
+ }
+
+ else if (parse_possible_directive(parser, "export")) {
+ global_node->base.flags |= Ast_Flag_Exported;
+
+ if (parser->curr->type == Token_Type_Literal_String) {
+ OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
+ global_node->exported_name = str_token;
+ }
+ }
+
+ else {
+ OnyxToken* directive_token = expect_token(parser, '#');
+ OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
+
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_UNKNOWN_DIRECTIVE,
+ directive_token->pos,
+ symbol_token->text, symbol_token->length);
+ }
+ }
+
+ global_node->base.type_node = parse_type(parser);
+ global_node->base.flags |= Ast_Flag_Lval;
+
+
+ bh_arr_push(parser->results.nodes_to_process, (AstNode *) global_node);
+
+ return (AstTyped *) global_node;
+}
+
+static AstTyped* parse_top_level_expression(OnyxParser* parser) {
+ if (parser->curr->type == Token_Type_Keyword_Proc) {
+ AstFunction* func_node = parse_function_definition(parser);
+
+ bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node);
+
+ return (AstTyped *) func_node;
+ }
+ else if (parser->curr->type == Token_Type_Keyword_Global) {
+ return parse_global_declaration(parser);
+ }
+ else {
+ return parse_expression(parser);
+ }
}
+// 'use' <string>
+// <symbol> :: <expr>
static AstNode* parse_top_level_statement(OnyxParser* parser) {
- switch (parser->curr_token->type) {
+ switch (parser->curr->type) {
case Token_Type_Keyword_Use:
{
AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
- use_node->base.token = expect(parser, Token_Type_Keyword_Use);
- use_node->filename = expect(parser, Token_Type_Literal_String);
+ use_node->base.token = expect_token(parser, Token_Type_Keyword_Use);
+ use_node->filename = expect_token(parser, Token_Type_Literal_String);
return (AstNode *) use_node;
}
case Token_Type_Symbol:
{
- OnyxToken* symbol = parser->curr_token;
- parser_next_token(parser);
+ OnyxToken* symbol = parser->curr;
+ consume_token(parser);
- expect(parser, ':');
- expect(parser, ':');
+ expect_token(parser, ':');
+ expect_token(parser, ':');
- AstTyped* node = parse_top_level_constant_symbol(parser);
+ AstTyped* node = parse_top_level_expression(parser);
if (node->kind == Ast_Kind_Function) {
AstFunction* func = (AstFunction *) node;
if (func->exported_name == NULL)
func->exported_name = symbol;
+
+ } else if (node->kind == Ast_Kind_Global) {
+ AstGlobal* global = (AstGlobal *) node;
+
+ if (global->exported_name == NULL)
+ global->exported_name = symbol;
+
} else {
// HACK
bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
default: break;
}
- parser_next_token(parser);
+ consume_token(parser);
return NULL;
}
parser.allocator = alloc;
parser.tokenizer = tokenizer;
- parser.curr_token = tokenizer->tokens;
- parser.prev_token = NULL;
+ parser.curr = tokenizer->tokens;
+ parser.prev = NULL;
parser.msgs = msgs;
parser.results = (ParseResults) {
}
ParseResults onyx_parse(OnyxParser *parser) {
- while (parser->curr_token->type != Token_Type_End_Stream) {
+ while (parser->curr->type != Token_Type_End_Stream) {
AstNode* curr_stmt = parse_top_level_statement(parser);
if (curr_stmt != NULL && curr_stmt != &error_node) {
// NOTE: Allows easier testing of types since most of the characters
// corresponding to these values are not printable
#if 1
-const WasmType WASM_TYPE_INT32 = 0x7F;
-const WasmType WASM_TYPE_INT64 = 0x7E;
-const WasmType WASM_TYPE_FLOAT32 = 0x7D;
-const WasmType WASM_TYPE_FLOAT64 = 0x7C;
-const WasmType WASM_TYPE_VOID = 0x00;
+#define WASM_TYPE_INT32 0x7F
+#define WASM_TYPE_INT64 0x7E
+#define WASM_TYPE_FLOAT32 0x7D
+#define WASM_TYPE_FLOAT64 0x7C
+#define WASM_TYPE_VOID 0x00
#else
-const WasmType WASM_TYPE_INT32 = 'A';
-const WasmType WASM_TYPE_INT64 = 'B';
-const WasmType WASM_TYPE_FLOAT32 = 'C';
-const WasmType WASM_TYPE_FLOAT64 = 'D';
-const WasmType WASM_TYPE_VOID = '\0';
+#define WASM_TYPE_INT32 'A'
+#define WASM_TYPE_INT64 'B'
+#define WASM_TYPE_FLOAT32 'C'
+#define WASM_TYPE_FLOAT64 'D'
+#define WASM_TYPE_VOID 'E'
#endif
static const char* wi_string(WasmInstructionType wit) {
bh_arr_new(mod->allocator, wasm_func.code, 4);
if (fd->base.flags & Ast_Flag_Exported) {
- onyx_token_null_toggle(fd->exported_name);
+ token_toggle_end(fd->exported_name);
i32 func_idx = (i32) bh_imap_get(&mod->func_map, (u64) fd);
bh_table_put(WasmExport, mod->exports, fd->exported_name->text, wasm_export);
mod->export_count++;
- onyx_token_null_toggle(fd->exported_name);
+ token_toggle_end(fd->exported_name);
}
// If there is no body then don't process the code
}
static void compile_global_declaration(OnyxWasmModule* module, AstGlobal* global) {
+ WasmType global_type = onyx_type_to_wasm_type(global->base.type);
+
+ if (global->base.flags & Ast_Flag_Foreign) {
+ WasmImport import = {
+ .kind = WASM_FOREIGN_GLOBAL,
+ .idx = global_type,
+ .mod = global->foreign_module,
+ .name = global->foreign_name,
+ };
+
+ bh_arr_push(module->imports, import);
+ return;
+ }
+
WasmGlobal glob = {
- .type = onyx_type_to_wasm_type(global->base.type),
+ .type = global_type,
.mutable = (global->base.flags & Ast_Flag_Const) == 0,
.initial_value = NULL,
};
- if (!global->initial_value) {
- onyx_message_add(module->msgs,
- ONYX_MESSAGE_TYPE_LITERAL,
- global->base.token->pos,
- "global without initial value");
- return;
- }
-
if ((global->base.flags & Ast_Flag_Exported) != 0) {
- onyx_token_null_toggle(global->base.token);
+ token_toggle_end(global->exported_name);
i32 global_idx = (i32) bh_imap_get(&module->func_map, (u64) global);
.kind = WASM_FOREIGN_GLOBAL,
.idx = global_idx,
};
- bh_table_put(WasmExport, module->exports, global->base.token->text, wasm_export);
+ bh_table_put(WasmExport, module->exports, global->exported_name->text, wasm_export);
module->export_count++;
- onyx_token_null_toggle(global->base.token);
+ token_toggle_end(global->exported_name);
}
- compile_expression(module, &glob.initial_value, global->initial_value);
- bh_arr_push(module->globals, glob);
-}
+ bh_arr_new(global_heap_allocator, glob.initial_value, 1);
-static void compile_foreign(OnyxWasmModule* module, AstForeign* foreign) {
- if (foreign->import->kind == Ast_Kind_Function) {
- i32 type_idx = generate_type_idx(module, (AstFunction *) foreign->import);
+ switch (global_type) {
+ case WASM_TYPE_INT32: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_I32_CONST, 0 })); break;
+ case WASM_TYPE_INT64: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_I64_CONST, 0 })); break;
+ case WASM_TYPE_FLOAT32: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_F32_CONST, 0 })); break;
+ case WASM_TYPE_FLOAT64: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_F64_CONST, 0 })); break;
- WasmImport import = {
- .kind = WASM_FOREIGN_FUNCTION,
- .idx = type_idx,
- .mod = foreign->mod_token,
- .name = foreign->name_token,
- };
-
- bh_arr_push(module->imports, import);
-
- } else if (foreign->import->kind == Ast_Kind_Global) {
- WasmType global_type = onyx_type_to_wasm_type(((AstGlobal *) foreign->import)->base.type);
-
- WasmImport import = {
- .kind = WASM_FOREIGN_GLOBAL,
- .idx = global_type,
- .mod = foreign->mod_token,
- .name = foreign->name_token,
- };
-
- bh_arr_push(module->imports, import);
-
- } else {
- DEBUG_HERE;
- // NOTE: Invalid foreign
- assert(0);
+ default: assert(("Invalid global type", 0)); break;
}
+
+ bh_arr_push(module->globals, glob);
}
OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs) {
}
}
+ bh_arr_each(AstGlobal *, global, program->globals) {
+ if ((*global)->base.flags & Ast_Flag_Foreign) {
+ bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
+ }
+ }
+
bh_arr_each(AstFunction *, function, program->functions) {
if ((*function)->base.flags & Ast_Flag_Foreign) continue;
bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
}
+ bh_arr_each(AstGlobal *, global, program->globals) {
+ if ((*global)->base.flags & Ast_Flag_Foreign) continue;
+
+ bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
+ }
+
// NOTE: Then, compile everything
+ bh_arr_each(AstGlobal *, global, program->globals)
+ compile_global_declaration(module, *global);
+
bh_arr_each(AstFunction *, function, program->functions)
compile_function(module, *function);