public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
* [PATCH olang v1] parser: codegen(x86_64): docs: implement else if
@ 2024-10-09 11:28 Johnny Richard
  2024-10-09  9:29 ` [olang/patches/.build.yml] build success builds.sr.ht
  2024-10-09  9:32 ` [PATCH olang v1] parser: codegen(x86_64): docs: implement else if Carlos Maniero
  0 siblings, 2 replies; 3+ messages in thread
From: Johnny Richard @ 2024-10-09 11:28 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard

Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
 docs/info/getting-started.texi |  2 +
 docs/info/specification.texi   |  2 +-
 src/codegen_linux_x86_64.c     | 67 ++++++++++++++++++++--------------
 src/parser.c                   |  8 +++-
 tests/olc/0032_else_if.ol      | 50 +++++++++++++++++++++++++
 5 files changed, 99 insertions(+), 30 deletions(-)
 create mode 100644 tests/olc/0032_else_if.ol

diff --git a/docs/info/getting-started.texi b/docs/info/getting-started.texi
index 394b266..a68f5b1 100644
--- a/docs/info/getting-started.texi
+++ b/docs/info/getting-started.texi
@@ -71,6 +71,8 @@ Any non zero expr is true.
 @verbatim
 if expr {
   # statement
+} else if expr {
+  # statement
 } else {
   # statement
 }
diff --git a/docs/info/specification.texi b/docs/info/specification.texi
index 1bac50f..6caaac8 100644
--- a/docs/info/specification.texi
+++ b/docs/info/specification.texi
@@ -42,7 +42,7 @@ language.
 <function-args>       ::= <expression> (<ows> ',' <function-args>)*
 <function-call>       ::= <function-name> <ows> '(' ( <ows> | <ows> <function-args> <ows> ) ')'
 <statement>           ::= <common-statement> | <if-statement> | <while-statement> | <return-statement> | <function-call>
-<if-statement>        ::= 'if' <ws> <expression> <ows> <block>
+<if-statement>        ::= 'if' <ws> <expression> <ows> <block> ( <ows> 'else' ( <ows> <block> | <ows> <if-statement> ) )?
 <while-statement>     ::= 'while' <ws> <expression> <ows> <block>
 <return-statement>    ::= 'return' <ws> <expression>
 
diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index 5749e65..10005b9 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -66,6 +66,9 @@ codegen_linux_x86_64_emit_start_entrypoint(codegen_x86_64_t *codegen);
 static void
 codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_t *fn);
 
+static void
+codegen_linux_x86_64_emit_if(codegen_x86_64_t *codegen, ast_if_stmt_t is_stmt);
+
 static void
 codegen_linux_x86_64_put_stack_offset(codegen_x86_64_t *codegen, symbol_t *symbol, size_t offset);
 
@@ -597,34 +600,7 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block)
             }
 
             case AST_NODE_IF_STMT: {
-                ast_if_stmt_t if_stmt = node->as_if_stmt;
-
-                ast_node_t *cond = if_stmt.cond;
-                ast_node_t *then = if_stmt.then;
-                ast_node_t *_else = if_stmt._else;
-
-                size_t end_if_label = codegen_linux_x86_64_get_next_label(codegen);
-                size_t end_else_label = codegen_linux_x86_64_get_next_label(codegen);
-
-                codegen_linux_x86_64_emit_expression(codegen, cond);
-                fprintf(codegen->out, "    cmp $1, %%rax\n");
-                fprintf(codegen->out, "    jnz .L%ld\n", end_if_label);
-
-                assert(then->kind == AST_NODE_BLOCK && "invalid if-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", end_else_label);
-
-                fprintf(codegen->out, ".L%ld:\n", end_if_label);
-
-                if (_else != NULL) {
-                    ast_block_t else_block = _else->as_block;
-                    codegen_linux_x86_64_emit_block(codegen, &else_block);
-                }
-
-                fprintf(codegen->out, ".L%ld:\n", end_else_label);
-
+                codegen_linux_x86_64_emit_if(codegen, node->as_if_stmt);
                 break;
             }
 
