diff options
author | Carlos Maniero <carlos@maniero.me> | 2023-05-08 23:53:41 -0300 |
---|---|---|
committer | Johnny Richard <johnny@johnnyrichard.com> | 2023-05-09 08:50:53 +0200 |
commit | aba7302e7e98fd7bca2056d8ad622d9ca81c495f (patch) | |
tree | 59b4de4d4946f622b97ca7b6e1ded4d1e9cebbe5 | |
parent | ccd5e8585f10488eed72c772cc1804efea6b8fb4 (diff) |
parser: Add the bool type
This commit introduces a new type for booleans. There is no code
generation for this type yet. The intention of this commit is to enable
flow control in the near future.
Signed-off-by: Carlos Maniero <carlos@maniero.me>
Reviewed-by: Johnny Richard <johnny@johnnyrichard.com>
-rw-r--r-- | src/ast.c | 18 | ||||
-rw-r--r-- | src/ast.h | 10 | ||||
-rw-r--r-- | src/ast_pretty_printer.c | 5 | ||||
-rw-r--r-- | src/lexer.c | 12 | ||||
-rw-r--r-- | src/lexer.h | 2 | ||||
-rw-r--r-- | src/parser.c | 15 | ||||
-rw-r--r-- | test/parser_test.c | 53 |
7 files changed, 113 insertions, 2 deletions
@@ -118,6 +118,24 @@ ast_node_new_literal_integer(uint32_t number) } ast_node_t * +ast_node_new_literal_bool(bool boolean) +{ + ast_node_t *node = ast_node_new(); + + *node = (ast_node_t){ + .kind = AST_LITERAL, + .data = { + .literal = { + .kind = AST_LITERAL_BOOL, + .value = { .boolean = boolean } + }, + }, + }; + + return node; +} + +ast_node_t * ast_node_new_binary_operation(ast_binary_operation_kind_t kind, ast_node_t *left, ast_node_t *right) { ast_node_t *node = ast_node_new(); @@ -22,7 +22,8 @@ typedef enum { - TYPE_I32 + TYPE_I32, + TYPE_BOOL } type_t; typedef struct ast_node_t ast_node_t; @@ -67,12 +68,14 @@ typedef struct ast_binary_operation_t typedef enum { - AST_LITERAL_INTEGER + AST_LITERAL_INTEGER, + AST_LITERAL_BOOL } ast_literal_kind_t; typedef union { uint32_t integer; + bool boolean; } ast_literal_value_t; typedef struct ast_literal_t @@ -148,6 +151,9 @@ ast_node_t * ast_node_new_literal_integer(uint32_t number); ast_node_t * +ast_node_new_literal_bool(bool boolean); + +ast_node_t * ast_node_new_variable(ast_identifier_t *identifier); ast_node_t * diff --git a/src/ast_pretty_printer.c b/src/ast_pretty_printer.c index ec8d2de..95f5993 100644 --- a/src/ast_pretty_printer.c +++ b/src/ast_pretty_printer.c @@ -117,6 +117,11 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast) ast_pretty_printer_printf(printer, "Literal type=i32 value='%d'\n", literal.value.integer); break; } + case AST_LITERAL_BOOL: + ast_pretty_printer_set_lst_children(printer); + ast_pretty_printer_printf( + printer, "Literal type=bool value='%s'\n", literal.value.boolean ? "true" : "false"); + break; } break; } diff --git a/src/lexer.c b/src/lexer.c index 72c27cd..f84163d 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -111,6 +111,14 @@ lexer_token_process_keyword(token_t *token) token->kind = TOKEN_KEYWORD_FN; return; } + if (string_view_eq(string_view_from_str("true"), token->value)) { + token->kind = TOKEN_TRUE; + return; + } + if (string_view_eq(string_view_from_str("false"), token->value)) { + token->kind = TOKEN_FALSE; + return; + } } void @@ -454,6 +462,10 @@ token_kind_to_str(token_kind_t kind) return "fn"; case TOKEN_KEYWORD_LET: return "let"; + case TOKEN_TRUE: + return "true"; + case TOKEN_FALSE: + return "false"; case TOKEN_EOF: return "TOKEN_EOF"; case TOKEN_UNKNOWN: diff --git a/src/lexer.h b/src/lexer.h index dd442cc..899c0aa 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -59,6 +59,8 @@ typedef enum TOKEN_KEYWORD_RETURN, TOKEN_KEYWORD_FN, TOKEN_KEYWORD_LET, + TOKEN_TRUE, + TOKEN_FALSE, TOKEN_UNKNOWN } token_kind_t; diff --git a/src/parser.c b/src/parser.c index baa2ef5..22313a6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -84,6 +84,11 @@ parser_parse_type(parser_t *parser, type_t *type) return true; } + if (string_view_eq(token.value, string_view_from_str("bool"))) { + *type = TYPE_BOOL; + return true; + } + parser_error_t error; error.token = token; @@ -102,6 +107,12 @@ parser_literal_integer_node(token_t *token) return ast_node_new_literal_integer(atoi(number_as_str)); } +static ast_node_t * +parser_literal_bool_node(token_t *token) +{ + return ast_node_new_literal_bool(token->kind == TOKEN_TRUE); +} + static ast_binary_operation_kind_t token_to_binary_operation_kind(token_t *token) { @@ -128,6 +139,10 @@ parser_parse_factor(parser_t *parser) switch (token.kind) { case TOKEN_NUMBER: return parser_literal_integer_node(&token); + case TOKEN_TRUE: + return parser_literal_bool_node(&token); + case TOKEN_FALSE: + return parser_literal_bool_node(&token); case TOKEN_OPAREN: { ast_node_t *expression = parser_parse_expression(parser); diff --git a/test/parser_test.c b/test/parser_test.c index a1614b9..12b2cac 100644 --- a/test/parser_test.c +++ b/test/parser_test.c @@ -131,6 +131,58 @@ test_parse_variable_definition(const MunitParameter params[], void *user_data_or } static MunitResult +test_parse_boolean(const MunitParameter params[], void *user_data_or_fixture) +{ + parser_t parser; + lexer_t lexer; + scope_t *scope = scope_new(); + + make_lexer_from_static_src(&lexer, "fn my_bool_fn(): bool { \nlet variable: bool = true; \nreturn variable;\n }"); + parser_init(&parser, &lexer, scope); + ast_node_t *ast_function = parser_parse_function_declaration(&parser); + + assert_true(ast_function != NULL); + + assert_string_view_equal("my_bool_fn", ast_function->data.function.identifier.name); + assert_int(AST_FUNCTION_DECLARATION, ==, ast_function->kind); + + ast_node_t *ast_variable = vector_at(ast_function->data.function.body, 0); + + assert_int(AST_VARIABLE_DECLARATION, ==, ast_variable->kind); + + assert_string_view_equal("variable", ast_variable->data.variable_declaration.identifier.name); + assert_int(TYPE_BOOL, ==, ast_variable->data.variable_declaration.type); + assert_int(AST_LITERAL, ==, ast_variable->data.variable_declaration.value->kind); + assert_int(AST_LITERAL_BOOL, ==, ast_variable->data.variable_declaration.value->data.literal.kind); + assert_true(ast_variable->data.variable_declaration.value->data.literal.value.boolean); + + ast_node_t *ast_return = vector_at(ast_function->data.function.body, 1); + + assert_int(AST_RETURN_STMT, ==, ast_return->kind); + + ast_node_t *ast_literal = ast_return->data.return_stmt.argument; + + assert_int(AST_VARIABLE, ==, ast_literal->kind); + assert_string_view_equal("variable", ast_literal->data.variable.identifier->name); + + ast_node_destroy(ast_function); + scope_destroy(scope); + + scope = scope_new(); + + make_lexer_from_static_src(&lexer, "fn my_bool_fn(): bool { \nlet variable: bool = false; \nreturn variable;\n }"); + parser_init(&parser, &lexer, scope); + ast_function = parser_parse_function_declaration(&parser); + + assert_true(ast_function != NULL); + ast_node_destroy(ast_function); + + scope_destroy(scope); + + return MUNIT_OK; +} + +static MunitResult test_parse_arithmetic_expression(const MunitParameter params[], void *user_data_or_fixture) { parser_t parser; @@ -225,6 +277,7 @@ test_parse_basic_syntax_errors(const MunitParameter params[], void *user_data_or static MunitTest tests[] = { { "/test_parse_function", test_parse_function, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, + { "/test_parse_boolean", test_parse_boolean, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { "/test_parse_basic_syntax_errors", test_parse_basic_syntax_errors, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { "/test_parse_arithmetic_expression", test_parse_arithmetic_expression, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { "/test_parse_variable_definition", test_parse_variable_definition, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, |