From 15d7a21a85593a0208137f751078dcf89403ea84 Mon Sep 17 00:00:00 2001 From: Mustafa Quraish Date: Thu, 3 Feb 2022 07:13:39 -0500 Subject: Add automatic type inference for initialized variable declarations If we know the type of the expression on the RHS, and no type is specified, then we can just assume that the variable has the same type. --- src/parser.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/parser.c b/src/parser.c index 2bb5649..6bf2f1d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -221,48 +221,58 @@ Node *parse_var_declaration(Lexer *lexer) bool is_global = (current_function == NULL); Token token = assert_token(Lexer_next(lexer), TOKEN_LET); - token = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER); + Token identifier = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER); // NOTE: We don't allow shadowing of variables in the any blocks, // this is by design since it's a common mistake. - if (find_local_variable(&token) != NULL) - die_location(token.loc, "Variable `%s` already declared in function", token.value.as_string); - if (find_global_variable(&token) != NULL) - die_location(token.loc, "Variable `%s` already declared globally", token.value.as_string); + if (find_local_variable(&identifier) != NULL) + die_location(identifier.loc, "Variable `%s` already declared in function", identifier.value.as_string); + if (find_global_variable(&identifier) != NULL) + die_location(identifier.loc, "Variable `%s` already declared globally", identifier.value.as_string); Node *node = Node_new(AST_VARDECL); - node->var_decl.var.name = token.value.as_string; + node->var_decl.var.name = identifier.value.as_string; token = Lexer_next(lexer); - if (token.type != TOKEN_COLON) - die_location(token.loc, "Missing type specifier for variable `%s`", node->var_decl.var.name); - node->var_decl.var.type = parse_type(lexer); - - if (is_global) { - add_global_variable(&node->var_decl.var); + bool is_missing_type = false; + if (token.type != TOKEN_COLON) { + is_missing_type = true; } else { - add_variable_to_current_block(&node->var_decl.var); + node->var_decl.var.type = parse_type(lexer); + token = Lexer_next(lexer); } - token = Lexer_next(lexer); if (token.type == TOKEN_ASSIGN) { if (is_global) die_location(token.loc, "Cannot initialize global variable `%s` outside function", node->var_decl.var.name); - if (node->var_decl.var.type->type == TYPE_ARRAY) - die_location(token.loc, "Cannot initialize array variable `%s` here.", node->var_decl.var.name); node->var_decl.value = parse_expression(lexer); - if (!is_convertible(node->var_decl.var.type, node->var_decl.value->expr_type)) { + if (is_missing_type) { + node->var_decl.var.type = node->var_decl.value->expr_type; + is_missing_type = false; + } else if (!is_convertible(node->var_decl.var.type, node->var_decl.value->expr_type)) { fprintf(stderr, "- Variable type: %s\n", type_to_str(node->var_decl.var.type)); fprintf(stderr, "- Value type: %s\n", type_to_str(node->var_decl.value->expr_type)); die_location(token.loc, "Type mismatch for variable declaration `%s` initalizer", node->var_decl.var.name); } + if (node->var_decl.var.type->type == TYPE_ARRAY) + die_location(token.loc, "Cannot initialize array variable `%s` here.", node->var_decl.var.name); + assert_token(Lexer_next(lexer), TOKEN_SEMICOLON); } else { assert_token(token, TOKEN_SEMICOLON); } + if (is_missing_type) + die_location(token.loc, "Type for variable `%s` not specified, and could not be inferred.", node->var_decl.var.name); + + if (is_global) { + add_global_variable(&node->var_decl.var); + } else { + add_variable_to_current_block(&node->var_decl.var); + } + return node; } -- cgit v1.2.3