summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-08 23:53:41 -0300
committerJohnny Richard <johnny@johnnyrichard.com>2023-05-09 08:50:53 +0200
commitaba7302e7e98fd7bca2056d8ad622d9ca81c495f (patch)
tree59b4de4d4946f622b97ca7b6e1ded4d1e9cebbe5
parentccd5e8585f10488eed72c772cc1804efea6b8fb4 (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.c18
-rw-r--r--src/ast.h10
-rw-r--r--src/ast_pretty_printer.c5
-rw-r--r--src/lexer.c12
-rw-r--r--src/lexer.h2
-rw-r--r--src/parser.c15
-rw-r--r--test/parser_test.c53
7 files changed, 113 insertions, 2 deletions
diff --git a/src/ast.c b/src/ast.c
index 5938e1d..8a46034 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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();
diff --git a/src/ast.h b/src/ast.h
index 69fc918..80148dc 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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 },