@@ -664,6 +640,41 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block)
     codegen->base_offset = block_offset;
 }
 
+static void
+codegen_linux_x86_64_emit_if(codegen_x86_64_t *codegen, ast_if_stmt_t if_stmt)
+{
+    ast_node_t *cond = if_stmt.cond;
+    ast_node_t *then = if_stmt.then;
+    ast_node_t *_else = if_stmt._else;
+
+    size_t end_if_label = codegen_linux_x86_64_get_next_label(codegen);
+    size_t end_else_label = codegen_linux_x86_64_get_next_label(codegen);
+
+    codegen_linux_x86_64_emit_expression(codegen, cond);
+    fprintf(codegen->out, "    cmp $1, %%rax\n");
+    fprintf(codegen->out, "    jnz .L%ld\n", end_if_label);
+
+    assert(then->kind == AST_NODE_BLOCK && "invalid if-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", end_else_label);
+
+    fprintf(codegen->out, ".L%ld:\n", end_if_label);
+
+    if (_else != NULL) {
+        if (_else->kind == AST_NODE_IF_STMT) {
+            ast_if_stmt_t else_if = _else->as_if_stmt;
+            codegen_linux_x86_64_emit_if(codegen, else_if);
+        } else {
+            ast_block_t else_block = _else->as_block;
+            codegen_linux_x86_64_emit_block(codegen, &else_block);
+        }
+    }
+
+    fprintf(codegen->out, ".L%ld:\n", end_else_label);
+}
+
 static size_t
 type_to_bytes(type_t *type)
 {
diff --git a/src/parser.c b/src/parser.c
index d498ea5..5d6290b 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -573,7 +573,13 @@ parser_parse_if_stmt(parser_t *parser)
         lexer_next_token(parser->lexer, &next_token);
         skip_line_feeds(parser->lexer);
 
-        _else = parser_parse_block(parser);
+        lexer_peek_next(parser->lexer, &next_token);
+
+        if (next_token.kind == TOKEN_IF) {
+            _else = parser_parse_if_stmt(parser);
+        } else {
+            _else = parser_parse_block(parser);
+        }
 
         if (_else == NULL) {
             return NULL;
diff --git a/tests/olc/0032_else_if.ol b/tests/olc/0032_else_if.ol
new file mode 100644
index 0000000..6260838
--- /dev/null
+++ b/tests/olc/0032_else_if.ol
@@ -0,0 +1,50 @@
+# Copyright (C) 2024 olang mantainers
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+fn main(): u32
+{
+  if 0 != 0 {
+    return 1
+  } else if 1 == 1 {
+    return 0
+  }
+  return 1
+}
+
+# XTEST test_compile(exit_code=0)
+
+# XTEST test_run_binary(exit_code=0)
+
+# TEST test_ast WITH
+# Translation_Unit
+# `-Function_Definition <name:main> <return:u32>
+#   `-Block
+#     |-If_Statement
+#     | |-Binary_Operation (!=)
+#     | | |-Literal <kind:u32> <value:0>
+#     | | `-Literal <kind:u32> <value:0>
+#     | |-Block
+#     | | `-Return_Statement
+#     | |   `-Literal <kind:u32> <value:1>
+#     | `-If_Statement
+#     |   |-Binary_Operation (==)
+#     |   | |-Literal <kind:u32> <value:1>
+#     |   | `-Literal <kind:u32> <value:1>
+#     |   `-Block
+#     |     `-Return_Statement
+#     |       `-Literal <kind:u32> <value:0>
+#     `-Return_Statement
+#       `-Literal <kind:u32> <value:1>
+# END

base-commit: 55edba3a0a62d33556e3366c49cd7ce5beab6665
-- 
2.46.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-10-09  9:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-09 11:28 [PATCH olang v1] parser: codegen(x86_64): docs: implement else if Johnny Richard
2024-10-09  9:29 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-10-09  9:32 ` [PATCH olang v1] parser: codegen(x86_64): docs: implement else if Carlos Maniero

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