Implement basic while
This commit is contained in:
parent
00d77039f3
commit
3f66a9587d
@ -1566,6 +1566,43 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_condition_parenthesis(noalias converter: *Converter, noalias module: *Module) *Value {
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character(left_parenthesis);
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const condition = converter.parse_condition_raw(module);
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
converter.expect_character(right_parenthesis);
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_condition_raw(noalias converter: *Converter, noalias module: *Module) *Value {
|
||||||
|
const condition = converter.parse_value(module, null, .value);
|
||||||
|
const boolean_type = module.integer_type(1, false);
|
||||||
|
if (condition.type != boolean_type) {
|
||||||
|
const llvm_value = switch (condition.type.bb) {
|
||||||
|
.integer => module.llvm.builder.create_compare(.ne, condition.llvm, condition.type.llvm.handle.to_integer().get_constant(0, 0).to_value()),
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.llvm = llvm_value,
|
||||||
|
.type = boolean_type,
|
||||||
|
.bb = .instruction,
|
||||||
|
.lvalue = false,
|
||||||
|
.dereference_to_assign = false,
|
||||||
|
};
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_type(noalias converter: *Converter, noalias module: *Module) *Type {
|
pub fn parse_type(noalias converter: *Converter, noalias module: *Module) *Type {
|
||||||
switch (converter.content[converter.offset]) {
|
switch (converter.content[converter.offset]) {
|
||||||
'a'...'z', 'A'...'Z', '_' => {
|
'a'...'z', 'A'...'Z', '_' => {
|
||||||
@ -2406,15 +2443,7 @@ const Converter = struct {
|
|||||||
const not_taken_block = module.llvm.context.create_basic_block("if.false", current_function_global.value.llvm.to_function());
|
const not_taken_block = module.llvm.context.create_basic_block("if.false", current_function_global.value.llvm.to_function());
|
||||||
const exit_block = module.llvm.context.create_basic_block("if.end", null);
|
const exit_block = module.llvm.context.create_basic_block("if.end", null);
|
||||||
|
|
||||||
converter.skip_space();
|
const condition = converter.parse_condition_parenthesis(module);
|
||||||
|
|
||||||
converter.expect_character(left_parenthesis);
|
|
||||||
converter.skip_space();
|
|
||||||
|
|
||||||
const condition = converter.parse_value(module, null, .value);
|
|
||||||
|
|
||||||
converter.skip_space();
|
|
||||||
converter.expect_character(right_parenthesis);
|
|
||||||
|
|
||||||
_ = module.llvm.builder.create_conditional_branch(condition.llvm, taken_block, not_taken_block);
|
_ = module.llvm.builder.create_conditional_branch(condition.llvm, taken_block, not_taken_block);
|
||||||
module.llvm.builder.position_at_end(taken_block);
|
module.llvm.builder.position_at_end(taken_block);
|
||||||
@ -2479,6 +2508,36 @@ const Converter = struct {
|
|||||||
exit_block.delete();
|
exit_block.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require_semicolon = false;
|
||||||
|
},
|
||||||
|
.@"while" => {
|
||||||
|
const loop_entry_block = module.llvm.context.create_basic_block("while.entry", current_function_global.value.llvm.to_function());
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
module.llvm.builder.position_at_end(loop_entry_block);
|
||||||
|
|
||||||
|
const condition = converter.parse_condition_parenthesis(module);
|
||||||
|
|
||||||
|
const loop_body_block = module.llvm.context.create_basic_block("while.body", current_function_global.value.llvm.to_function());
|
||||||
|
const loop_end_block = module.llvm.context.create_basic_block("while.end", current_function_global.value.llvm.to_function());
|
||||||
|
_ = module.llvm.builder.create_conditional_branch(condition.llvm, loop_body_block, loop_end_block);
|
||||||
|
module.llvm.builder.position_at_end(loop_body_block);
|
||||||
|
converter.skip_space();
|
||||||
|
converter.parse_block(module);
|
||||||
|
|
||||||
|
if (module.llvm.builder.get_insert_block() != null) {
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_body_block.to_value().use_empty()) {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_end_block.to_value().use_empty()) {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_end_block);
|
||||||
|
|
||||||
require_semicolon = false;
|
require_semicolon = false;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -2545,26 +2604,27 @@ const Converter = struct {
|
|||||||
|
|
||||||
const ExpressionState = enum {
|
const ExpressionState = enum {
|
||||||
none,
|
none,
|
||||||
add,
|
integer_add,
|
||||||
sub,
|
integer_sub,
|
||||||
mul,
|
integer_mul,
|
||||||
udiv,
|
integer_udiv,
|
||||||
sdiv,
|
integer_sdiv,
|
||||||
urem,
|
integer_urem,
|
||||||
srem,
|
integer_srem,
|
||||||
shl,
|
shl,
|
||||||
ashr,
|
ashr,
|
||||||
lshr,
|
lshr,
|
||||||
@"and",
|
@"and",
|
||||||
@"or",
|
@"or",
|
||||||
xor,
|
xor,
|
||||||
icmp_eq,
|
integer_compare_equal,
|
||||||
icmp_ne,
|
integer_compare_not_equal,
|
||||||
|
pointer_add,
|
||||||
|
|
||||||
pub fn to_int_predicate(expression_state: ExpressionState) llvm.IntPredicate {
|
pub fn to_int_predicate(expression_state: ExpressionState) llvm.IntPredicate {
|
||||||
return switch (expression_state) {
|
return switch (expression_state) {
|
||||||
.icmp_ne => .ne,
|
.integer_compare_not_equal => .ne,
|
||||||
.icmp_eq => .eq,
|
.integer_compare_equal => .eq,
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -2589,6 +2649,12 @@ const Converter = struct {
|
|||||||
iterative_expected_type = previous_value.?.type;
|
iterative_expected_type = previous_value.?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const old_iterative_expected_type = iterative_expected_type;
|
||||||
|
iterative_expected_type = switch (value_state) {
|
||||||
|
.pointer_add => module.integer_type(64, false),
|
||||||
|
else => iterative_expected_type,
|
||||||
|
};
|
||||||
|
|
||||||
const current_value = switch (converter.consume_character_if_match(left_parenthesis)) {
|
const current_value = switch (converter.consume_character_if_match(left_parenthesis)) {
|
||||||
true => blk: {
|
true => blk: {
|
||||||
const r = converter.parse_value(module, iterative_expected_type, value_kind);
|
const r = converter.parse_value(module, iterative_expected_type, value_kind);
|
||||||
@ -2599,6 +2665,8 @@ const Converter = struct {
|
|||||||
false => converter.parse_single_value(module, iterative_expected_type, value_kind),
|
false => converter.parse_single_value(module, iterative_expected_type, value_kind),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
iterative_expected_type = old_iterative_expected_type;
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const left = switch (value_state) {
|
const left = switch (value_state) {
|
||||||
@ -2610,20 +2678,26 @@ const Converter = struct {
|
|||||||
|
|
||||||
const llvm_value = switch (value_state) {
|
const llvm_value = switch (value_state) {
|
||||||
.none => current_value.llvm,
|
.none => current_value.llvm,
|
||||||
.sub => module.llvm.builder.create_sub(left, right),
|
.integer_sub => module.llvm.builder.create_sub(left, right),
|
||||||
.add => module.llvm.builder.create_add(left, right),
|
.integer_add => module.llvm.builder.create_add(left, right),
|
||||||
.mul => module.llvm.builder.create_mul(left, right),
|
.integer_mul => module.llvm.builder.create_mul(left, right),
|
||||||
.sdiv => module.llvm.builder.create_sdiv(left, right),
|
.integer_sdiv => module.llvm.builder.create_sdiv(left, right),
|
||||||
.udiv => module.llvm.builder.create_udiv(left, right),
|
.integer_udiv => module.llvm.builder.create_udiv(left, right),
|
||||||
.srem => module.llvm.builder.create_srem(left, right),
|
.integer_srem => module.llvm.builder.create_srem(left, right),
|
||||||
.urem => module.llvm.builder.create_urem(left, right),
|
.integer_urem => module.llvm.builder.create_urem(left, right),
|
||||||
.shl => module.llvm.builder.create_shl(left, right),
|
.shl => module.llvm.builder.create_shl(left, right),
|
||||||
.ashr => module.llvm.builder.create_ashr(left, right),
|
.ashr => module.llvm.builder.create_ashr(left, right),
|
||||||
.lshr => module.llvm.builder.create_lshr(left, right),
|
.lshr => module.llvm.builder.create_lshr(left, right),
|
||||||
.@"and" => module.llvm.builder.create_and(left, right),
|
.@"and" => module.llvm.builder.create_and(left, right),
|
||||||
.@"or" => module.llvm.builder.create_or(left, right),
|
.@"or" => module.llvm.builder.create_or(left, right),
|
||||||
.xor => module.llvm.builder.create_xor(left, right),
|
.xor => module.llvm.builder.create_xor(left, right),
|
||||||
.icmp_ne, .icmp_eq => |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left, right),
|
.integer_compare_equal, .integer_compare_not_equal => |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left, right),
|
||||||
|
.pointer_add => module.llvm.builder.create_gep(.{
|
||||||
|
.type = next_ty.bb.pointer.type.llvm.handle,
|
||||||
|
.aggregate = left,
|
||||||
|
.indices = &.{right},
|
||||||
|
.inbounds = false,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (value_state) {
|
switch (value_state) {
|
||||||
@ -2634,14 +2708,14 @@ const Converter = struct {
|
|||||||
.llvm = llvm_value,
|
.llvm = llvm_value,
|
||||||
.type = switch (value_state) {
|
.type = switch (value_state) {
|
||||||
.none => unreachable,
|
.none => unreachable,
|
||||||
.icmp_eq, .icmp_ne => module.integer_type(1, false),
|
.integer_compare_equal, .integer_compare_not_equal => module.integer_type(1, false),
|
||||||
.sub,
|
.integer_sub,
|
||||||
.add,
|
.integer_add,
|
||||||
.mul,
|
.integer_mul,
|
||||||
.sdiv,
|
.integer_sdiv,
|
||||||
.udiv,
|
.integer_udiv,
|
||||||
.srem,
|
.integer_srem,
|
||||||
.urem,
|
.integer_urem,
|
||||||
.shl,
|
.shl,
|
||||||
.ashr,
|
.ashr,
|
||||||
.lshr,
|
.lshr,
|
||||||
@ -2649,6 +2723,7 @@ const Converter = struct {
|
|||||||
.@"or",
|
.@"or",
|
||||||
.xor,
|
.xor,
|
||||||
=> next_ty,
|
=> next_ty,
|
||||||
|
.pointer_add => next_ty,
|
||||||
},
|
},
|
||||||
.bb = .instruction,
|
.bb = .instruction,
|
||||||
.lvalue = false,
|
.lvalue = false,
|
||||||
@ -2663,29 +2738,33 @@ const Converter = struct {
|
|||||||
'=' => switch (converter.content[converter.offset + 1]) {
|
'=' => switch (converter.content[converter.offset + 1]) {
|
||||||
'=' => blk: {
|
'=' => blk: {
|
||||||
converter.offset += 2;
|
converter.offset += 2;
|
||||||
break :blk .icmp_eq;
|
break :blk .integer_compare_equal;
|
||||||
},
|
},
|
||||||
else => break previous_value.?,
|
else => break previous_value.?,
|
||||||
},
|
},
|
||||||
'-' => blk: {
|
'-' => blk: {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
break :blk .sub;
|
break :blk .integer_sub;
|
||||||
},
|
},
|
||||||
'+' => blk: {
|
'+' => blk: {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
break :blk .add;
|
break :blk switch (next_ty.bb) {
|
||||||
|
.integer => .integer_add,
|
||||||
|
.pointer => .pointer_add,
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
'*' => blk: {
|
'*' => blk: {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
break :blk .mul;
|
break :blk .integer_mul;
|
||||||
},
|
},
|
||||||
'/' => blk: {
|
'/' => blk: {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
const ty = iterative_expected_type orelse unreachable;
|
const ty = iterative_expected_type orelse unreachable;
|
||||||
break :blk switch (ty.bb) {
|
break :blk switch (ty.bb) {
|
||||||
.integer => |int| switch (int.signed) {
|
.integer => |int| switch (int.signed) {
|
||||||
true => .sdiv,
|
true => .integer_sdiv,
|
||||||
false => .udiv,
|
false => .integer_udiv,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
@ -2695,8 +2774,8 @@ const Converter = struct {
|
|||||||
const ty = iterative_expected_type orelse unreachable;
|
const ty = iterative_expected_type orelse unreachable;
|
||||||
break :blk switch (ty.bb) {
|
break :blk switch (ty.bb) {
|
||||||
.integer => |int| switch (int.signed) {
|
.integer => |int| switch (int.signed) {
|
||||||
true => .srem,
|
true => .integer_srem,
|
||||||
false => .urem,
|
false => .integer_urem,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
@ -2747,7 +2826,7 @@ const Converter = struct {
|
|||||||
break :blk switch (converter.content[converter.offset]) {
|
break :blk switch (converter.content[converter.offset]) {
|
||||||
'=' => b: {
|
'=' => b: {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
break :b .icmp_ne;
|
break :b .integer_compare_not_equal;
|
||||||
},
|
},
|
||||||
else => os.abort(),
|
else => os.abort(),
|
||||||
};
|
};
|
||||||
@ -2979,15 +3058,7 @@ const Converter = struct {
|
|||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
.select => {
|
.select => {
|
||||||
const condition_value = converter.parse_value(module, null, .value);
|
const condition_value = converter.parse_condition_raw(module);
|
||||||
|
|
||||||
if (condition_value.type.bb != .integer) {
|
|
||||||
converter.report_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (condition_value.type.bb.integer.bit_count != 1) {
|
|
||||||
converter.report_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
converter.expect_character(',');
|
converter.expect_character(',');
|
||||||
@ -3950,11 +4021,12 @@ const Converter = struct {
|
|||||||
if (expected_ty == appointee_type) {
|
if (expected_ty == appointee_type) {
|
||||||
@trap();
|
@trap();
|
||||||
} else {
|
} else {
|
||||||
if (appointee_type.bb == .pointer and appointee_type.bb.pointer.type == expected_ty) {
|
assert(appointee_type.bb == .pointer); // TODO ?????
|
||||||
|
if (appointee_type.bb == .pointer and element_type == expected_ty) {
|
||||||
const load = module.values.add();
|
const load = module.values.add();
|
||||||
load.* = .{
|
load.* = .{
|
||||||
.llvm = module.create_load(.{ .type = expected_ty, .value = pointer_load.llvm }),
|
.llvm = module.create_load(.{ .type = element_type, .value = pointer_load.llvm }),
|
||||||
.type = expected_ty,
|
.type = element_type,
|
||||||
.bb = .instruction,
|
.bb = .instruction,
|
||||||
.lvalue = false,
|
.lvalue = false,
|
||||||
.dereference_to_assign = false,
|
.dereference_to_assign = false,
|
||||||
@ -3965,7 +4037,15 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@trap();
|
const load = module.values.add();
|
||||||
|
load.* = .{
|
||||||
|
.llvm = module.create_load(.{ .type = element_type, .value = pointer_load.llvm }),
|
||||||
|
.type = element_type,
|
||||||
|
.bb = .instruction,
|
||||||
|
.lvalue = false,
|
||||||
|
.dereference_to_assign = false,
|
||||||
|
};
|
||||||
|
break :b load;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.maybe_pointer, .pointer => {
|
.maybe_pointer, .pointer => {
|
||||||
@ -4165,6 +4245,8 @@ fn is_space(ch: u8) bool {
|
|||||||
const StatementStartKeyword = enum {
|
const StatementStartKeyword = enum {
|
||||||
@"return",
|
@"return",
|
||||||
@"if",
|
@"if",
|
||||||
|
// TODO: make `unreachable` a statement start keyword?
|
||||||
|
@"while",
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BuildMode = enum {
|
pub const BuildMode = enum {
|
||||||
|
@ -443,3 +443,7 @@ test "basic_string" {
|
|||||||
test "argv" {
|
test "argv" {
|
||||||
try invsrc(@src());
|
try invsrc(@src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "basic_while" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
28
src/main.zig
28
src/main.zig
@ -7,6 +7,20 @@ const Arena = lib.Arena;
|
|||||||
|
|
||||||
pub const panic = lib.panic_struct;
|
pub const panic = lib.panic_struct;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
if (!lib.is_test) {
|
||||||
|
@export(&main, .{
|
||||||
|
.name = "main",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = lib;
|
||||||
|
_ = llvm;
|
||||||
|
_ = converter;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
lib.print_string("Failed to match argument count\n");
|
lib.print_string("Failed to match argument count\n");
|
||||||
@ -50,17 +64,3 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
|||||||
});
|
});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
comptime {
|
|
||||||
if (!lib.is_test) {
|
|
||||||
@export(&main, .{
|
|
||||||
.name = "main",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
_ = lib;
|
|
||||||
_ = llvm;
|
|
||||||
_ = converter;
|
|
||||||
}
|
|
||||||
|
38
tests/basic_while.bbb
Normal file
38
tests/basic_while.bbb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
c_string_length = fn (c_string: &u8) u64
|
||||||
|
{
|
||||||
|
>it = c_string;
|
||||||
|
|
||||||
|
while (it.&)
|
||||||
|
{
|
||||||
|
it = it + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return #int_from_pointer(it) - #int_from_pointer(c_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn (argument_count: u32, argument_pointer: &&u8) s32
|
||||||
|
{
|
||||||
|
if (argument_count == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
>first_arg = argument_pointer[0];
|
||||||
|
if (!first_arg)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
>arg_length = c_string_length(first_arg);
|
||||||
|
if (arg_length == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_arg[arg_length] != 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user