Else if and empty if
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m12s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 3m13s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m3s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m2s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m7s
CI / ci (Debug, ubuntu-latest) (push) Successful in 3m10s
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m12s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 3m13s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m3s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m2s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m7s
CI / ci (Debug, ubuntu-latest) (push) Successful in 3m10s
This commit is contained in:
parent
d2e488edb1
commit
4dedaf3006
@ -617,6 +617,7 @@ pub const Statement = struct {
|
||||
@"if": If,
|
||||
@"while": While,
|
||||
@"switch": Switch,
|
||||
block: *LexicalBlock,
|
||||
},
|
||||
line: u32,
|
||||
column: u32,
|
||||
@ -643,8 +644,8 @@ pub const Statement = struct {
|
||||
|
||||
const If = struct {
|
||||
condition: *Value,
|
||||
if_block: *LexicalBlock,
|
||||
else_block: ?*LexicalBlock,
|
||||
if_statement: *Statement,
|
||||
else_statement: ?*Statement,
|
||||
};
|
||||
|
||||
const While = struct {
|
||||
@ -2242,34 +2243,7 @@ pub const Module = struct {
|
||||
return result.?;
|
||||
}
|
||||
|
||||
fn parse_block(module: *Module, function: *Global) *LexicalBlock {
|
||||
const parent_scope = module.current_scope;
|
||||
const block = module.lexical_blocks.append(.{
|
||||
.statements = .initialize(),
|
||||
.locals = .initialize(),
|
||||
.scope = .{
|
||||
.kind = .local,
|
||||
.parent = parent_scope,
|
||||
.line = module.get_line(),
|
||||
.column = module.get_column(),
|
||||
},
|
||||
});
|
||||
module.current_scope = &block.scope;
|
||||
defer module.current_scope = parent_scope;
|
||||
|
||||
module.expect_character(left_brace);
|
||||
|
||||
while (true) {
|
||||
module.skip_space();
|
||||
|
||||
if (module.offset == module.content.len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (module.consume_character_if_match(right_brace)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fn parse_statement(module: *Module, function: *Global, block: *LexicalBlock) *Statement {
|
||||
const statement_line = module.get_line();
|
||||
const statement_column = module.get_column();
|
||||
|
||||
@ -2333,7 +2307,7 @@ pub const Module = struct {
|
||||
|
||||
module.skip_space();
|
||||
|
||||
const if_block = module.parse_block(function);
|
||||
const if_statement = module.parse_statement(function, block);
|
||||
|
||||
module.skip_space();
|
||||
|
||||
@ -2348,15 +2322,18 @@ pub const Module = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const else_block = if (is_else) module.parse_block(function) else null;
|
||||
const else_block = switch (is_else) {
|
||||
true => module.parse_statement(function, block),
|
||||
false => null,
|
||||
};
|
||||
|
||||
require_semicolon = false;
|
||||
|
||||
break :blk .{
|
||||
.@"if" = .{
|
||||
.condition = condition,
|
||||
.if_block = if_block,
|
||||
.else_block = else_block,
|
||||
.if_statement = if_statement,
|
||||
.else_statement = else_block,
|
||||
},
|
||||
};
|
||||
},
|
||||
@ -2575,16 +2552,55 @@ pub const Module = struct {
|
||||
}
|
||||
}
|
||||
},
|
||||
left_brace => blk: {
|
||||
require_semicolon = false;
|
||||
break :blk .{
|
||||
.block = module.parse_block(function),
|
||||
};
|
||||
},
|
||||
else => @trap(),
|
||||
},
|
||||
.line = statement_line,
|
||||
.column = statement_column,
|
||||
};
|
||||
_ = block.statements.append(statement);
|
||||
|
||||
if (require_semicolon) {
|
||||
module.expect_character(';');
|
||||
}
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
fn parse_block(module: *Module, function: *Global) *LexicalBlock {
|
||||
const parent_scope = module.current_scope;
|
||||
const block = module.lexical_blocks.append(.{
|
||||
.statements = .initialize(),
|
||||
.locals = .initialize(),
|
||||
.scope = .{
|
||||
.kind = .local,
|
||||
.parent = parent_scope,
|
||||
.line = module.get_line(),
|
||||
.column = module.get_column(),
|
||||
},
|
||||
});
|
||||
module.current_scope = &block.scope;
|
||||
defer module.current_scope = parent_scope;
|
||||
|
||||
module.expect_character(left_brace);
|
||||
|
||||
while (true) {
|
||||
module.skip_space();
|
||||
|
||||
if (module.offset == module.content.len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (module.consume_character_if_match(right_brace)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const statement = module.parse_statement(function, block);
|
||||
_ = block.statements.append(statement);
|
||||
}
|
||||
|
||||
return block;
|
||||
@ -4445,6 +4461,7 @@ pub const Module = struct {
|
||||
};
|
||||
_ = &destination_pointer;
|
||||
|
||||
var destination_type = return_type_abi.semantic_type;
|
||||
if (return_type_abi.semantic_type.bb.structure.fields.len > 0) {
|
||||
// CreateCoercedStore(
|
||||
// CI, StorePtr,
|
||||
@ -4454,7 +4471,6 @@ pub const Module = struct {
|
||||
const source_value = llvm_call;
|
||||
const source_type = function_type.abi_return_type;
|
||||
// const source_size = source_type.get_byte_size();
|
||||
var destination_type = return_type_abi.semantic_type;
|
||||
const destination_size = destination_type.get_byte_size();
|
||||
// const destination_alignment = destination_type.get_byte_alignment();
|
||||
const left_destination_size = destination_size - return_type_abi.attributes.direct.offset;
|
||||
@ -4465,7 +4481,13 @@ pub const Module = struct {
|
||||
@trap();
|
||||
}
|
||||
|
||||
if (left_llvm) |l| {
|
||||
assert(destination_pointer == l);
|
||||
return destination_pointer;
|
||||
} else return switch (value.kind) {
|
||||
.left => @trap(),
|
||||
.right => module.create_load(.{ .type = destination_type, .value = destination_pointer }),
|
||||
};
|
||||
},
|
||||
.indirect => {
|
||||
return llvm_indirect_return_value;
|
||||
@ -5700,7 +5722,7 @@ pub const Module = struct {
|
||||
const array_element_pointer = module.llvm.builder.create_gep(.{
|
||||
.type = name_array_variable_type.to_type(),
|
||||
.aggregate = name_array_variable.to_value(),
|
||||
.indices = &.{uint64_zero, body_index_load},
|
||||
.indices = &.{ uint64_zero, body_index_load },
|
||||
});
|
||||
|
||||
const element_length_pointer = module.llvm.builder.create_struct_gep(slice_struct_type.llvm.abi.?.to_struct(), array_element_pointer, 1);
|
||||
@ -5716,10 +5738,7 @@ pub const Module = struct {
|
||||
module.llvm.builder.position_at_end(length_match_block);
|
||||
const s32 = module.integer_type(32, true);
|
||||
s32.resolve(module);
|
||||
const memcmp = if (module.llvm.memcmp) |memcmp| {
|
||||
_ = memcmp;
|
||||
@trap();
|
||||
} else b: {
|
||||
const memcmp = if (module.llvm.memcmp) |memcmp| memcmp else b: {
|
||||
if (module.llvm.module.get_named_function("memcmp")) |memcmp| {
|
||||
module.llvm.memcmp = memcmp;
|
||||
break :b memcmp;
|
||||
@ -5738,7 +5757,7 @@ pub const Module = struct {
|
||||
const length_array_element_pointer = module.llvm.builder.create_gep(.{
|
||||
.type = name_array_variable_type.to_type(),
|
||||
.aggregate = name_array_variable.to_value(),
|
||||
.indices = &.{uint64_zero, length_index_load},
|
||||
.indices = &.{ uint64_zero, length_index_load },
|
||||
});
|
||||
const element_pointer_pointer = module.llvm.builder.create_struct_gep(slice_struct_type.llvm.abi.?.to_struct(), length_array_element_pointer, 0);
|
||||
const element_pointer = module.llvm.builder.create_load(module.llvm.pointer_type, element_pointer_pointer);
|
||||
@ -5754,7 +5773,7 @@ pub const Module = struct {
|
||||
const value_array_element_pointer = module.llvm.builder.create_gep(.{
|
||||
.type = value_array_variable_type.to_type(),
|
||||
.aggregate = value_array_variable.to_value(),
|
||||
.indices = &.{uint64_zero, content_index_load},
|
||||
.indices = &.{ uint64_zero, content_index_load },
|
||||
});
|
||||
const enum_value_load = module.llvm.builder.create_load(string_to_enum.enum_type.llvm.memory.?, value_array_element_pointer);
|
||||
enum_value_load.set_alignment(string_to_enum.enum_type.get_byte_alignment());
|
||||
@ -6581,27 +6600,16 @@ pub const Module = struct {
|
||||
value.llvm = llvm_value;
|
||||
}
|
||||
|
||||
pub fn analyze_block(module: *Module, function: *Global, block: *LexicalBlock) void {
|
||||
pub fn analyze_statement(module: *Module, function: *Global, block: *LexicalBlock, statement: *Statement, last_line: *u32, last_column: *u32, last_statement_debug_location: **llvm.DI.Location) void {
|
||||
const llvm_function = function.variable.storage.?.llvm.?.to_function();
|
||||
if (module.has_debug_info) {
|
||||
const lexical_block = module.llvm.di_builder.create_lexical_block(block.scope.parent.?.llvm.?, module.llvm.file, block.scope.line, block.scope.column);
|
||||
block.scope.llvm = lexical_block.to_scope();
|
||||
}
|
||||
|
||||
const current_function = &function.variable.storage.?.bb.function;
|
||||
|
||||
var last_line: u32 = 0;
|
||||
var last_column: u32 = 0;
|
||||
var last_statement_debug_location: *llvm.DI.Location = undefined;
|
||||
|
||||
for (block.statements.get_slice()) |statement| {
|
||||
if (module.has_debug_info) {
|
||||
if (statement.line != last_line or statement.column != last_column) {
|
||||
if (statement.line != last_line.* or statement.column != last_column.*) {
|
||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||
last_statement_debug_location = llvm.DI.create_debug_location(module.llvm.context, statement.line, statement.column, block.scope.llvm.?, inlined_at);
|
||||
module.llvm.builder.set_current_debug_location(last_statement_debug_location);
|
||||
last_line = statement.line;
|
||||
last_column = statement.column;
|
||||
last_statement_debug_location.* = llvm.DI.create_debug_location(module.llvm.context, statement.line, statement.column, block.scope.llvm.?, inlined_at);
|
||||
module.llvm.builder.set_current_debug_location(last_statement_debug_location.*);
|
||||
last_line.* = statement.line;
|
||||
last_column.* = statement.column;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6624,7 +6632,7 @@ pub const Module = struct {
|
||||
}, .memory);
|
||||
|
||||
if (module.has_debug_info) {
|
||||
module.llvm.builder.set_current_debug_location(last_statement_debug_location);
|
||||
module.llvm.builder.set_current_debug_location(last_statement_debug_location.*);
|
||||
}
|
||||
|
||||
// Clang equivalent: CodeGenFunction::EmitReturnStmt
|
||||
@ -6719,7 +6727,7 @@ pub const Module = struct {
|
||||
module.analyze_value_type(function, local.variable.initial_value, .{ .type = local.variable.type });
|
||||
local.variable.resolve_type(local.variable.initial_value.type.?);
|
||||
if (expected_type) |lvt| assert(lvt == local.variable.type);
|
||||
module.emit_local_storage(local, last_statement_debug_location);
|
||||
module.emit_local_storage(local, last_statement_debug_location.*);
|
||||
|
||||
module.emit_assignment(function, local.variable.storage.?.llvm.?, local.variable.storage.?.type.?, local.variable.initial_value);
|
||||
},
|
||||
@ -6816,7 +6824,7 @@ pub const Module = struct {
|
||||
.@"if" => |if_statement| {
|
||||
const taken_block = module.llvm.context.create_basic_block("if.true", llvm_function);
|
||||
const not_taken_block = module.llvm.context.create_basic_block("if.false", llvm_function);
|
||||
const exit_block = module.llvm.context.create_basic_block("if.end", null);
|
||||
const exit_block = module.llvm.context.create_basic_block("if.end", llvm_function);
|
||||
|
||||
module.analyze(function, if_statement.condition, .{}, .memory);
|
||||
const llvm_condition = switch (if_statement.condition.type.?.bb) {
|
||||
@ -6833,49 +6841,21 @@ pub const Module = struct {
|
||||
|
||||
current_function.exit_block = exit_block;
|
||||
|
||||
module.analyze_block(function, if_statement.if_block);
|
||||
|
||||
const if_final_block = module.llvm.builder.get_insert_block();
|
||||
module.analyze_statement(function, block, if_statement.if_statement, last_line, last_line, last_statement_debug_location);
|
||||
if (module.llvm.builder.get_insert_block() != null) {
|
||||
_ = module.llvm.builder.create_branch(exit_block);
|
||||
}
|
||||
|
||||
module.llvm.builder.position_at_end(not_taken_block);
|
||||
var is_second_block_terminated = false;
|
||||
if (if_statement.else_block) |else_block| {
|
||||
current_function.exit_block = exit_block;
|
||||
module.analyze_block(function, else_block);
|
||||
is_second_block_terminated = module.llvm.builder.get_insert_block() == null;
|
||||
} else {
|
||||
if (if_final_block) |final_block| {
|
||||
const current_insert_block = module.llvm.builder.get_insert_block();
|
||||
defer if (current_insert_block) |b| {
|
||||
module.llvm.builder.position_at_end(b);
|
||||
};
|
||||
module.llvm.builder.position_at_end(final_block);
|
||||
_ = module.llvm.builder.create_branch(not_taken_block);
|
||||
module.llvm.builder.clear_insertion_position();
|
||||
if (if_statement.else_statement) |else_statement| {
|
||||
module.analyze_statement(function, block, else_statement, last_line, last_line, last_statement_debug_location);
|
||||
}
|
||||
|
||||
assert(exit_block.to_value().use_empty());
|
||||
not_taken_block.to_value().set_name("if.end");
|
||||
assert(exit_block.get_parent() == null);
|
||||
exit_block.delete();
|
||||
if (module.llvm.builder.get_insert_block() != null) {
|
||||
_ = module.llvm.builder.create_branch(exit_block);
|
||||
}
|
||||
|
||||
if (!(if_final_block == null and is_second_block_terminated)) {
|
||||
if (if_final_block != null) {
|
||||
// @trap();
|
||||
}
|
||||
|
||||
if (!is_second_block_terminated) {
|
||||
// if (is_else) {
|
||||
// @trap();
|
||||
// } else {}
|
||||
}
|
||||
} else {
|
||||
assert(exit_block.get_parent() == null);
|
||||
// TODO:
|
||||
// if call `exit_block.erase_from_paren()`, it crashes, investigate
|
||||
exit_block.delete();
|
||||
}
|
||||
module.llvm.builder.position_at_end(exit_block);
|
||||
},
|
||||
.@"while" => |while_loop| {
|
||||
const loop_entry_block = module.llvm.context.create_basic_block("while.entry", llvm_function);
|
||||
@ -6982,8 +6962,23 @@ pub const Module = struct {
|
||||
else => @trap(),
|
||||
}
|
||||
},
|
||||
.block => |child_block| module.analyze_block(function, child_block),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze_block(module: *Module, function: *Global, block: *LexicalBlock) void {
|
||||
if (module.has_debug_info) {
|
||||
const lexical_block = module.llvm.di_builder.create_lexical_block(block.scope.parent.?.llvm.?, module.llvm.file, block.scope.line, block.scope.column);
|
||||
block.scope.llvm = lexical_block.to_scope();
|
||||
}
|
||||
|
||||
var last_line: u32 = 0;
|
||||
var last_column: u32 = 0;
|
||||
var last_statement_debug_location: *llvm.DI.Location = undefined;
|
||||
|
||||
for (block.statements.get_slice()) |statement| {
|
||||
module.analyze_statement(function, block, statement, &last_line, &last_column, &last_statement_debug_location);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_assignment(module: *Module, function: *Global, left_llvm: *llvm.Value, left_type: *Type, right: *Value) void {
|
||||
|
@ -231,6 +231,18 @@ CompilerCommand = enum
|
||||
test,
|
||||
}
|
||||
|
||||
BuildMode = enum
|
||||
{
|
||||
debug_none,
|
||||
debug_fast,
|
||||
debug_size,
|
||||
soft_optimize,
|
||||
optimize_for_speed,
|
||||
optimize_for_size,
|
||||
aggressively_optimize_for_speed,
|
||||
aggressively_optimize_for_size,
|
||||
}
|
||||
|
||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
|
||||
{
|
||||
global_state_initialize();
|
||||
@ -242,7 +254,7 @@ CompilerCommand = enum
|
||||
|
||||
>command_string = c_string_to_slice(argv[1]);
|
||||
|
||||
> command_string_to_enum = #string_to_enum(CompilerCommand, command_string);
|
||||
>command_string_to_enum = #string_to_enum(CompilerCommand, command_string);
|
||||
if (!command_string_to_enum.is_valid)
|
||||
{
|
||||
return 1;
|
||||
@ -253,6 +265,41 @@ CompilerCommand = enum
|
||||
{
|
||||
.compile =>
|
||||
{
|
||||
if (argument_count < 3)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
>build_mode: BuildMode = .debug_none;
|
||||
>has_debug_info: u1 = 1;
|
||||
|
||||
if (argument_count >= 4)
|
||||
{
|
||||
>build_mode_string_to_enum = #string_to_enum(BuildMode, c_string_to_slice(argv[3]));
|
||||
if (!build_mode_string_to_enum.is_valid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
build_mode = build_mode_string_to_enum.enum_value;
|
||||
}
|
||||
|
||||
if (argument_count >= 5)
|
||||
{
|
||||
>has_debug_info_string = c_string_to_slice(argv[4]);
|
||||
if (string_equal(has_debug_info_string, "true"))
|
||||
{
|
||||
has_debug_info = 1;
|
||||
}
|
||||
else if (string_equal(has_debug_info_string, "false"))
|
||||
{
|
||||
has_debug_info = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
>relative_file_path_pointer = argv[2];
|
||||
if (!relative_file_path_pointer)
|
||||
{
|
||||
|
@ -311,4 +311,7 @@ const names = &[_][]const u8{
|
||||
"c_abi",
|
||||
"string_to_enum",
|
||||
"abi_enum_bool",
|
||||
"empty_if",
|
||||
"else_if",
|
||||
"else_if_complicated",
|
||||
};
|
||||
|
16
tests/else_if.bbb
Normal file
16
tests/else_if.bbb
Normal file
@ -0,0 +1,16 @@
|
||||
[export] main = fn [cc(c)] () s32
|
||||
{
|
||||
>result: s32 = 0;
|
||||
if (result == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (result == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
37
tests/else_if_complicated.bbb
Normal file
37
tests/else_if_complicated.bbb
Normal file
@ -0,0 +1,37 @@
|
||||
Foo = enum
|
||||
{
|
||||
a,b,c,
|
||||
}
|
||||
|
||||
[export] main = fn [cc(c)] (argument_count: u32) s32
|
||||
{
|
||||
>result: s32 = 0;
|
||||
>foo: Foo = .b;
|
||||
switch (foo)
|
||||
{
|
||||
.b =>
|
||||
{
|
||||
if (argument_count != 0)
|
||||
{
|
||||
>a: s32 = 1;
|
||||
if (result == 1)
|
||||
{
|
||||
}
|
||||
else if (result == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
},
|
||||
else =>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
12
tests/empty_if.bbb
Normal file
12
tests/empty_if.bbb
Normal file
@ -0,0 +1,12 @@
|
||||
[export] main = fn [cc(c)] (argument_count: u32) s32
|
||||
{
|
||||
>result: s32 = 0;
|
||||
if (argument_count != 1)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user