diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index bf97e34..b381599 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -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, diff --git a/bootstrap/frontend/lexer.zig b/bootstrap/frontend/lexer.zig index 4c92030..e7f6613 100644 --- a/bootstrap/frontend/lexer.zig +++ b/bootstrap/frontend/lexer.zig @@ -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; diff --git a/bootstrap/frontend/parser.zig b/bootstrap/frontend/parser.zig index 0496b2d..51d41b5 100644 --- a/bootstrap/frontend/parser.zig +++ b/bootstrap/frontend/parser.zig @@ -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: { diff --git a/src/main.nat b/src/main.nat index cdb005c..03a4ad0 100644 --- a/src/main.nat +++ b/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 { diff --git a/test/standalone/continue/main.nat b/test/standalone/continue/main.nat new file mode 100644 index 0000000..ac527d7 --- /dev/null +++ b/test/standalone/continue/main.nat @@ -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); +}