From: Brendan Hansen Date: Tue, 2 Jun 2020 01:05:14 +0000 (-0500) Subject: Better parse tree printer and some type checking X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=b873916ea511cab56d84b764bf3796392598b4fb;p=onyx.git Better parse tree printer and some type checking --- diff --git a/docs/plan b/docs/plan index 0d11788d..d78b4992 100644 --- a/docs/plan +++ b/docs/plan @@ -26,36 +26,33 @@ FEATURES: - defer ? polymorphic functions -EXAMPLE CODE: - -// This is a comment -// This is also the only way to do comments - -use "core"; // Looks for "core.onyx" in the current directory - -Foo :: struct { x i32, y i32 }; - -export add :: proc (a i32, b i32) -> i32 { - return a + b; -}; - -foo :: proc (a i32) -> Foo { - return Foo { x = a, y = 0 }; -} - -MVP CODE: - -/* Comments need to be parsed */ - -export add :: proc (a i32, b i32) -> i32 { - return a + b; -} - -export max :: proc (a i32, b i32) -> i32 { - /* Curly braces are required */ - if a > b { - return a; - } else { - return b; - } -} +HOW: + Currently there is a multi-phase development process since implementing everything + at once would be overwhelming and unsatisfying. The current progress of each stage: + + Stage 1 (MVP): + [ ] Can declare procedures + [ ] Procedures have params and returns of the following types: + - i32, u32 + - i64, u64 + - f32, f64 + [ ] Procedures have locals of the same set of types + [ ] Locals are declared in the following way + local : (const) (type) (= initial value); + + if const is specified, the value is unmodifiable + if type is specified, that is assumed to be the correct type + if type is not specified, the type of initial value is used as the type + + [ ] Five basic math operations are legal: + + - * / % + [ ] Math operations are sign aware and only operate on operands of the same type + [ ] All casts are explicit using this syntax: + X as T + + casts X to type T + + [ ] Conditional branching works as expected + [ ] Curly braces are required for all bodies of blocks + [ ] Simple while loop is functioning as expected + [ ] break and continue semantics diff --git a/docs/thoughts b/docs/thoughts index 86a7ba5d..24dfa3cc 100644 --- a/docs/thoughts +++ b/docs/thoughts @@ -22,3 +22,5 @@ Type checking at parse time: foo(5) would have a left node of SYMBOL:foo This will be resolved in a later stage between the parsing and semantic pass Type checking and resolving would have to occur afterwards + +Creating an IR: diff --git a/onyx b/onyx index 07864693..37a1774a 100755 Binary files a/onyx and b/onyx differ diff --git a/onyx.c b/onyx.c index 27eeec05..ceb09703 100644 --- a/onyx.c +++ b/onyx.c @@ -53,17 +53,19 @@ int main(int argc, char *argv[]) { // 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"); } - bh_file_contents_delete(&fc); - onyx_tokenizer_free(&tokenizer); - onyx_parser_free(&parser); + +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 index a922f7c8..d76c93f3 100644 --- a/onyxlex.c +++ b/onyxlex.c @@ -19,6 +19,7 @@ static const char* onyx_token_type_names[] = { "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", @@ -160,6 +161,7 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) { 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); diff --git a/onyxlex.h b/onyxlex.h index a64b0ec6..b1b5eb06 100644 --- a/onyxlex.h +++ b/onyxlex.h @@ -21,6 +21,7 @@ typedef enum OnyxTokenType { TOKEN_TYPE_KEYWORD_FOREIGN, TOKEN_TYPE_KEYWORD_PROC, TOKEN_TYPE_KEYWORD_GLOBAL, + TOKEN_TYPE_KEYWORD_CAST, TOKEN_TYPE_RIGHT_ARROW, TOKEN_TYPE_LEFT_ARROW, diff --git a/onyxmsgs.c b/onyxmsgs.c index 6b92357d..a2e55512 100644 --- a/onyxmsgs.c +++ b/onyxmsgs.c @@ -9,6 +9,8 @@ static const char* msg_formats[] = { "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, ...) { diff --git a/onyxmsgs.h b/onyxmsgs.h index fc102233..6c6a19e8 100644 --- a/onyxmsgs.h +++ b/onyxmsgs.h @@ -16,6 +16,8 @@ typedef enum OnyxMessageType { 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; diff --git a/onyxparser.c b/onyxparser.c index 77bc0c47..103d8e3c 100644 --- a/onyxparser.c +++ b/onyxparser.c @@ -1,5 +1,6 @@ #include "onyxlex.h" +#include "onyxmsgs.h" #include "onyxparser.h" static const char* ast_node_names[] = { @@ -42,23 +43,19 @@ static const char* ast_node_names[] = { struct OnyxTypeInfo builtin_types[] = { { ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" }, - { ONYX_TYPE_INFO_KIND_VOID, 0, "void" }, + { ONYX_TYPE_INFO_KIND_VOID, 0, "void", 0, 0, 0, 0, 1 }, - { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1 }, + { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1, 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_UINT32, 4, "u32", 1, 1, 0, 0, 1 }, + { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0, 1 }, - { 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_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 }, - { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0 }, - { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0 }, + { 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 }; @@ -197,41 +194,44 @@ static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident) { 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); - } + case TOKEN_TYPE_OPEN_PAREN: + { + parser_next_token(parser); + OnyxAstNode* expr = parse_expression(parser); + expect(parser, TOKEN_TYPE_CLOSE_PAREN); + return expr; + } - // TODO: Handle calling a function - return sym_node; - } + 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; - } + 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)); + 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; @@ -249,12 +249,25 @@ static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left) { } 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; } @@ -265,14 +278,31 @@ 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_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; @@ -289,83 +319,96 @@ static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret) { 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) { - parser_next_token(parser); - - OnyxAstNode* expr = parse_expression(parser); - OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT); - assignment->right = expr; - assignment->left = (OnyxAstNode*) local; - *ret = assignment; - } - return 1; - } + // NOTE: 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); + // NOTE: Assignment + case TOKEN_TYPE_SYM_EQUALS: + { + parser_next_token(parser); - OnyxAstNode* lval = lookup_identifier(parser, symbol); + 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); - } + 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; + } - 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); + 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; - } + find_token(parser, TOKEN_TYPE_SYM_SEMICOLON); + return 1; + } - default: - parser_prev_token(parser); + default: + parser_prev_token(parser); } return 0; @@ -393,31 +436,32 @@ static OnyxAstNode* parse_return_statement(OnyxParser* parser) { static OnyxAstNode* parse_statement(OnyxParser* parser) { switch (parser->curr_token->type) { - case TOKEN_TYPE_KEYWORD_RETURN: - return parse_return_statement(parser); + case TOKEN_TYPE_KEYWORD_RETURN: + return parse_return_statement(parser); - case TOKEN_TYPE_OPEN_BRACE: - return (OnyxAstNode *) parse_block(parser, 0); + 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_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_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); + case TOKEN_TYPE_KEYWORD_IF: + return parse_if_stmt(parser); - default: - return NULL; + default: + return NULL; } } @@ -558,65 +602,68 @@ static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) { 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)); + case TOKEN_TYPE_KEYWORD_USE: + assert(0); break; - } - OnyxAstNode* top_level_decl = parse_top_level_statement(parser); - top_level_decl->flags |= ONYX_AST_FLAG_EXPORTED; - return top_level_decl; - } break; - - case TOKEN_TYPE_SYMBOL: { - OnyxToken* symbol = parser->curr_token; - parser_next_token(parser); - - expect(parser, TOKEN_TYPE_SYM_COLON); - expect(parser, TOKEN_TYPE_SYM_COLON); - - if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) { - OnyxAstNodeFuncDef* func_def = parse_function_definition(parser); - func_def->token = symbol; - - 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; + 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; } - 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; + 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); diff --git a/onyxparser.h b/onyxparser.h index dadf29f9..b2496f69 100644 --- a/onyxparser.h +++ b/onyxparser.h @@ -100,6 +100,7 @@ typedef struct OnyxTypeInfo { u32 is_unsigned : 1; u32 is_float : 1; u32 is_bool : 1; + u32 is_known : 1; } OnyxTypeInfo; extern OnyxTypeInfo builtin_types[]; diff --git a/onyxutils.c b/onyxutils.c index 2a07f2a9..e40e0cb1 100644 --- a/onyxutils.c +++ b/onyxutils.c @@ -97,6 +97,15 @@ void onyx_ast_print(OnyxAstNode* node, i32 indent) { 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); diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 19173392..23ea5bbe 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -1,36 +1,16 @@ -/* This is a comment */ - -/* Currently the "foreign" keyword doesn't do anything */ -foreign "console" log :: proc (a i32, b i32) -> i32 --- export add :: proc (a i32, b i32) -> i32 { - /* More comments */ return a + b; } -export mul :: proc (a i32, b i32) -> i32 { +export mul :: proc (a i32, b i32) -> i64 { /* Typechecked */ - c: const i32 = a - b; + c: const i64 = ((a as i64) - (b as i64)); /* Don't love this syntax, but it's easy to parse so whatever Inferred type, but constant */ /* a and b are both i32, so i32 + i32 is i32 so d is i32 */ d: const = a + b; - return c * d; -} - -very_long_function_name :: proc () -> void { - a:i32; - b:i32; - c:i32; - d:i32; - e:i32; - f:i32; - g:i32; - h:i32; - i:i32 = 0 + 2; - j:i32; - k:i32; - l:i32; + return ((c as i32) * d) as i64; } diff --git a/progs/mvp.onyx b/progs/mvp.onyx index 1cfbedc2..cb32d79b 100644 --- a/progs/mvp.onyx +++ b/progs/mvp.onyx @@ -24,4 +24,4 @@ export max :: proc (a i32, b i32) -> i32 { export main :: proc () -> void { console.log(add(2, 3)); console.log(max(5, 10)); -}; \ No newline at end of file +};