From d5910989d1f7041e0d88155a0b49f85b82204f6b Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Wed, 29 Nov 2023 00:11:53 -0600 Subject: [PATCH] ranged for loop --- bootstrap/Compilation.zig | 18 ++- bootstrap/backend/c_transpiler.zig | 80 +++++++-- bootstrap/frontend/lexical_analyzer.zig | 2 + bootstrap/frontend/semantic_analyzer.zig | 189 ++++++++++++++++++---- bootstrap/frontend/syntactic_analyzer.zig | 131 +++++++++++++-- build.zig | 2 +- test/foreach/main.nat | 10 ++ 7 files changed, 361 insertions(+), 71 deletions(-) create mode 100644 test/foreach/main.nat diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 9598ca2..c431dac 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -512,9 +512,11 @@ pub const Block = struct { }; pub const Loop = struct { + pre: Value.Index, condition: Value.Index, body: Value.Index, - breaks: bool, + post: Value.Index, + reaches_end: bool, pub const List = BlockList(@This()); pub const Index = List.Index; @@ -528,6 +530,12 @@ const Unresolved = struct { pub const Assignment = struct { destination: Value.Index, source: Value.Index, + operation: Operation, + + const Operation = enum { + none, + add, + }; pub const List = BlockList(@This()); pub const Index = List.Index; @@ -651,10 +659,14 @@ pub const FieldAccess = struct { pub const Allocation = List.Allocation; }; -pub const Slice = struct { - sliceable: Value.Index, +pub const Range = struct { start: Value.Index, end: Value.Index, +}; + +pub const Slice = struct { + sliceable: Value.Index, + range: Range, type: Type.Index, pub const Access = struct { diff --git a/bootstrap/backend/c_transpiler.zig b/bootstrap/backend/c_transpiler.zig index 2ebcd7f..e0ef40a 100644 --- a/bootstrap/backend/c_transpiler.zig +++ b/bootstrap/backend/c_transpiler.zig @@ -130,7 +130,25 @@ pub const TranslationUnit = struct { .value_index = declaration.init_value, .type_index = declaration.type, }); - try list.append(allocator, ';'); + } + + fn writeAssignment(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, assignment_index: Compilation.Assignment.Index, function_return_type: Compilation.Type.Index, indentation: usize) !void { + const assignment = module.assignments.get(assignment_index); + const left_type = module.values.get(assignment.source).getType(module); + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = assignment.destination, + .type_index = left_type, + }); + try list.append(allocator, ' '); + switch (assignment.operation) { + .none => {}, + .add => try list.append(allocator, '+'), + } + try list.appendSlice(allocator, "= "); + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = assignment.source, + .type_index = Compilation.Type.Index.invalid, + }); } fn writeBlock(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, block_index: Compilation.Block.Index, function_return_type: Compilation.Type.Index, old_indentation: usize) !void { @@ -146,19 +164,10 @@ pub const TranslationUnit = struct { switch (statement.*) { .declaration => |declaration_index| { try unit.writeDeclaration(module, list, allocator, declaration_index, indentation); + try list.append(allocator, ';'); }, .assign => |assignment_index| { - const assignment = module.assignments.get(assignment_index); - const left_type = module.values.get(assignment.source).getType(module); - try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ - .value_index = assignment.destination, - .type_index = left_type, - }); - try list.appendSlice(allocator, " = "); - try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ - .value_index = assignment.source, - .type_index = Compilation.Type.Index.invalid, - }); + try unit.writeAssignment(module, list, allocator, assignment_index, function_return_type, indentation); try list.append(allocator, ';'); }, .@"return" => |return_index| { @@ -245,6 +254,38 @@ pub const TranslationUnit = struct { try unit.writeAssembly(module, list, allocator, assembly_block_index, indentation); try list.append(allocator, ';'); }, + .loop => |loop_index| { + const loop = module.loops.get(loop_index); + try list.appendSlice(allocator, "for ("); + if (!loop.pre.invalid) { + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = loop.pre, + .type_index = Compilation.Type.Index.invalid, + }); + } + try list.appendSlice(allocator, "; "); + + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = loop.condition, + .type_index = Compilation.Type.boolean, + }); + + try list.appendSlice(allocator, "; "); + + if (!loop.post.invalid) { + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = loop.post, + .type_index = Compilation.Type.Index.invalid, + }); + } + + try list.appendSlice(allocator, ") "); + + try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ + .value_index = loop.body, + .type_index = Compilation.Type.Index.invalid, + }); + }, else => |t| @panic(@tagName(t)), } @@ -326,6 +367,7 @@ pub const TranslationUnit = struct { => {}, .@"struct" => { try unit.writeDeclaration(module, &unit.global_variable_declarations, allocator, declaration_index, 0); + try unit.global_variable_declarations.append(allocator, ';'); try unit.global_variable_declarations.appendNTimes(allocator, '\n', 2); }, else => |t| @panic(@tagName(t)), @@ -798,6 +840,12 @@ pub const TranslationUnit = struct { _ = type_index; const value = module.values.get(value_index); switch (value.*) { + .declaration => |declaration_index| { + try unit.writeDeclaration(module, list, allocator, declaration_index, indentation); + }, + .assign => |assignment_index| { + try unit.writeAssignment(module, list, allocator, assignment_index, function_return_type, indentation); + }, .integer => |integer| { try list.writer(allocator).print("{}", .{integer.value}); }, @@ -996,7 +1044,7 @@ pub const TranslationUnit = struct { }); try list.appendSlice(allocator, ") + ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ - .value_index = slice.start, + .value_index = slice.range.start, .type_index = Compilation.Type.Index.invalid, }); try list.appendSlice(allocator, "),\n"); @@ -1009,16 +1057,16 @@ pub const TranslationUnit = struct { switch (sliceable_type.*) { .pointer => { - switch (slice.end.invalid) { + switch (slice.range.end.invalid) { false => { try list.append(allocator, '('); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ - .value_index = slice.end, + .value_index = slice.range.end, .type_index = Compilation.Type.Index.invalid, }); try list.appendSlice(allocator, ") - ("); try unit.writeValue(module, list, allocator, function_return_type, indentation + 1, .{ - .value_index = slice.start, + .value_index = slice.range.start, .type_index = Compilation.Type.Index.invalid, }); try list.appendSlice(allocator, ")\n"); diff --git a/bootstrap/frontend/lexical_analyzer.zig b/bootstrap/frontend/lexical_analyzer.zig index b3b5464..d39f5c0 100644 --- a/bootstrap/frontend/lexical_analyzer.zig +++ b/bootstrap/frontend/lexical_analyzer.zig @@ -50,6 +50,7 @@ pub const Token = packed struct(u64) { fixed_keyword_align = 0x1b, fixed_keyword_export = 0x1c, fixed_keyword_cc = 0x1d, + fixed_keyword_for = 0x1e, keyword_unsigned_integer = 0x1f, keyword_signed_integer = 0x20, bang = '!', // 0x21 @@ -114,6 +115,7 @@ pub const FixedKeyword = enum { @"align", @"export", cc, + @"for", }; pub const Result = struct { diff --git a/bootstrap/frontend/semantic_analyzer.zig b/bootstrap/frontend/semantic_analyzer.zig index b9e9d8f..895c332 100644 --- a/bootstrap/frontend/semantic_analyzer.zig +++ b/bootstrap/frontend/semantic_analyzer.zig @@ -18,6 +18,7 @@ const Field = Compilation.Field; const Function = Compilation.Function; const Intrinsic = Compilation.Intrinsic; const Loop = Compilation.Loop; +const Range = Compilation.Range; const Scope = Compilation.Scope; const ScopeType = Compilation.ScopeType; const Slice = Compilation.Slice; @@ -106,7 +107,9 @@ const Analyzer = struct { current_file: File.Index, current_declaration: Declaration.Index = Declaration.Index.invalid, payloads: ArrayList(Payload) = .{}, + current_block: Block.Index = Block.Index.invalid, maybe_count: usize = 0, + for_count: usize = 0, fn getScopeSourceFile(analyzer: *Analyzer, scope_index: Scope.Index) []const u8 { const scope = analyzer.module.scopes.get(scope_index); @@ -188,14 +191,20 @@ const Analyzer = struct { }); const scope_index = new_scope.index; - var statements = ArrayList(Value.Index){}; + const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{ + .statements = ArrayList(Value.Index){}, + .reaches_end = true, + }); + const block_index = block_allocation.index; + const previous_block = analyzer.current_block; + analyzer.current_block = block_index; for (analyzer.payloads.items) |payload| { const declaration_index = try analyzer.declarationCommon(scope_index, .local, payload.mutability, payload.name, payload.type, payload.value, null); const statement_value_allocation = try analyzer.module.values.append(analyzer.allocator, .{ .declaration = declaration_index, }); - try statements.append(analyzer.allocator, statement_value_allocation.index); + try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, statement_value_allocation.index); } analyzer.payloads.clearRetainingCapacity(); @@ -215,25 +224,9 @@ const Analyzer = struct { const statement_node = analyzer.getScopeNode(scope_index, statement_node_index); logln(.sema, .node, "Trying to resolve statement of id {s}", .{@tagName(statement_node.id)}); + const statement_value_index = switch (statement_node.id) { - .assign => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processAssignment(scope_index, statement_node_index))).index, - .simple_while => blk: { - const loop_allocation = try analyzer.module.loops.append(analyzer.allocator, .{ - .condition = Value.Index.invalid, - .body = Value.Index.invalid, - .breaks = false, - }); - loop_allocation.ptr.condition = (try analyzer.unresolvedAllocate(scope_index, ExpectType.boolean, statement_node.left)).index; - loop_allocation.ptr.body = (try analyzer.unresolvedAllocate(scope_index, ExpectType.none, statement_node.right)).index; - - // TODO: bool true - reaches_end = loop_allocation.ptr.breaks or unreachable; - - const value_allocation = try analyzer.module.values.append(analyzer.allocator, .{ - .loop = loop_allocation.index, - }); - break :blk value_allocation.index; - }, + .assign, .add_assign => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processAssignment(scope_index, statement_node_index))).index, .@"unreachable" => blk: { reaches_end = false; break :blk unreachable_index; @@ -300,7 +293,7 @@ const Analyzer = struct { const if_else_value = try analyzer.processIfElse(scope_index, expect_type, if_else_node_index, payload_node_index); if (if_else_value.maybe_payload_declaration_index) |maybe_payload_declaration| { - try statements.append(analyzer.allocator, maybe_payload_declaration); + try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, maybe_payload_declaration); } const branch = analyzer.module.branches.get(if_else_value.branch); @@ -328,7 +321,7 @@ const Analyzer = struct { const if_expression = try analyzer.processIf(scope_index, expect_type, if_statement_node_index, payload_node_index); if (if_expression.maybe_payload_declaration_value) |maybe_payload_declaration| { - try statements.append(analyzer.allocator, maybe_payload_declaration); + try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, maybe_payload_declaration); } const branch = try analyzer.module.branches.append(analyzer.allocator, .{ @@ -352,18 +345,24 @@ const Analyzer = struct { const value = try analyzer.module.values.append(analyzer.allocator, assembly_value); break :blk value.index; }, + .for_loop => blk: { + const loop_index = try analyzer.forLoop(scope_index, expect_type, statement_node_index); + const value = try analyzer.module.values.append(analyzer.allocator, .{ + .loop = loop_index, + }); + break :blk value.index; + }, else => |t| @panic(@tagName(t)), }; - try statements.append(analyzer.allocator, statement_value_index); + try analyzer.module.blocks.get(block_index).statements.append(analyzer.allocator, statement_value_index); } - const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{ - .statements = statements, - .reaches_end = reaches_end, - }); + analyzer.module.blocks.get(block_index).reaches_end = reaches_end; - return block_allocation.index; + analyzer.current_block = previous_block; + + return block_index; } fn processAssemblyStatements(analyzer: *Analyzer, comptime architecture: type, scope_index: Scope.Index, assembly_statement_nodes: []const Node.Index) ![]Compilation.Assembly.Instruction.Index { @@ -796,6 +795,126 @@ const Analyzer = struct { unreachable; } + fn range(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Range { + const range_node = analyzer.getScopeNode(scope_index, node_index); + assert(range_node.id == .range); + + const expect_type = ExpectType{ + .type_index = Type.usize, + }; + + const range_start = try analyzer.unresolvedAllocate(scope_index, expect_type, range_node.left); + const range_end = try analyzer.unresolvedAllocate(scope_index, expect_type, range_node.right); + + return Range{ + .start = range_start.index, + .end = range_end.index, + }; + } + + fn forLoop(analyzer: *Analyzer, parent_scope_index: Scope.Index, expect_type: ExpectType, for_node_index: Node.Index) !Loop.Index { + const for_loop_node = analyzer.getScopeNode(parent_scope_index, for_node_index); + assert(for_loop_node.id == .for_loop); + + const scope_allocation = try analyzer.allocateScope(.{ + .token = for_loop_node.token, + .file = analyzer.module.scopes.get(parent_scope_index).file, + .parent = parent_scope_index, + }); + const scope_index = scope_allocation.index; + const for_condition_node = analyzer.getScopeNode(scope_index, for_loop_node.left); + assert(for_condition_node.id == .for_condition); + + const for_loop_element_node = analyzer.getScopeNode(scope_index, for_condition_node.left); + var pre = Value.Index.invalid; + const for_condition = switch (for_loop_element_node.id) { + .range => blk: { + const for_range = try analyzer.range(scope_index, for_condition_node.left); + + const for_loop_payload_node = analyzer.getScopeNode(scope_index, for_condition_node.right); + const payload_name = switch (for_loop_payload_node.id) { + .node_list => b: { + const nodes = analyzer.getScopeNodeList(scope_index, for_loop_payload_node); + assert(nodes.items.len == 1); + const payload_node = analyzer.getScopeNode(scope_index, nodes.items[0]); + const result = analyzer.tokenIdentifier(scope_index, payload_node.token); + break :b result; + }, + else => |t| @panic(@tagName(t)), + }; + const declaration_index = try analyzer.declarationCommon(scope_index, .local, .@"var", payload_name, Type.usize, for_range.start, null); + const declaration_value = try analyzer.module.values.append(analyzer.allocator, .{ + .declaration = declaration_index, + }); + pre = declaration_value.index; + + const binary_condition = try analyzer.module.binary_operations.append(analyzer.allocator, .{ + .id = .compare_less_than, + .type = Type.boolean, + .left = try analyzer.doIdentifierString(scope_index, ExpectType{ + .type_index = Type.usize, + }, payload_name), + .right = for_range.end, + }); + + const condition = try analyzer.module.values.append(analyzer.allocator, .{ + .binary_operation = binary_condition.index, + }); + break :blk condition.index; + }, + else => |t| @panic(@tagName(t)), + }; + + const for_loop_body = try analyzer.unresolvedAllocate(scope_index, expect_type, for_loop_node.right); + var post = Value.Index.invalid; + switch (for_loop_element_node.id) { + .range => { + const for_condition_value = analyzer.module.values.get(for_condition); + switch (for_condition_value.*) { + .binary_operation => |binary_operation_index| { + const binary_operation = analyzer.module.binary_operations.get(binary_operation_index); + const left = binary_operation.left; + const right = try analyzer.module.values.append(analyzer.allocator, .{ + .integer = .{ + .value = 1, + .type = Type.usize, + .signedness = .unsigned, + }, + }); + + const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{ + .operation = .add, + .destination = left, + .source = right.index, + }); + + const assignment_value = try analyzer.module.values.append(analyzer.allocator, .{ + .assign = assignment.index, + }); + post = assignment_value.index; + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + + const reaches_end = switch (for_loop_body.ptr.*) { + .block => |block_index| analyzer.module.blocks.get(block_index).reaches_end, + else => |t| @panic(@tagName(t)), + }; + + const loop = try analyzer.module.loops.append(analyzer.allocator, .{ + .pre = pre, + .condition = for_condition, + .body = for_loop_body.index, + .reaches_end = reaches_end, + .post = post, + }); + + return loop.index; + } + const If = struct { maybe_payload_declaration_value: ?Value.Index, expression: Value.Index, @@ -935,11 +1054,11 @@ const Analyzer = struct { fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value { const node = analyzer.getScopeNode(scope_index, node_index); - assert(node.id == .assign); assert(!node.left.invalid); const left_node = analyzer.getScopeNode(scope_index, node.left); switch (left_node.id) { .discard => { + assert(node.id == .assign); var result = Value{ .unresolved = .{ .node_index = node.right, @@ -964,6 +1083,11 @@ const Analyzer = struct { const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{ .destination = left.index, .source = right.index, + .operation = switch (node.id) { + .assign => .none, + .add_assign => .add, + else => unreachable, + }, }); return Value{ @@ -1734,15 +1858,10 @@ const Analyzer = struct { .pointer => |pointer| pointer.element_type, else => |t| @panic(@tagName(t)), }; - const slice_range_node = analyzer.getScopeNode(scope_index, node.right); - assert(slice_range_node.id == .slice_range); - const slice_range_start = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, slice_range_node.left); - const slice_range_end = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, slice_range_node.right); const slice = try analyzer.module.slices.append(analyzer.allocator, .{ .sliceable = expression_to_slice.index, - .start = slice_range_start.index, - .end = slice_range_end.index, + .range = try analyzer.range(scope_index, node.right), .type = try analyzer.getSliceType(.{ .element_type = element_type, .@"const" = true, diff --git a/bootstrap/frontend/syntactic_analyzer.zig b/bootstrap/frontend/syntactic_analyzer.zig index 9208723..e919af3 100644 --- a/bootstrap/frontend/syntactic_analyzer.zig +++ b/bootstrap/frontend/syntactic_analyzer.zig @@ -165,7 +165,7 @@ pub const Node = struct { if_payload, discard, slice, - slice_range, + range, negation, anonymous_container_literal, const_single_pointer_type, @@ -175,6 +175,9 @@ pub const Node = struct { assembly_register, assembly_statement, assembly_block, + for_condition, + for_loop, + add_assign, }; }; @@ -429,7 +432,7 @@ const Analyzer = struct { return result; } - fn block(analyzer: *Analyzer, options: Options) !Node.Index { + fn block(analyzer: *Analyzer, options: Options) anyerror!Node.Index { const left_brace = try analyzer.expectToken(.left_brace); var list = ArrayList(Node.Index){}; @@ -448,6 +451,7 @@ const Analyzer = struct { .fixed_keyword_while => try analyzer.whileExpression(options), .fixed_keyword_switch => try analyzer.switchExpression(), .fixed_keyword_if => try analyzer.ifExpression(), + .fixed_keyword_for => try analyzer.forExpression(), .fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(), .hash => blk: { const intrinsic = try analyzer.compilerIntrinsic(); @@ -620,23 +624,117 @@ const Analyzer = struct { } } - fn assignExpression(analyzer: *Analyzer) !Node.Index { - const expr = try analyzer.expression(); - const expression_id: Node.Id = switch (analyzer.tokens[analyzer.token_i].id) { - .semicolon, .comma => return expr, - .equal => .assign, + fn forExpression(analyzer: *Analyzer) !Node.Index { + const token = try analyzer.expectToken(.fixed_keyword_for); + _ = try analyzer.expectToken(.left_parenthesis); + const expression_token = analyzer.token_i; + const first = try analyzer.expression(); + const ForExpression = struct { + node_index: Node.Index, + expected_payload_count: usize, + }; + const for_expression = switch (analyzer.tokens[analyzer.token_i].id) { + .period => switch (analyzer.tokens[analyzer.token_i + 1].id) { + .period => blk: { + analyzer.token_i += 2; + const second = try analyzer.expression(); + + break :blk ForExpression{ + .node_index = try analyzer.addNode(.{ + .id = .range, + .token = expression_token, + .left = first, + .right = second, + }), + .expected_payload_count = 1, + }; + }, + else => |t| @panic(@tagName(t)), + }, else => |t| @panic(@tagName(t)), }; + _ = try analyzer.expectToken(.right_parenthesis); + + _ = try analyzer.expectToken(.vertical_bar); + + var payload_nodes = ArrayList(Node.Index){}; + while (analyzer.tokens[analyzer.token_i].id != .vertical_bar) { + const payload_identifier = try analyzer.expectToken(.identifier); + + switch (analyzer.tokens[analyzer.token_i].id) { + .vertical_bar => {}, + .comma => analyzer.token_i += 1, + else => |t| @panic(@tagName(t)), + } + + try payload_nodes.append(analyzer.allocator, try analyzer.addNode(.{ + .id = .identifier, + .token = payload_identifier, + .left = Node.Index.invalid, + .right = Node.Index.invalid, + })); + } + + _ = try analyzer.expectToken(.vertical_bar); + + if (payload_nodes.items.len != for_expression.expected_payload_count) { + unreachable; + } + + const for_condition_node = try analyzer.addNode(.{ + .id = .for_condition, + .token = token, + .left = for_expression.node_index, + .right = try analyzer.nodeList(payload_nodes), + }); + + const for_content_node = switch (analyzer.tokens[analyzer.token_i].id) { + .left_brace => try analyzer.block(.{ + .is_comptime = false, + }), + else => blk: { + const for_content_expression = try analyzer.expression(); + _ = try analyzer.expectToken(.semicolon); + break :blk for_content_expression; + }, + }; + + const for_node = try analyzer.addNode(.{ + .id = .for_loop, + .token = token, + .left = for_condition_node, + .right = for_content_node, + }); + + return for_node; + } + + fn assignExpression(analyzer: *Analyzer) !Node.Index { + const left = try analyzer.expression(); + const expression_token = analyzer.token_i; + const expression_id: Node.Id = switch (analyzer.tokens[expression_token].id) { + .semicolon, .comma => return left, + .equal => .assign, + .plus => switch (analyzer.tokens[analyzer.token_i + 1].id) { + .equal => blk: { + analyzer.token_i += 1; + break :blk .add_assign; + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + }; + + analyzer.token_i += 1; + + const right = try analyzer.expression(); + const node = Node{ .id = expression_id, - .token = blk: { - const token_i = analyzer.token_i; - analyzer.token_i += 1; - break :blk token_i; - }, - .left = expr, - .right = try analyzer.expression(), + .token = expression_token, + .left = left, + .right = right, }; logln(.parser, .assign, "assign:\nleft: {}.\nright: {}", .{ node.left, node.right }); @@ -837,6 +935,7 @@ const Analyzer = struct { .comma, .fixed_keyword_const, .fixed_keyword_var, + .fixed_keyword_return, .identifier, => break, else => blk: { @@ -854,7 +953,7 @@ const Analyzer = struct { }, .plus => switch (next_token_id) { .plus => unreachable, - .equal => unreachable, + .equal => break, else => .add, }, .minus => switch (next_token_id) { @@ -1470,7 +1569,7 @@ const Analyzer = struct { .token = token, .left = left, .right = try analyzer.addNode(.{ - .id = .slice_range, + .id = .range, .token = token, .left = index_expression, .right = range_end_expression, diff --git a/build.zig b/build.zig index f977860..edad48c 100644 --- a/build.zig +++ b/build.zig @@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void { all = b.option(bool, "all", "All") orelse false; const target = b.standardTargetOptions(.{}); const optimization = b.standardOptimizeOption(.{}); - const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse false; + const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true; const exe = b.addExecutable(.{ .name = "nativity", .root_source_file = .{ .path = "bootstrap/main.zig" }, diff --git a/test/foreach/main.nat b/test/foreach/main.nat new file mode 100644 index 0000000..4f39fb7 --- /dev/null +++ b/test/foreach/main.nat @@ -0,0 +1,10 @@ +const main = fn () s32 { + var counter: s32 = 0; + const loop = 10; + + for (0..loop) |_| { + counter += 1; + } + + return loop - counter; +}