public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
From: Johnny Richard <johnny@johnnyrichard.com>
To: ~johnnyrichard/olang-devel@lists.sr.ht
Cc: Johnny Richard <johnny@johnnyrichard.com>
Subject: [PATCH olang v1] parser: add support for parsing while-statements
Date: Tue,  8 Oct 2024 23:33:05 +0200	[thread overview]
Message-ID: <20241008213319.239796-1-johnny@johnnyrichard.com> (raw)

Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
 src/ast.c                         | 14 +++++++++++
 src/ast.h                         | 12 ++++++++++
 src/checker.c                     |  7 ++++++
 src/codegen_linux_x86_64.c        | 25 ++++++++++++++++++++
 src/parser.c                      | 39 +++++++++++++++++++++++++++++++
 src/pretty_print_ast.c            | 14 +++++++++++
 tests/olc/0030_while_statement.ol | 20 ++++++++++++----
 7 files changed, 127 insertions(+), 4 deletions(-)

diff --git a/src/ast.c b/src/ast.c
index 531415c..d6ec70c 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -186,6 +186,20 @@ ast_new_node_if_stmt(arena_t *arena, token_loc_t loc, ast_node_t *cond, ast_node
     return node_if_stmt;
 }
 
+ast_node_t *
+ast_new_node_while_stmt(arena_t *arena, token_loc_t loc, ast_node_t *cond, ast_node_t *then)
+{
+    ast_node_t *node_while_stmt = arena_alloc(arena, sizeof(ast_node_t));
+    assert(node_while_stmt);
+
+    node_while_stmt->kind = AST_NODE_WHILE_STMT;
+    node_while_stmt->loc = loc;
+    node_while_stmt->as_while_stmt.cond = cond;
+    node_while_stmt->as_while_stmt.then = then;
+
+    return node_while_stmt;
+}
+
 ast_node_t *
 ast_new_node_block(arena_t *arena)
 {
diff --git a/src/ast.h b/src/ast.h
index dce7cd8..238435e 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -39,6 +39,7 @@ typedef enum
     AST_NODE_VAR_ASSIGN_STMT,
     AST_NODE_RETURN_STMT,
     AST_NODE_IF_STMT,
+    AST_NODE_WHILE_STMT,
     AST_NODE_LITERAL,
     AST_NODE_REF,
     AST_NODE_UNKNOWN
@@ -168,6 +169,13 @@ typedef struct ast_if_stmt
     ast_node_t *_else;
 } ast_if_stmt_t;
 
+typedef struct ast_while_stmt
+{
+    ast_node_meta_t meta;
+    ast_node_t *cond;
+    ast_node_t *then;
+} ast_while_stmt_t;
+
 typedef union ast_node
 {
     // inlined ast_node_meta_t struct.
@@ -187,6 +195,7 @@ typedef union ast_node
     ast_var_assign_stmt_t as_var_assign_stmt;
     ast_return_stmt_t as_return_stmt;
     ast_if_stmt_t as_if_stmt;
+    ast_while_stmt_t as_while_stmt;
 } ast_node_t;
 
 ast_node_t *
@@ -224,6 +233,9 @@ ast_new_node_return_stmt(arena_t *arena, token_loc_t loc, ast_node_t *expr);
 ast_node_t *
 ast_new_node_if_stmt(arena_t *arena, token_loc_t loc, ast_node_t *cond, ast_node_t *then, ast_node_t *_else);
 
+ast_node_t *
+ast_new_node_while_stmt(arena_t *arena, token_loc_t loc, ast_node_t *cond, ast_node_t *then);
+
 ast_node_t *
 ast_new_node_block(arena_t *arena);
 
diff --git a/src/checker.c b/src/checker.c
index 4523b79..36202bd 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -109,6 +109,13 @@ populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast)
             return;
         }
 
+        case AST_NODE_WHILE_STMT: {
+            populate_scope(checker, scope, ast->as_while_stmt.cond);
+            populate_scope(checker, scope, ast->as_while_stmt.then);
+
+            return;
+        }
+
         case AST_NODE_BINARY_OP: {
             ast_binary_op_t bin_op = ast->as_bin_op;
 
diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index ebda8eb..5749e65 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -627,6 +627,31 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block)
 
                 break;
             }
+
+            case AST_NODE_WHILE_STMT: {
+                ast_while_stmt_t while_stmt = node->as_while_stmt;
+
+                ast_node_t *cond = while_stmt.cond;
+                ast_node_t *then = while_stmt.then;
+
+                size_t begin_label = codegen_linux_x86_64_get_next_label(codegen);
+                size_t end_label = codegen_linux_x86_64_get_next_label(codegen);
+
+                fprintf(codegen->out, ".L%ld:\n", begin_label);
+                codegen_linux_x86_64_emit_expression(codegen, cond);
+                fprintf(codegen->out, "    cmp $1, %%rax\n");
+                fprintf(codegen->out, "    jnz .L%ld\n", end_label);
+
+                assert(then->kind == AST_NODE_BLOCK && "invalid while-then block");
+                ast_block_t then_block = then->as_block;
+
+                codegen_linux_x86_64_emit_block(codegen, &then_block);
+
+                fprintf(codegen->out, "    jmp .L%ld\n", begin_label);
+                fprintf(codegen->out, ".L%ld:\n", end_label);
+
+                break;
+            }
             default: {
                 // FIXME: improve error: replace the node->kind to a string representation
                 fprintf(stderr, "node kind %d not supported\n", node->kind);
diff --git a/src/parser.c b/src/parser.c
index 94e8a1e..d498ea5 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -46,6 +46,9 @@ parser_parse_return_stmt(parser_t *parser);
 static ast_node_t *
 parser_parse_if_stmt(parser_t *parser);
 
+static ast_node_t *
+parser_parse_while_stmt(parser_t *parser);
+
 static ast_node_t *
 parser_parse_var_def(parser_t *parser);
 
@@ -471,6 +474,10 @@ StartLoop:
             node = parser_parse_if_stmt(parser);
             break;
         }
