From cb021716ef97d7ec92812e146f248c6d18191cad Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Tue, 2 Dec 2025 21:27:41 +0100 Subject: [PATCH] completed for loop parsing --- lc.c | 9 +-- parser.c | 197 ++++++++++++++++++++++++++++++++++++++----------------- parser.h | 11 ++-- test.c | 16 +---- 4 files changed, 146 insertions(+), 87 deletions(-) diff --git a/lc.c b/lc.c index 3f0f861..7829db1 100644 --- a/lc.c +++ b/lc.c @@ -163,14 +163,9 @@ void print_ast(ast_node *node, int depth) { break; case NODE_FOR: printf("For:\n"); - print_ast(node->expr.fr.range, depth + 1); - print_ast(node->expr.fr.array, depth + 1); + print_ast(node->expr.fr.slices, depth + 1); + print_ast(node->expr.fr.captures, depth + 1); print_indent(depth + 1); - printf("Range capture: %.*s\n", node->expr.fr.rangeCaptureLen, node->expr.fr.rangeCapture); - if (node->expr.fr.arrayCapture) { - print_indent(depth + 1); - printf("Array capture: %.*s\n", node->expr.fr.arrayCaptureLen, node->expr.fr.arrayCapture); - } print_ast(node->expr.fr.body, depth + 1); break; case NODE_RANGE: diff --git a/parser.c b/parser.c index c693e34..b5f70f6 100644 --- a/parser.c +++ b/parser.c @@ -182,6 +182,24 @@ static ast_node *parse_factor(parser *p) ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); node->type = NODE_INTEGER; node->expr.integer = parse_int(t->lexeme, t->lexeme_len); + if (match(p, TOKEN_DOUBLE_DOT)) { + ast_node *range = arena_alloc(p->allocator, sizeof(ast_node)); + range->type = NODE_RANGE; + range->expr.binary.left = node; + range->expr.binary.operator = OP_PLUS; + snapshot snap = arena_snapshot(p->allocator); + ast_node *end = parse_factor(p); + if (!end) { + range->expr.binary.right = NULL; + } else if (end->type != NODE_INTEGER) { + arena_reset_to_snapshot(p->allocator, snap); + error(p, "expected integer."); + return NULL; + } else { + range->expr.binary.right = end; + } + return range; + } return node; } else if (match(p, TOKEN_FLOAT)) @@ -510,77 +528,138 @@ static ast_node *parse_compound(parser *p) return compound; } -static ast_node *parse_double_dot(parser* p) { - ast_node* begin = parse_expression(p); - if (!begin || (begin->type != NODE_INTEGER && begin->type != NODE_BINARY && begin->type != NODE_UNARY)) { - error(p, "Invalid begin range operator."); - return NULL; - } - if (!match(p, TOKEN_DOUBLE_DOT)) { - error(p, "Expected `..`."); - return NULL; - } - ast_node* node = arena_alloc(p->allocator, sizeof(ast_node)); - node->type = NODE_RANGE; - node->expr.binary.left = begin; - node->expr.binary.operator = OP_PLUS; // Always adding 1 - if (p->tokens->type != TOKEN_INTEGER) { - return node; - } - ast_node* end = parse_expression(p); - if (!end || (end->type != NODE_INTEGER && end->type != NODE_BINARY && end->type != NODE_UNARY)) { - error(p, "Invalid end range operator."); - return NULL; - } - node->expr.binary.right = end; - return node; -} - static ast_node *parse_for(parser *p) { advance(p); ast_node* node = arena_alloc(p->allocator, sizeof(ast_node)); node->type = NODE_FOR; - ast_node* range = parse_double_dot(p); - node->expr.fr.range = range; - if (p->tokens->type != TOKEN_RPAREN) { - if (!match(p, TOKEN_COMMA)) { - error(p, "Expected `,` seperating for parameters\n"); - return NULL; + + snapshot arena_start = arena_snapshot(p->allocator); + node->expr.fr.slices = arena_alloc(p->allocator, sizeof(ast_node)); + node->expr.fr.slices->type = NODE_UNIT; + node->expr.fr.slices->expr.unit_node.expr = parse_expression(p); + ast_node *tail = node->expr.fr.slices; + node->expr.fr.slice_len = 1; + + /* In this case, there is only one slice. */ + if (match(p, TOKEN_RPAREN)) + { + goto parse_captures; + } + + if (match(p, TOKEN_COMMA)) + { + ast_node *expr = parse_expression(p); + if (expr) + { + while (!match(p, TOKEN_RPAREN)) + { + if (!match(p, TOKEN_COMMA)) + { + error(p, "expected `)`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node)); + tail->expr.unit_node.next->expr.unit_node.expr = expr; + tail = tail->expr.unit_node.next; + tail->type = NODE_UNIT; + expr = parse_expression(p); + if (!expr) + { + error(p, "expected `)`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + node->expr.fr.slice_len += 1; + } + + tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node)); + tail->expr.unit_node.next->expr.unit_node.expr = expr; + tail = tail->expr.unit_node.next; + tail->type = NODE_UNIT; } - ast_node* array = parse_expression(p); - node->expr.fr.array = array; - } - if (!match(p, TOKEN_RPAREN)) { - error(p, "Expected `)` to close for range\n"); - return NULL; - } - if (p->tokens->type != TOKEN_PIPE) { - goto parseBody; - } - advance(p); - const char* rangeCapture = p->tokens->lexeme; - node->expr.fr.rangeCapture = rangeCapture; - node->expr.fr.rangeCaptureLen = p->tokens->lexeme_len; - if (!match(p, TOKEN_IDENTIFIER)) { - error(p, "Expected range capture to be an identifier\n"); - return NULL; - } - if (p->tokens->type == TOKEN_COMMA) { - advance(p); - const char* arrayCapture = p->tokens->lexeme; - node->expr.fr.arrayCapture = arrayCapture; - node->expr.fr.arrayCaptureLen = p->tokens->lexeme_len; - if (!match(p, TOKEN_IDENTIFIER)) { - error(p, "Expected array capture to be an identifier\n"); + else + { + error(p, "expected expression."); + arena_reset_to_snapshot(p->allocator, arena_start); return NULL; } } + else + { + error(p, "expected `)`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + +parse_captures: + if (!match(p, TOKEN_PIPE)) { - error(p, "Expected `|` to close captures\n"); + error(p, "expected capture."); return NULL; } -parseBody:; + + arena_start = arena_snapshot(p->allocator); + node->expr.fr.captures = arena_alloc(p->allocator, sizeof(ast_node)); + node->expr.fr.captures->type = NODE_UNIT; + node->expr.fr.captures->expr.unit_node.expr = parse_expression(p); + if (node->expr.fr.captures->expr.unit_node.expr && node->expr.fr.captures->expr.unit_node.expr->type != NODE_IDENTIFIER) { + error(p, "captures must be identifiers."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + tail = node->expr.fr.captures; + node->expr.fr.capture_len = 1; + + /* In this case, there is only one capture */ + if (match(p, TOKEN_PIPE)) { + goto parse_body; + } + + if (match(p, TOKEN_COMMA)) { + ast_node *expr = parse_expression(p); + if (expr) { + while (!match(p, TOKEN_PIPE)) { + if (!match(p, TOKEN_COMMA)) { + error(p, "expected `)`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node)); + tail->expr.unit_node.next->expr.unit_node.expr = expr; + tail = tail->expr.unit_node.next; + tail->type = NODE_UNIT; + expr = parse_expression(p); + if (!expr) { + error(p, "expected `|`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + node->expr.fr.capture_len += 1; + } + + tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node)); + tail->expr.unit_node.next->expr.unit_node.expr = expr; + tail = tail->expr.unit_node.next; + tail->type = NODE_UNIT; + } else { + error(p, "expected identifier."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + } else { + error(p, "expected `|`."); + arena_reset_to_snapshot(p->allocator, arena_start); + return NULL; + } + +parse_body:; + if (node->expr.fr.capture_len != node->expr.fr.slice_len) { + error(p, "invalid number of captures."); + return NULL; + } + ast_node* body = parse_compound(p); node->expr.fr.body = body; return node; diff --git a/parser.h b/parser.h index 60ef9e3..999a843 100644 --- a/parser.h +++ b/parser.h @@ -156,12 +156,11 @@ typedef struct _ast_node { struct _ast_node *path; } import; struct { - struct _ast_node *range; - struct _ast_node *array; - const char* rangeCapture; - const char* arrayCapture; - int rangeCaptureLen; - int arrayCaptureLen; + /* These should be lists of unit_node */ + struct _ast_node *slices; + struct _ast_node *captures; + int capture_len; + int slice_len; struct _ast_node* body; } fr; // for struct { diff --git a/test.c b/test.c index 0593e4f..a5b0652 100644 --- a/test.c +++ b/test.c @@ -1,17 +1,3 @@ -//import example.test.idk.idk; - -//hello: -//goto test; -//return 5; - -// loop(0..15) |i| { -// printf("%d\n", i); -// } - -return 6; - -loop (0.., list) |i, v| { +loop (0..1, list, 4..5, test, idk) |i, v, k, e, s| { printf("%d\n", i); } - -return 7; \ No newline at end of file