9 Commits

Author SHA1 Message Date
Chris Boesch
83a89702b2 Merge pull request 'Improve command line style' (#451) from manliop/exercises:improve-command-line-style into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/451
2026-06-06 22:11:53 +02:00
Manlio Perillo
72a441a6bd Improve command line style
Parse the command line following the code from the Zig compiler cli.

Use the args iterator instead of slice, and use while instead of for
loop.

Use the new std.mem.cutPrefix instead of the custom function prefix.

Move Context struct to the top.
2026-06-06 17:39:42 +02:00
Chris Boesch
6aaf048935 Merge pull request 'removed unnecessary shell prompt' (#449) from readme-fixes into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/449
2026-06-04 20:17:48 +02:00
Chris Boesch
febc5e8bd2 removed unnecessary shell prompt 2026-06-04 20:16:35 +02:00
Chris Boesch
b7ff71cb9e Merge pull request 'Fix exercises 65, 71, 82 due to the build system update' (#443) from mark2185/exercises:fix-build-update into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/443
2026-06-03 18:37:25 +02:00
Chris Boesch
a403436fe8 Merge branch 'main' into fix-build-update 2026-06-03 17:39:58 +02:00
Luka Markušić
3b865a0c17 Fix 082_anonymous_structs3.zig because of new build system 2026-06-01 16:00:27 +02:00
Luka Markušić
63c798637c Fix 071_comptime6.zig because of new build system 2026-06-01 15:37:05 +02:00
Luka Markušić
4480762e83 Fix 065_builtins2.zig because of new build system 2026-06-01 15:34:01 +02:00
8 changed files with 94 additions and 108 deletions

View File

@@ -44,7 +44,7 @@ in that case, you can download it directly from the [build directory](https://zi
Verify the installation and build number of `zig` like so:
```
$ zig version
zig version
0.17.0-dev.xxxx+xxxxxxxxx
```

View File

@@ -93,36 +93,25 @@ pub fn main() void {
print("He has room in his heart for:", .{});
// A StructFields array
const fields = @typeInfo(Narcissus).@"struct".fields;
// `field_names` is a slice of strings and it holds the names of the struct's fields
// `field_types` is a slice of strings and it holds the types of the struct's fields,
// it is guaranteed to be the same length as `field_names`
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
// 'fields' is a slice of StructFields. Here's the declaration:
//
// pub const StructField = struct {
// name: [:0]const u8, // Don't worry about `:0` yet!
// type: type,
// default_value_ptr: ?*const anyopaque,
// is_comptime: bool,
// alignment: comptime_int,
//
// defaultValue() ?sf.type // Function that loads the
// // field's default value from
// // `default_value_ptr`
// };
//
// 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) {
print(" {s}", .{fields[0].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
if (fields[1].??? != void) {
print(" {s}", .{fields[1].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
if (fields[2].??? != void) {
print(" {s}", .{fields[2].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
// Yuck, look at all that repeated code above! I don't know

View File

@@ -36,13 +36,14 @@ pub fn main() void {
// statement was repeated three times almost verbatim. Yuck!
//
// Please use an 'inline for' to implement the block below
// for each field in the slice 'fields'!
// for each field in the corresponding slices (they're of the same length)!
const fields = @typeInfo(Narcissus).@"struct".fields;
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
??? {
if (field.type != void) {
print(" {s}", .{field.name});
if (field_type != void) {
print(" {s}", .{field_name});
}
}

View File

@@ -74,36 +74,27 @@ fn printTuple(tuple: anytype) void {
// @typeInfo() - takes a type, returns a TypeInfo union
// with fields specific to that type.
//
// The list of a struct type's fields can be found in
// TypeInfo's @"struct".fields.
// The list of a struct type's field types can be found in
// TypeInfo's @"struct".field_types.
//
// Example:
//
// @typeInfo(Circle).@"struct".fields
// @typeInfo(Circle).@"struct".field_types
//
// This will be an array of StructFields.
const fields = ???;
// This will be an array of field types.
const field_types = ???;
// This will be an array of field names.
const field_names = ???;
// 2. Loop through each field. This must be done at compile
// time.
//
// Hint: remember 'inline' loops?
//
for (fields) |field| {
for (???, ???) |???, ???| {
// 3. Print the field's name, type, and value.
//
// Each 'field' in this loop is one of these:
//
// pub const StructField = struct {
// name: [:0]const u8,
// type: type,
// default_value_ptr: ?*const anyopaque,
// is_comptime: bool,
// alignment: comptime_int,
// };
//
// Note we will learn about 'anyopaque' type later
//
// You'll need this builtin:
//
// @field(lhs: anytype, comptime field_name: []const u8)
@@ -123,8 +114,8 @@ fn printTuple(tuple: anytype) void {
// for declarations. If it's a value, it looks for data.
//
print("\"{s}\"({any}):{any} ", .{
field.???,
field.???,
field_name,
field_type,
???,
});
}

View File

@@ -1,5 +1,5 @@
--- exercises/065_builtins2.zig 2026-02-27 13:10:36
+++ answers/065_builtins2.zig 2026-02-27 13:10:52
--- exercises/065_builtins2.zig 2026-06-01 15:33:16.617432671 +0200
+++ answers/065_builtins2.zig 2026-06-01 15:33:31.104018108 +0200
@@ -58,7 +58,7 @@
// Oops! We cannot leave the 'me' and 'myself' fields
// undefined. Please set them here:
@@ -18,22 +18,26 @@
// Now we print a pithy statement about Narcissus.
print("A {s} loves all {s}es. ", .{
@@ -113,15 +113,15 @@
@@ -102,16 +102,16 @@
// 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}", .{fields[0].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[0] != void) {
+ print(" {s}", .{field_names[0]});
}
- if (fields[1].??? != void) {
+ if (fields[1].type != void) {
print(" {s}", .{fields[1].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[1] != void) {
+ print(" {s}", .{field_names[1]});
}
- if (fields[2].??? != void) {
+ if (fields[2].type != void) {
print(" {s}", .{fields[2].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[2] != void) {
+ print(" {s}", .{field_names[2]});
}
// Yuck, look at all that repeated code above! I don't know

View File

@@ -1,11 +1,11 @@
--- exercises/071_comptime6.zig 2024-09-02 19:21:50.250454978 +0200
+++ answers/071_comptime6.zig 2024-09-02 19:21:23.553250563 +0200
@@ -40,7 +40,7 @@
const fields = @typeInfo(Narcissus).@"struct".fields;
--- exercises/071_comptime6.zig 2026-06-01 15:35:27.223400223 +0200
+++ answers/071_comptime6.zig 2026-06-01 15:36:35.349728561 +0200
@@ -41,7 +41,7 @@
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
- ??? {
+ inline for (fields) |field| {
if (field.type != void) {
print(" {s}", .{field.name});
+ inline for (field_names, field_types) |field_name, field_type| {
if (field_type != void) {
print(" {s}", .{field_name});
}

View File

@@ -1,32 +1,32 @@
--- exercises/082_anonymous_structs3.zig 2026-02-27 13:05:46
+++ answers/082_anonymous_structs3.zig 2026-02-27 13:07:22
@@ -82,14 +82,14 @@
// @typeInfo(Circle).@"struct".fields
--- exercises/082_anonymous_structs3.zig 2026-06-01 15:59:11.872467805 +0200
+++ answers/082_anonymous_structs3.zig 2026-06-01 15:58:38.004730144 +0200
@@ -82,17 +82,17 @@
// @typeInfo(Circle).@"struct".field_types
//
// This will be an array of StructFields.
- const fields = ???;
+ const fields = @typeInfo(@TypeOf(tuple)).@"struct".fields;
// This will be an array of field types.
- const field_types = ???;
+ const field_types = @typeInfo(@TypeOf(tuple)).@"struct".field_types;
// This will be an array of field names.
- const field_names = ???;
+ const field_names = @typeInfo(@TypeOf(tuple)).@"struct".field_names;
// 2. Loop through each field. This must be done at compile
// time.
//
// Hint: remember 'inline' loops?
//
- for (fields) |field| {
+ inline for (fields) |field| {
- for (???, ???) |???, ???| {
+ inline for (field_types, field_names) |field_type, field_name| {
// 3. Print the field's name, type, and value.
//
// Each 'field' in this loop is one of these:
@@ -123,9 +123,9 @@
// for declarations. If it's a value, it looks for data.
//
// You'll need this builtin:
@@ -116,7 +116,7 @@
print("\"{s}\"({any}):{any} ", .{
- field.???,
- field.???,
field_name,
field_type,
- ???,
+ field.name,
+ field.type,
+ @field(tuple, field.name),
+ @field(tuple, field_name),
});
}
}

View File

@@ -21,6 +21,7 @@ const builtin = @import("builtin");
const Process = std.process;
const print = std.debug.print;
const cutPrefix = std.mem.cutPrefix;
const progress_filename = ".progress.txt";
@@ -102,6 +103,16 @@ pub const Exercise = struct {
}
};
// Shared, read-only run context threaded through the helpers.
const Context = struct {
io: std.Io,
arena: std.mem.Allocator,
zig_exe: []const u8,
work_path: []const u8,
};
const Error = error{Failed};
// Ansi colors.
var use_color_escapes = false;
var red_text: []const u8 = "";
@@ -138,7 +149,8 @@ pub fn main(init: std.process.Init) !void {
const io = init.io;
const arena = init.arena.allocator();
const args = try init.minimal.args.toSlice(arena);
var args_it = try init.minimal.args.iterateAllocator(arena);
if (!args_it.skip()) @panic("expected self arg");
setupColors(io);
@@ -150,22 +162,21 @@ pub fn main(init: std.process.Init) !void {
var only_n: ?usize = null;
var start_n: ?usize = null;
for (1..args.len) |n| {
const arg = args[n];
while (args_it.next()) |arg| {
if (std.mem.eql(u8, arg, "--logo")) {
print("{s}{s}{s}", .{ yellow_text, logo, reset_text });
return;
} else if (prefix(arg, "--zig=")) |v| {
} else if (cutPrefix(u8, arg, "--zig=")) |v| {
zig_exe = v;
} else if (prefix(arg, "--work-path=")) |v| {
} else if (cutPrefix(u8, arg, "--work-path=")) |v| {
work_path = v;
} else if (prefix(arg, "--only=")) |v| {
} else if (cutPrefix(u8, arg, "--only=")) |v| {
only_n = std.fmt.parseInt(usize, v, 10) catch {
print("invalid --only value: {s}\n", .{v});
std.process.exit(1);
};
mode = .named;
} else if (prefix(arg, "--start=")) |v| {
} else if (cutPrefix(u8, arg, "--start=")) |v| {
start_n = std.fmt.parseInt(usize, v, 10) catch {
print("invalid --start value: {s}\n", .{v});
std.process.exit(1);
@@ -181,7 +192,12 @@ pub fn main(init: std.process.Init) !void {
print("{s}", .{logo});
const ctx: Context = .{ .io = io, .arena = arena, .zig_exe = zig_exe, .work_path = work_path };
const ctx: Context = .{
.io = io,
.arena = arena,
.zig_exe = zig_exe,
.work_path = work_path,
};
switch (mode) {
.named => {
@@ -230,21 +246,6 @@ pub fn main(init: std.process.Init) !void {
}
}
fn prefix(arg: []const u8, pre: []const u8) ?[]const u8 {
if (std.mem.startsWith(u8, arg, pre)) return arg[pre.len..];
return null;
}
// Shared, read-only run context threaded through the helpers.
const Context = struct {
io: std.Io,
arena: std.mem.Allocator,
zig_exe: []const u8,
work_path: []const u8,
};
const Error = error{Failed};
// Iterates exercises from `start_index` to the end, stopping at the first failure.
// Progress is written after each passed exercise.
fn iterateFrom(ctx: Context, start_index: usize) Error!void {