for each wip

This commit is contained in:
David Gonzalez Martin 2025-04-18 19:18:18 -06:00
parent 8bef7f8bd0
commit d20dbd02a8
2 changed files with 128 additions and 1 deletions

View File

@ -616,12 +616,20 @@ pub const Statement = struct {
expression: *Value,
@"if": If,
@"while": While,
for_each: ForEach,
@"switch": Switch,
block: *LexicalBlock,
},
line: u32,
column: u32,
const ForEach = struct {
left_values: []const []const u8,
right_values: []const *Value,
predicate: *Statement,
scope: Scope,
};
const Assignment = struct {
left: *Value,
right: *Value,
@ -980,6 +988,7 @@ pub const Scope = struct {
global,
function,
local,
for_each,
};
};
@ -1639,6 +1648,7 @@ pub const Module = struct {
@"return",
@"if",
// TODO: make `unreachable` a statement start keyword?
@"for",
@"while",
@"switch",
};
@ -2286,7 +2296,7 @@ pub const Module = struct {
return result.?;
}
fn parse_statement(module: *Module, function: *Global, block: *LexicalBlock) *Statement {
fn parse_statement(module: *Module, function: *Global, scope: *Scope) *Statement {
const statement_line = module.get_line();
const statement_column = module.get_column();
@ -2404,6 +2414,86 @@ pub const Module = struct {
},
};
},
.@"for" => {
module.skip_space();
module.expect_character(left_parenthesis);
module.skip_space();
var name_buffer: [64][]const u8 = undefined;
var left_value_count: u64 = 0;
while (true) {
module.skip_space();
const is_left = switch (module.content[module.offset]) {
'&' => true,
else => false,
};
module.offset += @intFromBool(is_left);
if (is_identifier_start_ch(module.content[module.offset])) {
const identifier = module.parse_identifier();
name_buffer[left_value_count] = identifier;
left_value_count += 1;
} else {
@trap();
}
module.skip_space();
if (!module.consume_character_if_match(',')) {
module.expect_character(':');
break;
}
}
module.skip_space();
var right_value_buffer: [64]*Value = undefined;
var right_value_count: u64 = 0;
while (true) {
module.skip_space();
const identifier = module.parse_value(function, .{});
right_value_buffer[right_value_count] = identifier;
right_value_count += 1;
module.skip_space();
if (!module.consume_character_if_match(',')) {
module.expect_character(right_parenthesis);
break;
}
}
module.skip_space();
if (left_value_count != right_value_count) {
module.report_error();
}
const left_values = module.arena.allocate([]const u8, left_value_count);
@memcpy(left_values, name_buffer[0..left_value_count]);
const right_values = module.arena.allocate(*Value, right_value_count);
@memcpy(right_values, right_value_buffer[0..right_value_count]);
const predicate = module.parse_statement(function, block);
break :blk .{
.for_each = .{
.left_values = left_values,
.right_values = right_values,
.predicate = predicate,
.scope = .{
.line = statement_line,
.column = statement_column,
.kind = .for_each,
.parent = &block.scope,
},
},
};
},
.@"switch" => {
module.skip_space();
module.expect_character(left_parenthesis);
@ -2732,6 +2822,9 @@ pub const Module = struct {
}
assert(scope.parent != null);
},
.for_each => {
@trap();
},
}
} else {
module.report_error();
@ -7102,6 +7195,10 @@ pub const Module = struct {
}
},
.block => |child_block| module.analyze_block(function, child_block),
.for_each => |for_loop| {
_ = for_loop;
@trap();
},
}
}

30
tests/for_each.bbb Normal file
View File

@ -0,0 +1,30 @@
require = fn (ok: u1) void
{
if (!ok) #trap();
}
[export] main = fn [cc(c)] () s32
{
>array: [_]u32 = [5, 3, 2];
>counter: u32 = 0;
for (e : array)
{
counter += e;
}
require(counter == 10);
//for (&e : array)
//{
// e.& += 1;
//}
//>new_counter: u32 = 0;
//for (e : array)
//{
// new_counter += e;
//}
//require(counter + array.length);
return 0;
}