summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.c23
-rw-r--r--src/ast.h11
-rw-r--r--src/ast_pretty_printer.c25
-rw-r--r--src/gas_assembly_generator.c1
-rw-r--r--src/lexer.c6
-rw-r--r--src/lexer.h1
-rw-r--r--src/parser.c54
7 files changed, 121 insertions, 0 deletions
diff --git a/src/ast.c b/src/ast.c
index 1200e30..5790c05 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -47,6 +47,10 @@ ast_node_destroy(ast_node_t *node)
case AST_FUNCTION_DECLARATION:
ast_node_destroy(node->data.function.body);
break;
+ case AST_IF_STMT:
+ ast_node_destroy(node->data.if_stmt.condition);
+ ast_node_destroy(node->data.if_stmt.body);
+ break;
case AST_BLOCK:
ast_node_destroy_vector(node->data.block.body);
break;
@@ -140,6 +144,25 @@ ast_node_new_literal_integer(uint32_t number)
}
ast_node_t *
+ast_node_new_if_stmt(ast_node_t *condition, ast_node_t *body)
+{
+ ast_node_t *node = ast_node_new();
+
+ *node = (ast_node_t){
+ .kind = AST_IF_STMT,
+ .result_type = TYPE_VOID,
+ .data = {
+ .if_stmt = {
+ .condition = condition,
+ .body = body
+ },
+ },
+ };
+
+ return node;
+}
+
+ast_node_t *
ast_node_new_literal_bool(bool boolean)
{
ast_node_t *node = ast_node_new();
diff --git a/src/ast.h b/src/ast.h
index 1637173..b2c565c 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -111,6 +111,12 @@ typedef struct ast_variable_assignment_t
ast_node_t *expression;
} ast_variable_assignment_t;
+typedef struct ast_if_stmt_t
+{
+ ast_node_t *condition;
+ ast_node_t *body;
+} ast_if_stmt_t;
+
typedef enum
{
AST_BINARY_OPERATION,
@@ -118,6 +124,7 @@ typedef enum
AST_FUNCTION_DECLARATION,
AST_LITERAL,
AST_RETURN_STMT,
+ AST_IF_STMT,
AST_UNKOWN_NODE,
AST_VARIABLE_DECLARATION,
AST_VARIABLE_ASSIGNMENT,
@@ -130,6 +137,7 @@ typedef union
ast_function_declaration_t function;
ast_literal_t literal;
ast_block_t block;
+ ast_if_stmt_t if_stmt;
ast_return_stmt_t return_stmt;
ast_variable_declaration_t variable_declaration;
ast_variable_assignment_t variable_assignment;
@@ -185,4 +193,7 @@ ast_node_new_variable(ast_identifier_t *identifier, type_t result_type);
ast_node_t *
ast_node_new_variable_assignment(ast_identifier_t *identifier, ast_node_t *expression);
+ast_node_t *
+ast_node_new_if_stmt(ast_node_t *condition, ast_node_t *body);
+
#endif /* AST_H */
diff --git a/src/ast_pretty_printer.c b/src/ast_pretty_printer.c
index 718d22a..e2d007a 100644
--- a/src/ast_pretty_printer.c
+++ b/src/ast_pretty_printer.c
@@ -63,6 +63,31 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast)
assert(ast);
switch (ast->kind) {
+ case AST_IF_STMT: {
+ ast_if_stmt_t if_stmt = ast->data.if_stmt;
+ ast_pretty_printer_printf(printer, "IfStmt\n");
+ ast_pretty_printer_add_indentation(printer);
+ {
+ ast_pretty_printer_printf(printer, "condition:\n");
+ ast_pretty_printer_add_indentation(printer);
+ {
+ ast_pretty_printer_set_lst_children(printer);
+ ast_pretty_printer_print_ast(printer, if_stmt.condition);
+
+ ast_pretty_printer_rm_indentation(printer);
+ }
+ ast_pretty_printer_printf(printer, "body:\n");
+ ast_pretty_printer_add_indentation(printer);
+ {
+ ast_pretty_printer_set_lst_children(printer);
+ ast_pretty_printer_print_ast(printer, if_stmt.body);
+
+ ast_pretty_printer_rm_indentation(printer);
+ }
+ ast_pretty_printer_rm_indentation(printer);
+ }
+ break;
+ }
case AST_BINARY_OPERATION: {
ast_binary_operation_t binop = ast->data.binary_operation;
ast_pretty_printer_printf(printer, "BinaryOperation operation='%c'\n", operation_kinds[binop.kind]);
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index 0cce205..4b898ed 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -138,6 +138,7 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast)
case AST_BLOCK:
gas_assembly_generator_compile_block(gen, &ast->data.block);
break;
+ case AST_IF_STMT:
case AST_UNKOWN_NODE:
assert(false && "unreachable");
}
diff --git a/src/lexer.c b/src/lexer.c
index f84163d..a6c8ae2 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -111,6 +111,10 @@ lexer_token_process_keyword(token_t *token)
token->kind = TOKEN_KEYWORD_FN;
return;
}
+ if (string_view_eq(string_view_from_str("if"), token->value)) {
+ token->kind = TOKEN_KEYWORD_IF;
+ return;
+ }
if (string_view_eq(string_view_from_str("true"), token->value)) {
token->kind = TOKEN_TRUE;
return;
@@ -462,6 +466,8 @@ token_kind_to_str(token_kind_t kind)
return "fn";
case TOKEN_KEYWORD_LET:
return "let";
+ case TOKEN_KEYWORD_IF:
+ return "if";
case TOKEN_TRUE:
return "true";
case TOKEN_FALSE:
diff --git a/src/lexer.h b/src/lexer.h
index 899c0aa..0e36ada 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -59,6 +59,7 @@ typedef enum
TOKEN_KEYWORD_RETURN,
TOKEN_KEYWORD_FN,
TOKEN_KEYWORD_LET,
+ TOKEN_KEYWORD_IF,
TOKEN_TRUE,
TOKEN_FALSE,
diff --git a/src/parser.c b/src/parser.c
index 848bb4a..9167f1e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -30,6 +30,9 @@
static bool
parser_expression_matches_the_expected_type(parser_t *parser, ast_node_t *expression, type_t type, token_t token);
+static ast_node_t *
+parser_parse_block_declarations(parser_t *parser, type_t result_type);
+
void
parser_init(parser_t *parser, lexer_t *lexer, scope_t *scope)
{
@@ -463,6 +466,35 @@ parser_parse_variable_declaration(parser_t *parser)
return node;
}
+static ast_node_t *
+parser_parse_if_stmt(parser_t *parser, type_t result_type)
+{
+ token_t if_token;
+ if (!expected_token(&if_token, parser, TOKEN_KEYWORD_IF)) {
+ return NULL;
+ }
+
+ ast_node_t *condition = parser_parse_expression(parser);
+
+ if (condition == NULL) {
+ return NULL;
+ }
+
+ if (!parser_expression_matches_the_expected_type(parser, condition, TYPE_BOOL, if_token)) {
+ ast_node_destroy(condition);
+ return NULL;
+ }
+
+ ast_node_t *body = parser_parse_block_declarations(parser, result_type);
+
+ if (body == NULL) {
+ ast_node_destroy(condition);
+ return NULL;
+ }
+
+ return ast_node_new_if_stmt(condition, body);
+}
+
static bool
is_next_statement_a_variable_declaration(parser_t *parser)
{
@@ -488,6 +520,15 @@ is_next_statement_a_variable_assignement(parser_t *parser)
}
static bool
+is_next_statement_a_if_stmt(parser_t *parser)
+{
+ token_t token;
+ lexer_peek_next_token(parser->lexer, &token);
+
+ return token.kind == TOKEN_KEYWORD_IF;
+}
+
+static bool
is_next_statement_return(parser_t *parser)
{
token_t token;
@@ -563,6 +604,19 @@ parser_parse_block_declarations(parser_t *parser, type_t result_type)
continue;
}
+ if (is_next_statement_a_if_stmt(parser)) {
+ ast_node_t *if_stmt = parser_parse_if_stmt(parser, result_type);
+
+ if (if_stmt == NULL) {
+ scope_leave(parser->scope);
+ ast_node_destroy_vector(body);
+ return NULL;
+ }
+
+ vector_push_back(body, if_stmt);
+ continue;
+ }
+
if (is_next_statement_a_variable_declaration(parser)) {
ast_node_t *variable_node = parser_parse_variable_declaration(parser);