Loop break and continue
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m46s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m44s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m50s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 4m21s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m47s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m58s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m37s
CI / ci (Debug, ubuntu-latest) (push) Successful in 4m21s

This commit is contained in:
David Gonzalez Martin 2025-04-28 20:19:55 -06:00
parent 88c187de46
commit 1b0a5c4636
4 changed files with 178 additions and 16 deletions

View File

@ -788,6 +788,8 @@ pub const Statement = struct {
for_each: ForEach,
@"switch": Switch,
block: *LexicalBlock,
break_statement,
continue_statement,
},
line: u32,
column: u32,
@ -1062,6 +1064,7 @@ pub const Value = struct {
.unary => false,
.array_expression => false,
.string_literal => true,
.dereference => false,
else => @trap(),
};
}
@ -1254,6 +1257,8 @@ pub const Module = struct {
current_function: ?*Global = null,
current_macro_declaration: ?*Macro = null,
current_macro_instantiation: ?*Value = null,
exit_block: ?*llvm.BasicBlock = null,
continue_block: ?*llvm.BasicBlock = null,
inline_at_debug_location: ?*llvm.DI.Location = null,
name: []const u8,
path: []const u8,
@ -1884,6 +1889,8 @@ pub const Module = struct {
@"for",
@"while",
@"switch",
@"break",
@"continue",
};
const rules = blk: {
@ -2464,8 +2471,18 @@ pub const Module = struct {
},
'\'' => blk: {
module.offset += 1;
const ch = module.content[module.offset];
module.offset += 1;
const ch_after_quote = module.content[module.offset];
const ch: u8 = switch (ch_after_quote) {
'\\' => switch (module.content[module.offset + 1]) {
'n' => '\n',
'r' => '\r',
't' => '\t',
else => @trap(),
},
else => ch_after_quote,
};
module.offset += @as(u64, @intFromBool(ch_after_quote == '\\')) + 1;
module.expect_character('\'');
break :blk .{
@ -2916,6 +2933,8 @@ pub const Module = struct {
},
};
},
.@"break" => break :blk .break_statement,
.@"continue" => break :blk .continue_statement,
} else {
module.offset -= statement_start_identifier.len;
@ -8484,27 +8503,53 @@ pub const Module = struct {
_ = module.llvm.builder.create_branch(loop_entry_block);
module.llvm.builder.position_at_end(loop_entry_block);
module.analyze(while_loop.condition, .{}, .abi);
const boolean_type = module.integer_type(1, false);
const condition_value = switch (while_loop.condition.type == boolean_type) {
true => while_loop.condition.llvm.?,
false => switch (while_loop.condition.type.?.bb) {
.integer => module.llvm.builder.create_integer_compare(.ne, while_loop.condition.llvm.?, while_loop.condition.type.?.llvm.abi.?.to_integer().get_constant(0, @intFromBool(false)).to_value()),
else => @trap(),
},
};
const loop_body_block = module.llvm.context.create_basic_block("while.body", llvm_function);
const previous_continue_block = module.continue_block;
defer module.continue_block = previous_continue_block;
const loop_continue_block = module.llvm.context.create_basic_block("while.continue", llvm_function);
module.continue_block = loop_continue_block;
const previous_exit_block = module.exit_block;
defer module.exit_block = previous_exit_block;
const loop_end_block = module.llvm.context.create_basic_block("while.end", llvm_function);
_ = module.llvm.builder.create_conditional_branch(condition_value, loop_body_block, loop_end_block);
module.exit_block = loop_end_block;
if (while_loop.condition.is_constant()) {
switch (while_loop.condition.bb) {
.constant_integer => |constant_integer| {
if (constant_integer.value == 0) {
module.report_error();
}
},
else => @trap(),
}
_ = module.llvm.builder.create_branch(loop_body_block);
} else {
module.analyze(while_loop.condition, .{}, .abi);
const boolean_type = module.integer_type(1, false);
const condition_value = switch (while_loop.condition.type == boolean_type) {
true => while_loop.condition.llvm.?,
false => switch (while_loop.condition.type.?.bb) {
.integer => module.llvm.builder.create_integer_compare(.ne, while_loop.condition.llvm.?, while_loop.condition.type.?.llvm.abi.?.to_integer().get_constant(0, @intFromBool(false)).to_value()),
else => @trap(),
},
};
_ = module.llvm.builder.create_conditional_branch(condition_value, loop_body_block, loop_end_block);
}
module.llvm.builder.position_at_end(loop_body_block);
module.analyze_block(while_loop.block);
if (module.llvm.builder.get_insert_block() != null) {
_ = module.llvm.builder.create_branch(loop_entry_block);
}
_ = module.llvm.builder.create_branch(loop_continue_block);
}
module.llvm.builder.position_at_end(loop_continue_block);
_ = module.llvm.builder.create_branch(loop_entry_block);
if (loop_body_block.to_value().use_empty()) {
@trap();
@ -8589,8 +8634,17 @@ pub const Module = struct {
const loop_entry_block = module.llvm.context.create_basic_block("foreach.entry", llvm_function);
const loop_body_block = module.llvm.context.create_basic_block("foreach.body", llvm_function);
const previous_continue_block = module.continue_block;
defer module.continue_block = previous_continue_block;
const loop_continue_block = module.llvm.context.create_basic_block("foreach.continue", llvm_function);
module.continue_block = loop_continue_block;
const previous_exit_block = module.exit_block;
defer module.exit_block = previous_exit_block;
const loop_exit_block = module.llvm.context.create_basic_block("foreach.exit", llvm_function);
module.exit_block = loop_exit_block;
switch (for_loop.kind) {
.slice => {
@ -8787,6 +8841,16 @@ pub const Module = struct {
},
}
},
.break_statement => {
const exit_block = module.exit_block orelse module.report_error();
_ = module.llvm.builder.create_branch(exit_block);
module.llvm.builder.clear_insertion_position();
},
.continue_statement => {
const continue_block = module.continue_block orelse module.report_error();
_ = module.llvm.builder.create_branch(continue_block);
module.llvm.builder.clear_insertion_position();
},
}
}

View File

@ -630,6 +630,11 @@ Module = struct
arena: &Arena,
base_type_allocation: &Type,
void_value: &Value,
// Parser data
content: []u8,
offset: u64,
line_offset: u64,
line_character_offset: u64,
}
module_integer_type = fn (module: &Module, integer: TypeInteger) &Type
@ -650,6 +655,60 @@ module_noreturn_type = fn (module: &Module) &Type
return module_void_type(module) + 1;
}
is_space = fn (ch: u8) u1
{
return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r';
}
module_skip_space = fn (module: &Module) void
{
while (1)
{
>iteration_offset = module.offset;
while (module.offset < module.content.length and? is_space(module.content[module.offset]))
{
module.line_offset += #extend(module.content[module.offset] == '\n');
module.line_character_offset = #select(module.content[module.offset] == '\n', module.offset, module.line_character_offset);
module.offset += 1;
}
if (module.offset + 1 < module.content.length)
{
>i = module.offset;
>is_comment = module.content[i] == '/' and module.content[i + 1] == '/';
if (is_comment)
{
while (module.offset < module.content.length and? module.content[module.offset] != '\n')
{
module.offset += 1;
}
if (module.offset < module.content.length)
{
module.line_offset += 1;
module.line_character_offset = module.offset;
module.offset += 1;
}
}
}
if (module.offset - iteration_offset == 0)
{
break;
}
}
}
module_parse = fn (module: &Module) void
{
}
module_emit = fn (module: &Module) void
{
}
compile = fn (arena: &Arena, options: CompileOptions) void
{
>signs: [2]u1 = [0, 1];
@ -729,7 +788,14 @@ compile = fn (arena: &Arena, options: CompileOptions) void
.arena = arena,
.base_type_allocation = base_type_allocation,
.void_value = void_value,
.content = options.content,
.offset = 0,
.line_offset = 0,
.line_character_offset = 0,
};
module_parse(&module);
module_emit(&module);
}
compile_file = fn (arena: &Arena, compile_options: CompileFile) void

View File

@ -330,4 +330,5 @@ const names = &[_][]const u8{
"basic_union",
"constant_global_reference",
"generic_pointer_macro",
"break_continue",
};

31
tests/break_continue.bbb Normal file
View File

@ -0,0 +1,31 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 0;
while (a < 10)
{
if (a == 3)
{
break;
}
a += 1;
continue;
}
>b: s32 = 2;
for (i: 0..10)
{
if (b == 2)
{
b += 1;
continue;
}
else
{
break;
}
}
return a - b;
}