Merge pull request #151 from birth-software/continue

Implement continue expression
This commit is contained in:
David 2024-04-18 10:14:42 -06:00 committed by GitHub
commit ba4bc3712a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 180 additions and 52 deletions

View File

@ -3073,7 +3073,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_
write(.panic, "\nPANIC: ") catch {};
write(.panic, message) catch {};
write(.panic, "\n") catch {};
if (@import("builtin").os.tag != .windows) @breakpoint();
@breakpoint();
std.posix.abort();
},
}
@ -4390,6 +4390,7 @@ pub const Builder = struct {
current_basic_block: BasicBlock.Index = .null,
exit_blocks: UnpinnedArray(BasicBlock.Index) = .{},
loop_exit_block: BasicBlock.Index = .null,
loop_header_block: BasicBlock.Index = .null,
return_phi: Instruction.Index = .null,
return_block: BasicBlock.Index = .null,
last_check_point: struct {
@ -13516,9 +13517,12 @@ pub const Builder = struct {
assert(statement_node.left != .null);
assert(statement_node.right != .null);
const loop_header_block = try builder.newBasicBlock(unit, context);
try builder.jump(unit, context, loop_header_block);
builder.current_basic_block = loop_header_block;
const old_loop_header_block = builder.loop_header_block;
defer builder.loop_header_block = old_loop_header_block;
builder.loop_header_block = try builder.newBasicBlock(unit, context);
try builder.jump(unit, context, builder.loop_header_block);
builder.current_basic_block = builder.loop_header_block;
const condition = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .bool }, statement_node.left, .right);
const body_block = try builder.newBasicBlock(unit, context);
@ -13530,33 +13534,11 @@ pub const Builder = struct {
switch (condition.value) {
.runtime => |condition_instruction| {
try builder.branch(unit, context, condition_instruction, body_block, exit_block);
builder.current_basic_block = body_block;
builder.loop_exit_block = exit_block;
const body_value = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .void }, statement_node.right, .right);
_ = body_value; // autofix
try builder.jump(unit, context, loop_header_block);
builder.current_basic_block = exit_block;
},
.@"comptime" => |ct| switch (ct) {
.bool => |boolean| switch (boolean) {
true => {
try builder.jump(unit, context, body_block);
builder.current_basic_block = body_block;
builder.loop_exit_block = exit_block;
const body_value = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .void }, statement_node.right, .right);
switch (unit.types.get(body_value.type).*) {
.void => {
try builder.jump(unit, context, loop_header_block);
},
.noreturn => {},
else => |t| @panic(@tagName(t)),
}
builder.current_basic_block = exit_block;
},
false => unreachable,
},
@ -13564,6 +13546,20 @@ pub const Builder = struct {
},
else => unreachable,
}
builder.current_basic_block = body_block;
builder.loop_exit_block = exit_block;
const body_value = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .void }, statement_node.right, .right);
switch (unit.types.get(body_value.type).*) {
.void => {
try builder.jump(unit, context, builder.loop_header_block);
},
.noreturn => {},
else => |t| @panic(@tagName(t)),
}
builder.current_basic_block = exit_block;
},
.for_loop => {
assert(statement_node.left != .null);
@ -13676,9 +13672,12 @@ pub const Builder = struct {
},
};
const loop_header = try builder.newBasicBlock(unit, context);
try builder.jump(unit, context, loop_header);
builder.current_basic_block = loop_header;
const old_loop_header_block = builder.loop_header_block;
defer builder.loop_header_block = old_loop_header_block;
builder.loop_header_block = try builder.newBasicBlock(unit, context);
try builder.jump(unit, context, builder.loop_header_block);
builder.current_basic_block = builder.loop_header_block;
const pointer_to_usize = try unit.getPointerType(context, .{
.type = Type.usize,
@ -13874,13 +13873,16 @@ pub const Builder = struct {
try builder.appendInstruction(unit, context, increment_store);
try builder.jump(unit, context, loop_header);
try builder.jump(unit, context, builder.loop_header_block);
builder.current_basic_block = exit_block;
},
.break_expression => {
try builder.jump(unit, context, builder.loop_exit_block);
},
.continue_expression => {
try builder.jump(unit, context, builder.loop_header_block);
},
.@"if" => {
assert(statement_node.left != .null);
assert(statement_node.right != .null);
@ -14440,9 +14442,42 @@ pub const Builder = struct {
.node_list => {
const condition_nodes = unit.getNodeListFromNode(condition_node);
try conditions.ensure_capacity(context.my_allocator, @intCast(condition_nodes.len));
for (condition_nodes) |condition_node_index| {
const condition = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, condition_node_index, null, .right, &.{}, null, &.{});
conditions.append_with_capacity(condition);
const cn = unit.getNode(condition_node_index);
switch (cn.id) {
.range => {
const left = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, cn.left, null, .right, &.{}, null, &.{});
const right = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, cn.right, null, .right, &.{}, null, &.{});
switch (condition_type) {
.u8 => {
var left_ch: u8 = switch (left) {
.constant_int => |ci| @intCast(ci.value),
else => |t| @panic(@tagName(t)),
};
const right_ch: u8 = switch (right) {
.constant_int => |ci| @intCast(ci.value),
else => |t| @panic(@tagName(t)),
};
if (left_ch < right_ch) {
while (left_ch <= right_ch) : (left_ch += 1) {
try conditions.append(context.my_allocator, .{
.constant_int = .{
.value = left_ch,
},
});
}
} else {
unreachable;
}
},
else => unreachable,
}
},
else => try conditions.append(context.my_allocator, try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, condition_node_index, null, .right, &.{}, null, &.{})),
}
}
},
else => {
@ -16709,6 +16744,7 @@ pub const FixedKeyword = enum {
Self,
any,
type,
@"continue"
};
pub const Descriptor = struct {
@ -16853,6 +16889,8 @@ pub const Token = struct {
operator_at,
operator_comma,
operator_dot,
operator_double_dot,
operator_triple_dot,
operator_colon,
operator_bang,
operator_optional,
@ -16925,6 +16963,8 @@ pub const Token = struct {
fixed_keyword_Self,
fixed_keyword_any,
fixed_keyword_type,
fixed_keyword_continue,
unused1,
unused2,
unused3,

View File

@ -259,7 +259,18 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B
},
'.' => blk: {
index += 1;
break :blk .operator_dot;
if (text[index] == '.') {
index += 1;
if (text[index] == '.') {
index += 1;
break :blk .operator_triple_dot;
} else {
break :blk .operator_double_dot;
}
} else {
break :blk .operator_dot;
}
},
':' => blk: {
index += 1;

View File

@ -176,6 +176,7 @@ pub const Node = struct {
anonymous_empty_literal,
empty_container_literal_guess,
break_expression,
continue_expression,
character_literal,
function_attribute_naked,
function_attribute_cc,
@ -601,13 +602,30 @@ const Analyzer = struct {
else => blk: {
var array_list = UnpinnedArray(Node.Index){};
while (true) {
const switch_case_node = try analyzer.expression();
const token = analyzer.token_i;
const left = try analyzer.expression();
const switch_case_node = switch (analyzer.peekToken()) {
.operator_triple_dot => try analyzer.addNode(.{
.id = .range,
.token = b: {
analyzer.consumeToken();
break :b token;
},
.left = left,
.right = try analyzer.expression(),
}),
else => left,
};
try array_list.append(analyzer.my_allocator, switch_case_node);
switch (analyzer.peekToken()) {
.operator_comma => analyzer.consumeToken(),
.operator_switch_case => break,
else => {},
}
}
break :blk switch (array_list.length) {
@ -726,21 +744,17 @@ const Analyzer = struct {
const first = try analyzer.expression();
const node_index = switch (analyzer.peekToken()) {
.operator_dot => switch (analyzer.peekTokenAhead(1)) {
.operator_dot => blk: {
analyzer.consumeTokens(2);
break :blk try analyzer.addNode(.{
.id = .range,
.token = expression_token,
.left = first,
.right = switch (analyzer.peekToken()) {
.operator_right_parenthesis, .operator_comma => Node.Index.null,
else => try analyzer.expression(),
},
.operator_double_dot => blk: {
analyzer.consumeToken();
break :blk try analyzer.addNode(.{
.id = .range,
.token = expression_token,
.left = first,
.right = switch (analyzer.peekToken()) {
.operator_right_parenthesis, .operator_comma => Node.Index.null,
else => try analyzer.expression(),
},
});
},
else => |t| @panic(@tagName(t)),
},
.operator_right_parenthesis,
.operator_comma,
@ -825,6 +839,17 @@ const Analyzer = struct {
return for_node;
}
fn continueExpression(analyzer: *Analyzer) !Node.Index {
const t = try analyzer.expectToken(.fixed_keyword_continue);
const node_index = try analyzer.addNode(.{
.id = .continue_expression,
.token = t,
.left = Node.Index.null,
.right = Node.Index.null,
});
return node_index;
}
fn breakExpression(analyzer: *Analyzer) !Node.Index {
const t = try analyzer.expectToken(.fixed_keyword_break);
const node_index = try analyzer.addNode(.{
@ -1139,6 +1164,8 @@ const Analyzer = struct {
.operator_div_assign,
.operator_mod_assign,
.operator_dot,
.operator_double_dot,
.operator_triple_dot,
.operator_switch_case,
.fixed_keyword_const,
.fixed_keyword_var,
@ -1148,6 +1175,7 @@ const Analyzer = struct {
.identifier,
.discard,
.fixed_keyword_test,
.fixed_keyword_break,
=> break,
.operator_compare_equal => .compare_equal,
.operator_compare_not_equal => .compare_not_equal,
@ -1292,6 +1320,7 @@ const Analyzer = struct {
.right = Node.Index.null,
}),
.fixed_keyword_break => try analyzer.breakExpression(),
.fixed_keyword_continue => try analyzer.continueExpression(),
// todo:?
.operator_left_brace => try analyzer.block(),
.fixed_keyword_if => try analyzer.ifExpression(),
@ -2142,8 +2171,8 @@ const Analyzer = struct {
analyzer.consumeToken();
const index_expression = try analyzer.expression();
if (analyzer.peekToken() == .operator_dot and analyzer.peekTokenAhead(1) == .operator_dot) {
analyzer.consumeTokens(2);
if (analyzer.peekToken() == .operator_double_dot) {
analyzer.consumeToken();
const range_end_expression = switch (analyzer.peekToken()) {
.operator_right_bracket => Node.Index.null,
else => try analyzer.expression(),
@ -2206,7 +2235,6 @@ const Analyzer = struct {
.right = Node.Index.null,
}),
}),
.operator_dot => Node.Index.null,
.operator_ampersand => try analyzer.addNode(.{
.id = .address_of,
.token = blk: {

View File

@ -10,6 +10,11 @@ const ArgumentProcessingError = error{
no_arguments,
};
const Token = struct {
const Id = enum(u8) {
};
};
const lex = fn (arena: &Arena, bytes: []const u8) *!void {
if (bytes.length >= 0xffffffff) {
unreachable;
@ -26,11 +31,33 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void {
var index: u32 = 0;
while (index < length) {
const byte = bytes[index];
line_offsets[line_count] = index;
line_count += #cast(byte == '\n');
line_offsets[line_count] = index;
index += 1;
}
index = 0;
//while (index < length) {
// const start_index = index;
// const start_character = bytes[index];
// switch (start_character) {
// 'a'...'z', 'A'...'Z', '_' => {
// while (true) {
// const ch = bytes[index];
// if ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_' or (ch >= '0' and ch <= '9')) {
// index += 1;
// continue;
// }
// break;
// }
// },
// else => unreachable,
// }
//}
}
const get_argument = fn (real_argument: []const u8, wanted_argument: []const u8, command_arguments: []const [&:0]const u8, i_ptr: &usize) ?[]const u8 {

View File

@ -0,0 +1,22 @@
const std = #import("std");
const expect = std.testing.expect;
const main = fn () *!void {
var i: u32 = 0;
var b: bool = false;
while (i < 10) {
if (b) {
break;
}
i += 1;
if (i == 5) {
break;
}
}
try expect(i == 5);
}