From 89709b7284638a684a9f2a7c882f761c58dff096 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 22 Jun 2020 16:43:54 -0500 Subject: [PATCH] Added initial type checking --- .vimspector.json | 2 +- Makefile | 1 + include/onyxmsgs.h | 7 ++ include/onyxsempass.h | 7 ++ onyx | Bin 177840 -> 184712 bytes progs/new_minimal.onyx | 26 ++-- src/onyx.c | 1 + src/onyxmsgs.c | 9 +- src/onyxparser.c | 9 +- src/onyxsempass.c | 1 + src/onyxsymres.c | 5 +- src/onyxtypecheck.c | 276 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 324 insertions(+), 20 deletions(-) create mode 100644 src/onyxtypecheck.c diff --git a/.vimspector.json b/.vimspector.json index a52e2a69..6444b264 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/onyx", - "args": ["progs/minimal.onyx"], + "args": ["progs/new_minimal.onyx"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/Makefile b/Makefile index 817e8f10..b300bbaf 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ OBJ_FILES=\ build/onyxparser.o \ build/onyxsempass.o \ build/onyxsymres.o \ + build/onyxtypecheck.o \ build/onyxmsgs.o \ build/onyxutils.o \ build/onyxwasm.o \ diff --git a/include/onyxmsgs.h b/include/onyxmsgs.h index b1d0f50d..b6e0a8fb 100644 --- a/include/onyxmsgs.h +++ b/include/onyxmsgs.h @@ -9,6 +9,7 @@ #define ONYX_MSG_BUFFER_SIZE 256 typedef enum OnyxMessageType { + ONYX_MESSAGE_TYPE_LITERAL, ONYX_MESSAGE_TYPE_EXPECTED_TOKEN, ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, @@ -20,6 +21,12 @@ typedef enum OnyxMessageType { ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH, ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION, + ONYX_MESSAGE_TYPE_FUNCTION_RETURN_MISMATCH, + ONYX_MESSAGE_TYPE_FUNCTION_PARAM_TYPE_MISMATCH, + + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, + ONYX_MESSAGE_TYPE_COUNT, } OnyxMessageType; diff --git a/include/onyxsempass.h b/include/onyxsempass.h index c2e6bcf7..238e1035 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -18,14 +18,21 @@ typedef struct OnyxSemPassState { bh_allocator allocator, node_allocator; OnyxMessages *msgs; + // NOTE: Used in symbol resolution phase OnyxAstNodeScope* curr_scope; + // NOTE: Used in type checking phase + OnyxTypeInfo* expected_return_type; + bh_table(SemPassSymbol *) symbols; } OnyxSemPassState; // NOTE: Resolving all symbols in the tree void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node); +// NOTE: Inferring and checking types in the tree +void onyx_type_check(OnyxSemPassState* state, OnyxAstNode* root_node); + // NOTE: Full semantic pass OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs); void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node); diff --git a/onyx b/onyx index dc020938d5f77feea550cb5b1c5cf7ab0ea2f26f..06ca04055b3312b7c0578b066db555927aca8fec 100755 GIT binary patch delta 64476 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 delta 56320 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 i32 { - // Typechecked - c := a - b; // Mutable - d :: a + b; // Constant +simple_test :: proc { + a: i32 = 5; + b: i64 = 6 as i64; - { - c : i32 = a * 2 + foo(5, 2); - d : i32 = (c + a) * 2; + if a > b { + foo := 123; + print(foo); } - return c * d; + c :: a + foo(); + print(c); } -foo :: proc (a i32, b i32) -> i32 { - return a * 5 + b * 7; +foo :: proc -> i32 { + return 10; +} + +print_nums :: proc (a i32, b i32, c i32) { + print(a); + print(b); + print(c); } diff --git a/src/onyx.c b/src/onyx.c index 788be323..f86095d6 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -63,6 +63,7 @@ int main(int argc, char *argv[]) { // 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)) { + bh_printf("\n\n"); onyx_message_print(&msgs); goto main_exit; } else { diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c index a5f0c7d8..3f87b874 100644 --- a/src/onyxmsgs.c +++ b/src/onyxmsgs.c @@ -2,6 +2,7 @@ #include "onyxmsgs.h" static const char* msg_formats[] = { + "%s", "expected token '%s', got '%s'", "unexpected token '%s'", "unknown type '%s'", @@ -10,8 +11,14 @@ static const char* msg_formats[] = { "unknown symbol '%s'", "redefinition of function '%s'", "mismatched types for binary operator, '%s', '%s'", - "mismatched types on assignment, '%s', '%s'", + "mismatched types on assignment, expected '%s', got '%s'", "expected expression, got '%s'", + + "returning '%s' from function that returns '%s'", + "function '%b' expected type '%s' in position '%d', got '%s'", + + "unable to resolve type for symbol '%b'", + "unable to resolve symbol '%b'", }; void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...) { diff --git a/src/onyxparser.c b/src/onyxparser.c index 01dc0fec..6286e4ce 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -209,9 +209,8 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) { } // NOTE: Function call - expect(parser, TOKEN_TYPE_OPEN_PAREN); - OnyxAstNodeCall* call_node = (OnyxAstNodeCall *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CALL); + call_node->token = expect(parser, TOKEN_TYPE_OPEN_PAREN); call_node->callee = sym_node; // NOTE: Return type is stored on function definition's type // This may have to change if we want multiple returns @@ -319,6 +318,7 @@ static OnyxAstNode* parse_expression(OnyxParser* parser) { parser_next_token(parser); OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, bin_op_kind); + bin_op->token = bin_op_tok; while ( !bh_arr_is_empty(tree_stack) && get_precedence(bh_arr_last(tree_stack)->kind) >= get_precedence(bin_op_kind)) @@ -469,10 +469,9 @@ static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret) { } 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]; + return_node->token = expect(parser, TOKEN_TYPE_KEYWORD_RETURN); + OnyxAstNode* expr = NULL; if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) { diff --git a/src/onyxsempass.c b/src/onyxsempass.c index 7a36627e..d593cb30 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -19,4 +19,5 @@ OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node) { onyx_resolve_symbols(state, root_node); + onyx_type_check(state, root_node); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index edccbecf..6e2b2a2a 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -64,7 +64,7 @@ static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol) symbol->token->token); onyx_token_null_toggle(*symbol->token); - return NULL; + return symbol; } SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); @@ -159,7 +159,7 @@ static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr) { case ONYX_AST_NODE_KIND_CALL: symres_call(state, *expr); break; - case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &(*expr)->as_block); + case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &(*expr)->as_block); break; case ONYX_AST_NODE_KIND_SYMBOL: *expr = symbol_resolve(state, *expr); @@ -281,7 +281,6 @@ void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node) { walker = walker->next; } - // NOTE: First, resolve all symbols walker = root_node; while (walker) { switch (walker->kind) { diff --git a/src/onyxtypecheck.c b/src/onyxtypecheck.c new file mode 100644 index 00000000..28b1f72e --- /dev/null +++ b/src/onyxtypecheck.c @@ -0,0 +1,276 @@ +#define BH_DEBUG +#include "onyxsempass.h" + +static void typecheck_function_defintion(OnyxSemPassState* state, OnyxAstNodeFuncDef* func); +static void typecheck_block(OnyxSemPassState* state, OnyxAstNodeBlock* block); +static void typecheck_statement_chain(OnyxSemPassState* state, OnyxAstNode* start); +static void typecheck_statement(OnyxSemPassState* state, OnyxAstNode* stmt); +static void typecheck_assignment(OnyxSemPassState* state, OnyxAstNode* assign); +static void typecheck_return(OnyxSemPassState* state, OnyxAstNode* retnode); +static void typecheck_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode); +static void typecheck_call(OnyxSemPassState* state, OnyxAstNodeCall* call); +static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr); + +static void typecheck_assignment(OnyxSemPassState* state, OnyxAstNode* assign) { + if (assign->left->kind == ONYX_AST_NODE_KIND_SYMBOL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, + assign->left->token->pos, + assign->left->token->token, assign->left->token->length); + return; + } + + typecheck_expression(state, assign->right); + + if (!assign->left->type->is_known) { + assign->left->type = assign->right->type; + } else { + if (assign->left->type != assign->right->type) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH, + assign->token->pos, + assign->left->type->name, assign->right->type->name); + return; + } + } +} + +static void typecheck_return(OnyxSemPassState* state, OnyxAstNode* retnode) { + if (retnode->left) { + typecheck_expression(state, retnode->left); + + if (retnode->left->type != state->expected_return_type) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_FUNCTION_RETURN_MISMATCH, + retnode->left->token->pos, + retnode->left->type->name, state->expected_return_type->name); + } + } else { + if (state->expected_return_type->size > 0) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + retnode->token->pos, + "returning from non-void function without value"); + } + } +} + +static void typecheck_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode) { + // NOTE: Add check for boolean type on condition + if (ifnode->true_block) typecheck_statement(state, ifnode->true_block); + if (ifnode->false_block) typecheck_statement(state, ifnode->false_block); +} + +static void typecheck_call(OnyxSemPassState* state, OnyxAstNodeCall* call) { + OnyxAstNodeFuncDef* callee = (OnyxAstNodeFuncDef *) call->callee; + + if (callee->kind == ONYX_AST_NODE_KIND_SYMBOL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, + callee->token->pos, + callee->token->token, callee->token->length); + return; + } + + call->type = callee->return_type; + + OnyxAstNodeParam* formal_param = callee->params; + OnyxAstNode* actual_param = call->arguments; + + i32 arg_pos = 0; + while (formal_param != NULL && actual_param != NULL) { + typecheck_expression(state, actual_param); + + if (formal_param->type != actual_param->type) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_FUNCTION_PARAM_TYPE_MISMATCH, + call->token->pos, + callee->token->token, callee->token->length, + formal_param->type->name, arg_pos, + actual_param->type->name); + return; + } + + arg_pos++; + formal_param = formal_param->next; + actual_param = actual_param->next; + } + + if (formal_param != NULL && actual_param == NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + call->token->pos, + "too few arguments to function call"); + return; + } + + if (formal_param == NULL && actual_param != NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + call->token->pos, + "too many arguments to function call"); + return; + } +} + +static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr) { + switch (expr->kind) { + case ONYX_AST_NODE_KIND_ADD: + case ONYX_AST_NODE_KIND_MINUS: + case ONYX_AST_NODE_KIND_MULTIPLY: + case ONYX_AST_NODE_KIND_DIVIDE: + case ONYX_AST_NODE_KIND_MODULUS: + case ONYX_AST_NODE_KIND_EQUAL: + case ONYX_AST_NODE_KIND_NOT_EQUAL: + case ONYX_AST_NODE_KIND_LESS: + case ONYX_AST_NODE_KIND_LESS_EQUAL: + case ONYX_AST_NODE_KIND_GREATER: + case ONYX_AST_NODE_KIND_GREATER_EQUAL: + expr->type = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN]; + + typecheck_expression(state, expr->left); + typecheck_expression(state, expr->right); + + if (expr->left->type == NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + expr->token->pos, + NULL, 0); + return; + } + + if (expr->right->type == NULL) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + expr->token->pos, + NULL, 0); + return; + } + + if (expr->left->type != expr->right->type) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE, + expr->token->pos, + expr->left->type->name, + expr->right->type->name); + return; + } + + expr->type = expr->left->type; + break; + + case ONYX_AST_NODE_KIND_NEGATE: + typecheck_expression(state, expr->left); + expr->type = expr->left->type; + break; + + case ONYX_AST_NODE_KIND_CAST: + // NOTE: Do nothing. The resulting type from the cast + // is already in the cast expression. + break; + + case ONYX_AST_NODE_KIND_CALL: + typecheck_call(state, &expr->as_call); + break; + + case ONYX_AST_NODE_KIND_BLOCK: + typecheck_block(state, &expr->as_block); + break; + + case ONYX_AST_NODE_KIND_SYMBOL: + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, + expr->token->pos, + expr->token->token, expr->token->length); + break; + + case ONYX_AST_NODE_KIND_LOCAL: + case ONYX_AST_NODE_KIND_PARAM: + if (!expr->type->is_known) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + expr->token->pos, + "local variable with unknown type"); + } + break; + + case ONYX_AST_NODE_KIND_ARGUMENT: + typecheck_expression(state, expr->left); + expr->type = expr->left->type; + break; + + case ONYX_AST_NODE_KIND_LITERAL: + // NOTE: Literal types should have been decided + // in the parser (for now). + assert(expr->type->is_known); + break; + + default: + DEBUG_HERE; + break; + } +} + +static void typecheck_statement(OnyxSemPassState* state, OnyxAstNode* stmt) { + switch (stmt->kind) { + case ONYX_AST_NODE_KIND_ASSIGNMENT: typecheck_assignment(state, stmt); break; + case ONYX_AST_NODE_KIND_RETURN: typecheck_return(state, stmt); break; + case ONYX_AST_NODE_KIND_IF: typecheck_if(state, &stmt->as_if); break; + case ONYX_AST_NODE_KIND_CALL: typecheck_call(state, &stmt->as_call); break; + case ONYX_AST_NODE_KIND_BLOCK: typecheck_block(state, &stmt->as_block); break; + + default: break; + } +} + +static void typecheck_statement_chain(OnyxSemPassState* state, OnyxAstNode* start) { + while (start) { + typecheck_statement(state, start); + start = start->next; + } +} + +static void typecheck_block(OnyxSemPassState* state, OnyxAstNodeBlock* block) { + typecheck_statement_chain(state, block->body); + + forll(OnyxAstNodeLocal, local, block->scope->last_local, prev_local) { + if (!local->type->is_known) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, + local->token->pos, + local->token->token, local->token->length); + return; + } + } +} + +static void typecheck_function_defintion(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) { + forll(OnyxAstNodeParam, param, func->params, next) { + if (!param->type->is_known) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + param->token->pos, + "function parameter types must be known"); + return; + } + } + + state->expected_return_type = func->return_type; + if (func->body) { + typecheck_block(state, func->body); + } +} + +void onyx_type_check(OnyxSemPassState* state, OnyxAstNode* root_node) { + OnyxAstNode* walker = root_node; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + typecheck_function_defintion(state, &walker->as_funcdef); + break; + default: break; + } + + walker = walker->next; + } +} -- 2.25.1