Implement continue expression
This commit is contained in:
parent
26a21c828e
commit
213082f532
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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: {
|
||||
|
29
src/main.nat
29
src/main.nat
@ -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 {
|
||||
|
22
test/standalone/continue/main.nat
Normal file
22
test/standalone/continue/main.nat
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user