completed for loop parsing

This commit is contained in:
Lorenzo Torres 2025-12-02 21:27:41 +01:00
parent 0015c2b81d
commit cb021716ef
4 changed files with 146 additions and 87 deletions

9
lc.c
View file

@ -163,14 +163,9 @@ void print_ast(ast_node *node, int depth) {
break; break;
case NODE_FOR: case NODE_FOR:
printf("For:\n"); printf("For:\n");
print_ast(node->expr.fr.range, depth + 1); print_ast(node->expr.fr.slices, depth + 1);
print_ast(node->expr.fr.array, depth + 1); print_ast(node->expr.fr.captures, depth + 1);
print_indent(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); print_ast(node->expr.fr.body, depth + 1);
break; break;
case NODE_RANGE: case NODE_RANGE:

197
parser.c
View file

@ -182,6 +182,24 @@ static ast_node *parse_factor(parser *p)
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_INTEGER; node->type = NODE_INTEGER;
node->expr.integer = parse_int(t->lexeme, t->lexeme_len); 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; return node;
} }
else if (match(p, TOKEN_FLOAT)) else if (match(p, TOKEN_FLOAT))
@ -510,77 +528,138 @@ static ast_node *parse_compound(parser *p)
return compound; 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) static ast_node *parse_for(parser *p)
{ {
advance(p); advance(p);
ast_node* node = arena_alloc(p->allocator, sizeof(ast_node)); ast_node* node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_FOR; node->type = NODE_FOR;
ast_node* range = parse_double_dot(p);
node->expr.fr.range = range; snapshot arena_start = arena_snapshot(p->allocator);
if (p->tokens->type != TOKEN_RPAREN) { node->expr.fr.slices = arena_alloc(p->allocator, sizeof(ast_node));
if (!match(p, TOKEN_COMMA)) { node->expr.fr.slices->type = NODE_UNIT;
error(p, "Expected `,` seperating for parameters\n"); node->expr.fr.slices->expr.unit_node.expr = parse_expression(p);
return NULL; 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); else
node->expr.fr.array = array; {
} error(p, "expected expression.");
if (!match(p, TOKEN_RPAREN)) { arena_reset_to_snapshot(p->allocator, arena_start);
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");
return NULL; return NULL;
} }
} }
else
{
error(p, "expected `)`.");
arena_reset_to_snapshot(p->allocator, arena_start);
return NULL;
}
parse_captures:
if (!match(p, TOKEN_PIPE)) { if (!match(p, TOKEN_PIPE)) {
error(p, "Expected `|` to close captures\n"); error(p, "expected capture.");
return NULL; 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); ast_node* body = parse_compound(p);
node->expr.fr.body = body; node->expr.fr.body = body;
return node; return node;

View file

@ -156,12 +156,11 @@ typedef struct _ast_node {
struct _ast_node *path; struct _ast_node *path;
} import; } import;
struct { struct {
struct _ast_node *range; /* These should be lists of unit_node */
struct _ast_node *array; struct _ast_node *slices;
const char* rangeCapture; struct _ast_node *captures;
const char* arrayCapture; int capture_len;
int rangeCaptureLen; int slice_len;
int arrayCaptureLen;
struct _ast_node* body; struct _ast_node* body;
} fr; // for } fr; // for
struct { struct {

16
test.c
View file

@ -1,17 +1,3 @@
//import example.test.idk.idk; loop (0..1, list, 4..5, test, idk) |i, v, k, e, s| {
//hello:
//goto test;
//return 5;
// loop(0..15) |i| {
// printf("%d\n", i);
// }
return 6;
loop (0.., list) |i, v| {
printf("%d\n", i); printf("%d\n", i);
} }
return 7;