+        case TOKEN_WHILE: {
+            node = parser_parse_while_stmt(parser);
+            break;
+        }
         case TOKEN_VAR: {
             node = parser_parse_var_def(parser);
             break;
@@ -580,6 +587,38 @@ parser_parse_if_stmt(parser_t *parser)
     return node_if_stmt;
 }
 
+static ast_node_t *
+parser_parse_while_stmt(parser_t *parser)
+{
+    token_t token_while;
+    if (!expected_next_token(parser, &token_while, TOKEN_WHILE)) {
+        return NULL;
+    }
+
+    ast_node_t *cond = parser_parse_expr(parser);
+
+    if (cond == NULL) {
+        return NULL;
+    }
+
+    skip_line_feeds(parser->lexer);
+
+    ast_node_t *then = parser_parse_block(parser);
+
+    if (then == NULL) {
+        return NULL;
+    }
+
+    token_t next_token;
+    peek_next_non_lf_token(parser->lexer, &next_token);
+
+    ast_node_t *node_while_stmt = ast_new_node_while_stmt(parser->arena, token_while.loc, cond, then);
+
+    assert(node_while_stmt);
+
+    return node_while_stmt;
+}
+
 static ast_node_t *
 parser_parse_var_def(parser_t *parser)
 {
diff --git a/src/pretty_print_ast.c b/src/pretty_print_ast.c
index 3282166..0c5d2d5 100644
--- a/src/pretty_print_ast.c
+++ b/src/pretty_print_ast.c
@@ -237,6 +237,20 @@ ast_node_to_pretty_print_node(ast_node_t *ast, arena_t *arena)
 
             return node;
         }
+        case AST_NODE_WHILE_STMT: {
+            pretty_print_node_t *node = pretty_print_node_new(arena);
+            ast_while_stmt_t while_stmt = ast->as_while_stmt;
+
+            node->name = "While_Statement";
+
+            pretty_print_node_t *child = ast_node_to_pretty_print_node(while_stmt.cond, arena);
+            list_append(node->children, child);
+
+            child = ast_node_to_pretty_print_node(while_stmt.then, arena);
+            list_append(node->children, child);
+
+            return node;
+        }
         case AST_NODE_LITERAL: {
             pretty_print_node_t *node = pretty_print_node_new(arena);
             ast_literal_t literal = ast->as_literal;
diff --git a/tests/olc/0030_while_statement.ol b/tests/olc/0030_while_statement.ol
index 1ebdc5a..0eca528 100644
--- a/tests/olc/0030_while_statement.ol
+++ b/tests/olc/0030_while_statement.ol
@@ -23,16 +23,28 @@ fn main(): u32 {
   return i
 }
 
-# XTEST test_compile(exit_code=0)
+# TEST test_compile(exit_code=0)
 #
-# XTEST test_run_binary(exit_code=9)
+# TEST test_run_binary(exit_code=10)
 #
-# XTEST test_ast WITH
+# TEST test_ast WITH
 # Translation_Unit
 # `-Function_Definition <name:main> <return:u32>
 #   `-Block
+#     |-Var_Definition <name:i> <kind:u32>
+#     | `-Literal <kind:u32> <value:0>
+#     |-While_Statement
+#     | |-Binary_Operation (<)
+#     | | |-Reference <name:i>
+#     | | `-Literal <kind:u32> <value:10>
+#     | `-Block
+#     |   `-Var_Assigment
+#     |     |-Reference <name:i>
+#     |     `-Binary_Operation (+)
+#     |       |-Reference <name:i>
+#     |       `-Literal <kind:u32> <value:1>
 #     `-Return_Statement
-#       `-Literal <kind:u32> <value:0>
+#       `-Reference <name:i>
 # END
 #
 # TEST test_contains_tokens WITH

base-commit: f0a565d7d551df220c7b8ae0b924245dd70c9468
-- 
2.46.0


             reply	other threads:[~2024-10-08 19:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-08 21:33 Johnny Richard [this message]
2024-10-08 19:34 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-10-08 22:49 ` [PATCH olang v1] parser: add support for parsing while-statements Carlos Maniero
2024-10-09 14:55   ` Johnny Richard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241008213319.239796-1-johnny@johnnyrichard.com \
    --to=johnny@johnnyrichard.com \
    --cc=~johnnyrichard/olang-devel@lists.sr.ht \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.johnnyrichard.com/olang.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox