aboutsummaryrefslogtreecommitdiff
path: root/boot
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 /boot
parent43b8623ad8323ac73f40908f0fae9f57aa906f39 (diff)
downloadcatskill-ef66c99536a631ff2bd1dab4a825ce16d2efa530.tar.zst
catskill-ef66c99536a631ff2bd1dab4a825ce16d2efa530.zip
Parse blocks of statements as node
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
-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;