diff --git a/README.md b/README.md index 776bafb..e1a848f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Ziglings +-> Fix originally by [nerdman](https://codeberg.org/nerdman) from [this issue](https://codeberg.org/ziglings/exercises/issues/127). + Welcome to Ziglings! This project contains a series of tiny broken programs (and one nasty surprise). By fixing them, you'll learn how to read and write [Zig](https://ziglang.org/) code. diff --git a/build.zig b/build.zig index b40f8bd..6b65c9e 100644 --- a/build.zig +++ b/build.zig @@ -274,7 +274,7 @@ const ZiglingStep = struct { return self; } - fn make(step: *Step, prog_node: std.Progress.Node) !void { + fn make(step: *Step, options: Step.MakeOptions) !void { // NOTE: Using exit code 2 will prevent the Zig compiler to print the message: // "error: the following build command failed with exit code 1:..." const self: *ZiglingStep = @alignCast(@fieldParentPtr("step", step)); @@ -285,7 +285,7 @@ const ZiglingStep = struct { return; } - const exe_path = self.compile(prog_node) catch { + const exe_path = self.compile(options) catch { self.printErrors(); if (self.exercise.hint) |hint| @@ -295,7 +295,7 @@ const ZiglingStep = struct { std.process.exit(2); }; - self.run(exe_path.?, prog_node) catch { + self.run(exe_path.?, options.progress_node) catch { self.printErrors(); if (self.exercise.hint) |hint| @@ -405,7 +405,7 @@ const ZiglingStep = struct { print("{s}PASSED{s}\n\n", .{ green_text, reset_text }); } - fn compile(self: *ZiglingStep, prog_node: std.Progress.Node) !?[]const u8 { + fn compile(self: *ZiglingStep, options: Step.MakeOptions) !?[]const u8 { print("Compiling: {s}\n", .{self.exercise.main_file}); const b = self.step.owner; @@ -436,7 +436,7 @@ const ZiglingStep = struct { zig_args.append("--listen=-") catch @panic("OOM"); - return try self.step.evalZigProcess(zig_args.items, prog_node); + return try self.step.evalZigProcess(zig_args.items, options.progress_node, false); } fn help(self: *ZiglingStep) void { @@ -525,7 +525,7 @@ const PrintStep = struct { return self; } - fn make(step: *Step, _: std.Progress.Node) !void { + fn make(step: *Step, _: Step.MakeOptions) !void { const self: *PrintStep = @alignCast(@fieldParentPtr("step", step)); print("{s}", .{self.message}); } diff --git a/exercises/047_methods.zig b/exercises/047_methods.zig index 3221ca2..3a2bac5 100644 --- a/exercises/047_methods.zig +++ b/exercises/047_methods.zig @@ -88,7 +88,7 @@ pub fn main() void { for (&aliens) |*alien| { // *** Zap the alien with the heat ray here! *** - ???.zap(???); + heat_ray.zap(alien); // If the alien's health is still above 0, it's still alive. if (alien.health > 0) aliens_alive += 1; diff --git a/exercises/048_methods2.zig b/exercises/048_methods2.zig index a1fbe9e..f0ce821 100644 --- a/exercises/048_methods2.zig +++ b/exercises/048_methods2.zig @@ -54,7 +54,7 @@ fn visitElephants(first_elephant: *Elephant) void { // This gets the next elephant or stops: // which method do we want here? - e = if (e.hasTail()) e.??? else break; + e = if (e.hasTail()) e.getTail() else break; } } diff --git a/exercises/049_quiz6.zig b/exercises/049_quiz6.zig index 9dbea51..2da18de 100644 --- a/exercises/049_quiz6.zig +++ b/exercises/049_quiz6.zig @@ -27,7 +27,13 @@ const Elephant = struct { // Your Elephant trunk methods go here! // --------------------------------------------------- - ??? + pub fn getTrunk(self: *Elephant) *Elephant { + return self.trunk.?; + } + + pub fn hasTrunk(self: *Elephant) bool { + return (self.trunk != null); + } // --------------------------------------------------- diff --git a/exercises/050_no_value.zig b/exercises/050_no_value.zig index 8c73ed3..80d20eb 100644 --- a/exercises/050_no_value.zig +++ b/exercises/050_no_value.zig @@ -65,10 +65,10 @@ const std = @import("std"); const Err = error{Cthulhu}; pub fn main() void { - var first_line1: *const [16]u8 = ???; + var first_line1: *const [16]u8 = undefined; first_line1 = "That is not dead"; - var first_line2: Err!*const [21]u8 = ???; + var first_line2: Err!*const [21]u8 = Err.Cthulhu; first_line2 = "which can eternal lie"; // Note we need the "{!s}" format for the error union string. @@ -77,8 +77,8 @@ pub fn main() void { printSecondLine(); } -fn printSecondLine() ??? { - var second_line2: ?*const [18]u8 = ???; +fn printSecondLine() void { + var second_line2: ?*const [18]u8 = null; second_line2 = "even death may die"; std.debug.print("And with strange aeons {s}.\n", .{second_line2.?}); diff --git a/exercises/051_values.zig b/exercises/051_values.zig index 4e98d8e..debd521 100644 --- a/exercises/051_values.zig +++ b/exercises/051_values.zig @@ -87,7 +87,7 @@ pub fn main() void { // Let's assign the std.debug.print function to a const named // "print" so that we can use this new name later! - const print = ???; + const print = std.debug.print; // Now let's look at assigning and pointing to values in Zig. // @@ -163,13 +163,13 @@ pub fn main() void { print("XP before:{}, ", .{glorp.experience}); // Fix 1 of 2 goes here: - levelUp(glorp, reward_xp); + levelUp(&glorp, reward_xp); print("after:{}.\n", .{glorp.experience}); } // Fix 2 of 2 goes here: -fn levelUp(character_access: Character, xp: u32) void { +fn levelUp(character_access: *Character, xp: u32) void { character_access.experience += xp; } diff --git a/exercises/052_slices.zig b/exercises/052_slices.zig index af5930b..0645e55 100644 --- a/exercises/052_slices.zig +++ b/exercises/052_slices.zig @@ -32,8 +32,8 @@ pub fn main() void { var cards = [8]u8{ 'A', '4', 'K', '8', '5', '2', 'Q', 'J' }; // Please put the first 4 cards in hand1 and the rest in hand2. - const hand1: []u8 = cards[???]; - const hand2: []u8 = cards[???]; + const hand1: []u8 = cards[0..4]; + const hand2: []u8 = cards[4..8]; std.debug.print("Hand1: ", .{}); printHand(hand1); @@ -43,7 +43,7 @@ pub fn main() void { } // Please lend this function a hand. A u8 slice hand, that is. -fn printHand(hand: ???) void { +fn printHand(hand: []u8) void { for (hand) |h| { std.debug.print("{u} ", .{h}); } diff --git a/exercises/053_slices2.zig b/exercises/053_slices2.zig index 545b4da..924f6a3 100644 --- a/exercises/053_slices2.zig +++ b/exercises/053_slices2.zig @@ -17,19 +17,19 @@ const std = @import("std"); pub fn main() void { const scrambled = "great base for all your justice are belong to us"; - const base1: []u8 = scrambled[15..23]; - const base2: []u8 = scrambled[6..10]; - const base3: []u8 = scrambled[32..]; + const base1: []const u8 = scrambled[15..23]; + const base2: []const u8 = scrambled[6..10]; + const base3: []const u8 = scrambled[32..]; printPhrase(base1, base2, base3); - const justice1: []u8 = scrambled[11..14]; - const justice2: []u8 = scrambled[0..5]; - const justice3: []u8 = scrambled[24..31]; + const justice1: []const u8 = scrambled[11..14]; + const justice2: []const u8 = scrambled[0..5]; + const justice3: []const u8 = scrambled[24..31]; printPhrase(justice1, justice2, justice3); std.debug.print("\n", .{}); } -fn printPhrase(part1: []u8, part2: []u8, part3: []u8) void { +fn printPhrase(part1: []const u8, part2: []const u8, part3: []const u8) void { std.debug.print("'{s} {s} {s}.' ", .{ part1, part2, part3 }); } diff --git a/exercises/054_manypointers.zig b/exercises/054_manypointers.zig index ede02df..63a9745 100644 --- a/exercises/054_manypointers.zig +++ b/exercises/054_manypointers.zig @@ -33,7 +33,7 @@ pub fn main() void { // we can CONVERT IT TO A SLICE. (Hint: we do know the length!) // // Please fix this line so the print statement below can print it: - const zen12_string: []const u8 = zen_manyptr; + const zen12_string: []const u8 = zen_manyptr[0..21]; // Here's the moment of truth! std.debug.print("{s}\n", .{zen12_string}); diff --git a/exercises/055_unions.zig b/exercises/055_unions.zig index 794f2df..a88cd2f 100644 --- a/exercises/055_unions.zig +++ b/exercises/055_unions.zig @@ -59,8 +59,8 @@ pub fn main() void { std.debug.print("Insect report! ", .{}); // Oops! We've made a mistake here. - printInsect(ant, AntOrBee.c); - printInsect(bee, AntOrBee.c); + printInsect(ant, AntOrBee.a); + printInsect(bee, AntOrBee.b); std.debug.print("\n", .{}); } diff --git a/exercises/056_unions2.zig b/exercises/056_unions2.zig index c46d133..bebc833 100644 --- a/exercises/056_unions2.zig +++ b/exercises/056_unions2.zig @@ -44,14 +44,14 @@ pub fn main() void { std.debug.print("Insect report! ", .{}); // Could it really be as simple as just passing the union? - printInsect(???); - printInsect(???); + printInsect(ant); + printInsect(bee); std.debug.print("\n", .{}); } fn printInsect(insect: Insect) void { - switch (???) { + switch (insect) { .still_alive => |a| std.debug.print("Ant alive is: {}. ", .{a}), .flowers_visited => |f| std.debug.print("Bee visited {} flowers. ", .{f}), } diff --git a/exercises/057_unions3.zig b/exercises/057_unions3.zig index a5017d2..0c3c3b2 100644 --- a/exercises/057_unions3.zig +++ b/exercises/057_unions3.zig @@ -15,7 +15,7 @@ // const std = @import("std"); -const Insect = union(InsectStat) { +const Insect = union(enum) { flowers_visited: u16, still_alive: bool, }; diff --git a/exercises/058_quiz7.zig b/exercises/058_quiz7.zig index cf32fc3..1fc5d85 100644 --- a/exercises/058_quiz7.zig +++ b/exercises/058_quiz7.zig @@ -192,8 +192,8 @@ const TripItem = union(enum) { // Oops! The hermit forgot how to capture the union values // in a switch statement. Please capture both values as // 'p' so the print statements work! - .place => print("{s}", .{p.name}), - .path => print("--{}->", .{p.dist}), + .place => |p| print("{s}", .{p.name}), + .path => |p| print("--{}->", .{p.dist}), } } }; @@ -255,7 +255,7 @@ const HermitsNotebook = struct { // dereference and optional value "unwrapping" look // together. Remember that you return the address with the // "&" operator. - if (place == entry.*.?.place) return entry; + if (place == entry.*.?.place) return &entry.*.?; // Try to make your answer this long:__________; } return null; @@ -309,7 +309,7 @@ const HermitsNotebook = struct { // // Looks like the hermit forgot something in the return value of // this function. What could that be? - fn getTripTo(self: *HermitsNotebook, trip: []?TripItem, dest: *Place) void { + fn getTripTo(self: *HermitsNotebook, trip: []?TripItem, dest: *Place) TripError!void { // We start at the destination entry. const destination_entry = self.getEntry(dest); diff --git a/exercises/059_integers.zig b/exercises/059_integers.zig index ae65790..51b90cc 100644 --- a/exercises/059_integers.zig +++ b/exercises/059_integers.zig @@ -20,9 +20,9 @@ const print = @import("std").debug.print; pub fn main() void { const zig = [_]u8{ - 0o131, // octal - 0b1101000, // binary - 0x66, // hex + 'Z', // octal + 'i', // binary + 'g', // hex }; print("{s} is cool.\n", .{zig}); diff --git a/exercises/060_floats.zig b/exercises/060_floats.zig index 6f341ad..0754323 100644 --- a/exercises/060_floats.zig +++ b/exercises/060_floats.zig @@ -43,7 +43,7 @@ pub fn main() void { // // We'll convert this weight from pound to kilograms at a // conversion of 0.453592kg to the pound. - const shuttle_weight: f16 = 0.453592 * 4480e6; + const shuttle_weight: f32 = 0.453592 * 4480e3; // By default, float values are formatted in scientific // notation. Try experimenting with '{d}' and '{d:.3}' to see diff --git a/exercises/061_coercions.zig b/exercises/061_coercions.zig index ccf3c9b..0ecf542 100644 --- a/exercises/061_coercions.zig +++ b/exercises/061_coercions.zig @@ -67,7 +67,7 @@ const print = @import("std").debug.print; pub fn main() void { var letter: u8 = 'A'; - const my_letter: ??? = &letter; + const my_letter: ?*[1]u8 = &letter; // ^^^^^^^ // Your type here. // Must coerce from &letter (which is a *u8). diff --git a/exercises/062_loop_expressions.zig b/exercises/062_loop_expressions.zig index f6b8771..8c37e28 100644 --- a/exercises/062_loop_expressions.zig +++ b/exercises/062_loop_expressions.zig @@ -47,7 +47,7 @@ pub fn main() void { // return it from the for loop. const current_lang: ?[]const u8 = for (langs) |lang| { if (lang.len == 3) break lang; - }; + } else null; if (current_lang) |cl| { print("Current language: {s}\n", .{cl}); diff --git a/exercises/063_labels.zig b/exercises/063_labels.zig index 79adfaa..a131101 100644 --- a/exercises/063_labels.zig +++ b/exercises/063_labels.zig @@ -128,8 +128,8 @@ pub fn main() void { // wanted for this Food. // // Please return this Food from the loop. - break; - }; + break food; + } else menu[0]; // ^ Oops! We forgot to return Mac & Cheese as the default // Food when the requested ingredients aren't found. diff --git a/exercises/064_builtins.zig b/exercises/064_builtins.zig index e91dfbe..ba3c8dc 100644 --- a/exercises/064_builtins.zig +++ b/exercises/064_builtins.zig @@ -63,7 +63,7 @@ pub fn main() void { // // If there was no overflow at all while adding 5 to a, what value would // 'my_result' hold? Write the answer in into 'expected_result'. - const expected_result: u8 = ???; + const expected_result: u8 = 18; print(". Without overflow: {b:0>8}. ", .{expected_result}); print("Furthermore, ", .{}); @@ -78,6 +78,6 @@ pub fn main() void { // Now it's your turn. See if you can fix this attempt to use // this builtin to reverse the bits of a u8 integer. const input: u8 = 0b11110000; - const tupni: u8 = @bitReverse(input, tupni); + const tupni: u8 = @bitReverse(input); print("{b:0>8} backwards is {b:0>8}.\n", .{ input, tupni }); } diff --git a/exercises/065_builtins2.zig b/exercises/065_builtins2.zig index 283aca5..a2dc705 100644 --- a/exercises/065_builtins2.zig +++ b/exercises/065_builtins2.zig @@ -58,7 +58,7 @@ pub fn main() void { // Oops! We cannot leave the 'me' and 'myself' fields // undefined. Please set them here: narcissus.me = &narcissus; - narcissus.??? = ???; + narcissus.myself = &narcissus; // This determines a "peer type" from three separate // references (they just happen to all be the same object). @@ -70,7 +70,7 @@ pub fn main() void { // // The fix for this is very subtle, but it makes a big // difference! - const Type2 = narcissus.fetchTheMostBeautifulType(); + const Type2 = Narcissus.fetchTheMostBeautifulType(); // Now we print a pithy statement about Narcissus. print("A {s} loves all {s}es. ", .{ @@ -109,15 +109,15 @@ pub fn main() void { // Please complete these 'if' statements so that the field // name will not be printed if the field is of type 'void' // (which is a zero-bit type that takes up no space at all!): - if (fields[0].??? != void) { + if (fields[0].type != void) { print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name}); } - if (fields[1].??? != void) { + if (fields[1].type != void) { print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name}); } - if (fields[2].??? != void) { + if (fields[2].type != void) { print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name}); } diff --git a/exercises/066_comptime.zig b/exercises/066_comptime.zig index 9b07a2d..124b472 100644 --- a/exercises/066_comptime.zig +++ b/exercises/066_comptime.zig @@ -62,8 +62,8 @@ pub fn main() void { // types with specific sizes. The comptime numbers will be // coerced (if they'll fit!) into your chosen runtime types. // For this it is necessary to specify a size, e.g. 32 bit. - var var_int = 12345; - var var_float = 987.654; + var var_int: u32 = 12345; + var var_float: f32 = 987.654; // We can change what is stored at the areas set aside for // "var_int" and "var_float" in the running compiled program. diff --git a/exercises/067_comptime2.zig b/exercises/067_comptime2.zig index 6b9b14a..7867902 100644 --- a/exercises/067_comptime2.zig +++ b/exercises/067_comptime2.zig @@ -35,7 +35,7 @@ pub fn main() void { // In this contrived example, we've decided to allocate some // arrays using a variable count! But something's missing... // - var count = 0; + comptime var count = 0; count += 1; const a1: [count]u8 = .{'A'} ** count; @@ -60,5 +60,5 @@ pub fn main() void { // // Try uncommenting this line and playing around with it // (copy it, move it) to see what it does: - //@compileLog("Count at compile time: ", count); + // @compileLog("Count at compile time: ", count); } diff --git a/exercises/068_comptime3.zig b/exercises/068_comptime3.zig index 15b8997..1bd5fd1 100644 --- a/exercises/068_comptime3.zig +++ b/exercises/068_comptime3.zig @@ -43,7 +43,7 @@ const Schooner = struct { // // Please change this so that it sets a 0 scale to 1 // instead. - if (my_scale == 0) @compileError("Scale 1:0 is not valid!"); + if (my_scale == 0) my_scale = 1; self.scale = my_scale; self.hull_length /= my_scale; @@ -69,7 +69,7 @@ pub fn main() void { // Hey, we can't just pass this runtime variable as an // argument to the scaleMe() method. What would let us do // that? - var scale: u32 = undefined; + comptime var scale: u32 = undefined; scale = 32; // 1:32 scale diff --git a/exercises/069_comptime4.zig b/exercises/069_comptime4.zig index e090bb3..0263de0 100644 --- a/exercises/069_comptime4.zig +++ b/exercises/069_comptime4.zig @@ -42,8 +42,8 @@ pub fn main() void { // 2) Sets the size of the array of type T (which is the // sequence we're creating and returning). // -fn makeSequence(comptime T: type, ??? size: usize) [???]T { - var sequence: [???]T = undefined; +fn makeSequence(comptime T: type, comptime size: usize) [size]T { + var sequence: [size]T = undefined; var i: usize = 0; while (i < size) : (i += 1) { diff --git a/exercises/070_comptime5.zig b/exercises/070_comptime5.zig index afd4ae8..c6bc4bb 100644 --- a/exercises/070_comptime5.zig +++ b/exercises/070_comptime5.zig @@ -123,8 +123,8 @@ fn isADuck(possible_duck: anytype) bool { // Please make sure MyType has both waddle() and quack() // methods: const MyType = @TypeOf(possible_duck); - const walks_like_duck = ???; - const quacks_like_duck = ???; + const walks_like_duck = @hasDecl(MyType, "waddle"); + const quacks_like_duck = @hasDecl(MyType, "quack"); const is_duck = walks_like_duck and quacks_like_duck; diff --git a/exercises/071_comptime6.zig b/exercises/071_comptime6.zig index 7723291..d467184 100644 --- a/exercises/071_comptime6.zig +++ b/exercises/071_comptime6.zig @@ -40,7 +40,7 @@ pub fn main() void { const fields = @typeInfo(Narcissus).Struct.fields; - ??? { + inline for (fields) |field| { if (field.type != void) { print(" {s}", .{field.name}); } diff --git a/exercises/072_comptime7.zig b/exercises/072_comptime7.zig index 631e75b..1bdcc1a 100644 --- a/exercises/072_comptime7.zig +++ b/exercises/072_comptime7.zig @@ -35,7 +35,7 @@ pub fn main() void { // at compile time. // // Please fix this to loop once per "instruction": - ??? (i < instructions.len) : (???) { + inline while (i < instructions.len) : (i += 3) { // This gets the digit from the "instruction". Can you // figure out why we subtract '0' from it? diff --git a/test/tests.zig b/test/tests.zig index 126a1cd..d714085 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -36,7 +36,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step { b.graph.zig_exe, "build", "-Dhealed", - b.fmt("-Dhealed-path={s}", .{tmp_path}), + b.fmt("-Dhealed-path={s}", .{tmp_path.src_path.sub_path}), b.fmt("-Dn={}", .{n}), }); cmd.setName(b.fmt("zig build -Dhealed -Dn={}", .{n})); @@ -72,7 +72,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step { b.graph.zig_exe, "build", "-Dhealed", - b.fmt("-Dhealed-path={s}", .{tmp_path}), + b.fmt("-Dhealed-path={s}", .{tmp_path.src_path.sub_path}), }); cmd.setName("zig build -Dhealed"); cmd.expectExitCode(0); @@ -150,7 +150,7 @@ const CheckNamedStep = struct { return self; } - fn make(step: *Step, _: std.Progress.Node) !void { + fn make(step: *Step, _: Step.MakeOptions) !void { const b = step.owner; const self: *CheckNamedStep = @alignCast(@fieldParentPtr("step", step)); const ex = self.exercise; @@ -202,7 +202,7 @@ const CheckStep = struct { return self; } - fn make(step: *Step, _: std.Progress.Node) !void { + fn make(step: *Step, _: Step.MakeOptions) !void { const b = step.owner; const self: *CheckStep = @alignCast(@fieldParentPtr("step", step)); const exercises = self.exercises; @@ -325,7 +325,7 @@ const FailStep = struct { return self; } - fn make(step: *Step, _: std.Progress.Node) !void { + fn make(step: *Step, _: Step.MakeOptions) !void { const b = step.owner; const self: *FailStep = @alignCast(@fieldParentPtr("step", step)); @@ -352,7 +352,7 @@ const HealStep = struct { exercises: []const Exercise, work_path: []const u8, - pub fn create(owner: *Build, exercises: []const Exercise, work_path: []const u8) *HealStep { + pub fn create(owner: *Build, exercises: []const Exercise, work_path: LazyPath) *HealStep { const self = owner.allocator.create(HealStep) catch @panic("OOM"); self.* = .{ .step = Step.init(.{ @@ -362,13 +362,13 @@ const HealStep = struct { .makeFn = make, }), .exercises = exercises, - .work_path = work_path, + .work_path = work_path.src_path.sub_path, }; return self; } - fn make(step: *Step, _: std.Progress.Node) !void { + fn make(step: *Step, _: Step.MakeOptions) !void { const b = step.owner; const self: *HealStep = @alignCast(@fieldParentPtr("step", step)); @@ -403,12 +403,17 @@ fn heal(allocator: Allocator, exercises: []const Exercise, work_path: []const u8 /// This function is the same as the one in std.Build.makeTempPath, with the /// difference that returns an error when the temp path cannot be created. -pub fn makeTempPath(b: *Build) ![]const u8 { +pub fn makeTempPath(b: *Build) !LazyPath { const rand_int = std.crypto.random.int(u64); const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ Build.hex64(rand_int); const path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM"); try b.cache_root.handle.makePath(tmp_dir_sub_path); - return path; + return LazyPath{ + .src_path = .{ + .owner = b, + .sub_path = path, + }, + }; }