about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-05-31 23:56:35 +0200
committerMel <mel@rnrd.eu>2025-05-31 23:56:35 +0200
commitef66c99536a631ff2bd1dab4a825ce16d2efa530 (patch)
treed1f2b12d53b3f670b694011f5b6a8077b92762f5
parent43b8623ad8323ac73f40908f0fae9f57aa906f39 (diff)
downloadcatskill-ef66c99536a631ff2bd1dab4a825ce16d2efa530.tar.zst
catskill-ef66c99536a631ff2bd1dab4a825ce16d2efa530.zip
Parse blocks of statements as node
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/parse.c79
-rw-r--r--boot/tree.c27
2 files changed, 88 insertions, 18 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 5d3b26c..5bfa006 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -9,6 +9,10 @@
     parse;           \
     if (!parser_error_is_none(error)) return nil;
 
+#define CHECK_RETURN(parse, ret) \
+    parse;                       \
+    if (!parser_error_is_none(error)) return (ret){ 0 };
+
 struct Parser_Error
 {
     enum Parser_Error_Kind
@@ -162,8 +166,52 @@ parser_probe(struct Parser* p, enum Token_Kind kind)
     return token_is(&token, kind);
 }
 
+struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error);
 struct Expression* parser_expression(struct Parser* p, struct Parser_Error* error);
 
+void
+parser_end_statement(struct Parser* p, struct Parser_Error* error)
+{
+    struct Token token = parser_peek(p);
+    if (!token_ends_statement(&token)) {
+        *error = parser_error(PARSER_ERROR_EXPECTED_STATEMENT_END);
+        return;
+    }
+    parser_next(p);
+}
+
+struct Block_Node
+parser_block_node(struct Parser* p, struct Parser_Error* error)
+{
+    struct Token start_token =
+        CHECK_RETURN(parser_need(p, TOKEN_CURLY_OPEN, error), struct Block_Node);
+
+    struct Statement* head = nil;
+    struct Statement* current = nil;
+
+    while (!parser_probe(p, TOKEN_CURLY_CLOSE)) {
+        struct Statement* statement = CHECK_RETURN(parser_statement(p, error), struct Block_Node);
+        CHECK_RETURN(parser_end_statement(p, error), struct Block_Node);
+
+        if (!head) {
+            head = statement;
+        } else {
+            current->next = statement;
+        }
+        current = statement;
+    }
+
+    struct Token end_token =
+        CHECK_RETURN(parser_need(p, TOKEN_CURLY_CLOSE, error), struct Block_Node);
+    struct Span span = span_merge(start_token.span, end_token.span);
+
+    return (struct Block_Node){
+        .statements = head,
+        .span = span,
+        .location = start_token.location,
+    };
+}
+
 struct Type_Node
 parser_node_type(struct Parser* p, struct Parser_Error* error)
 {
@@ -482,17 +530,6 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error)
     return statement_new(STATEMENT_DECLARATION, value, span, location);
 }
 
-void
-parser_end_statement(struct Parser* p, struct Parser_Error* error)
-{
-    struct Token token = parser_peek(p);
-    if (!token_ends_statement(&token)) {
-        *error = parser_error(PARSER_ERROR_EXPECTED_STATEMENT_END);
-        return;
-    }
-    parser_next(p);
-}
-
 struct Statement*
 parser_statement(struct Parser* p, struct Parser_Error* error)
 {
@@ -504,7 +541,7 @@ parser_statement(struct Parser* p, struct Parser_Error* error)
         token = parser_peek(p);
     }
 
-    if (token.kind == TOKEN_NAME) {
+    if (token_is(&token, TOKEN_NAME)) {
         // NOTE: these can be a variable declaration:
         //     x uint = 123
         //     me, them Obj = create()
@@ -516,6 +553,14 @@ parser_statement(struct Parser* p, struct Parser_Error* error)
             return parser_statement_declaration(p, error);
     }
 
+    if (token_is(&token, TOKEN_CURLY_OPEN)) {
+        // a block statement.
+        struct Block_Node block = CHECK(parser_block_node(p, error));
+        return statement_new(
+            STATEMENT_BLOCK, (union Statement_Value){ .block = { block } }, block.span,
+            block.location);
+    }
+
     struct Expression* expression = CHECK(parser_expression(p, error));
 
     // expand by one byte to include the statement terminator.
@@ -533,11 +578,8 @@ parser_do_your_thing(struct Parser* p, struct Parser_Error* error)
 
     struct Statement* current = nil;
     while (!p->lexer->eof) {
-        struct Statement* next = parser_statement(p, error);
-        if (!parser_error_is_none(error)) return (struct Tree){ nil };
-
-        parser_end_statement(p, error);
-        if (!parser_error_is_none(error)) return (struct Tree){ nil };
+        struct Statement* next = CHECK_RETURN(parser_statement(p, error), struct Tree);
+        CHECK_RETURN(parser_end_statement(p, error), struct Tree);
 
         if (current) {
             current->next = next;
@@ -551,4 +593,5 @@ parser_do_your_thing(struct Parser* p, struct Parser_Error* error)
     return (struct Tree){ head };
 }
 
-#undef CHECK
\ No newline at end of file
+#undef CHECK
+#undef CHECK_RETURN
\ No newline at end of file
diff --git a/boot/tree.c b/boot/tree.c
index 1d88743..7dd6447 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -326,6 +326,15 @@ binary_operation_to_string(enum Binary_Operation operation)
 // nodes are parts of the syntax tree that are reused often
 // and in different places.
 
+// a block of code, enclosed in curly braces.
+// represents a sequence of statements that are executed in order.
+struct Block_Node
+{
+    struct Statement* statements;
+    struct Span span;
+    struct Cursor location;
+};
+
 // a type node represents a type in the syntax tree.
 // currently, we only support types that are simple names.
 struct Type_Node
@@ -538,6 +547,8 @@ enum Statement_Kind
     STATEMENT_NONE,
     STATEMENT_EXPRESSION,
     STATEMENT_DECLARATION,
+    // NOTE: a block could be an expression in the future.
+    STATEMENT_BLOCK,
 };
 
 struct Statement_Value_Expression
@@ -554,10 +565,16 @@ struct Statement_Value_Declaration
     struct Type_Node type; // the type of the variable, if any.
 };
 
+struct Statement_Value_Block
+{
+    struct Block_Node inner; // the block of statements.
+};
+
 union Statement_Value
 {
     struct Statement_Value_Expression expression;
     struct Statement_Value_Declaration declaration;
+    struct Statement_Value_Block block;
 };
 
 struct Statement
@@ -621,6 +638,16 @@ statement_print(const struct Statement* statement)
         printf(")");
         break;
     }
+    case STATEMENT_BLOCK:
+        printf("(block \n");
+        FOR_EACH(struct Statement*, sub_statement, statement->value.block.inner.statements)
+        {
+            printf("\t");
+            statement_print(sub_statement);
+            printf("\n");
+        }
+        printf(")");
+        break;
     default:
         failure("unexpected statement kind passed to `statement_print`");
         break;