diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-03 07:13:39 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-03 07:13:39 -0500 |
| commit | 15d7a21a85593a0208137f751078dcf89403ea84 (patch) | |
| tree | 116866a169469b7cceaef2672b4176615cb3356a | |
| parent | Add pre-increment and pre-decrement operators. (diff) | |
| download | cup-15d7a21a85593a0208137f751078dcf89403ea84.tar.xz cup-15d7a21a85593a0208137f751078dcf89403ea84.zip | |
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.
| -rw-r--r-- | src/parser.c | 44 |
1 files 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; } |