mirror of
https://codeberg.org/ziglings/exercises.git
synced 2026-07-28 18:25:16 +00:00
Merge branch 'main' into make-threading-mathier
This commit is contained in:
+3
-3
@@ -8,11 +8,11 @@ of Ziglings Maintenance!
|
||||
|
||||
Ziglings is intended for programmers of all experience levels. No
|
||||
specific language knowledge is expected. Anyone who can install
|
||||
the current Zig snapshot, setup a copy of Ziglings, and knows
|
||||
the current Zig snapshot, set up a copy of Ziglings, and knows
|
||||
common language building blocks (if/then/else, loops, and
|
||||
functions) is ready for Ziglings.
|
||||
|
||||
Zigling's excercises are self-contained. If you can't solve
|
||||
Zigling's exercises are self-contained. If you can't solve
|
||||
an exercise from the information you've gleaned so far from
|
||||
Ziglings, then the exercise probably needs some additional work.
|
||||
Please file an issue!
|
||||
@@ -95,7 +95,7 @@ interface. Specifically:
|
||||
eternal Ziglings contributor glory is yours!
|
||||
|
||||
|
||||
## Licence
|
||||
## License
|
||||
|
||||
If you submit your contribution to the repository/project,
|
||||
you agree that your contribution will be licensed under
|
||||
|
||||
@@ -81,6 +81,7 @@ pub fn build(b: *Build) !void {
|
||||
const run = b.addRunArtifact(elrond);
|
||||
run.addArg(b.fmt("--zig={s}", .{b.graph.zig_exe}));
|
||||
run.addArg(b.fmt("--work-path={s}", .{work_path}));
|
||||
run.addArg(b.fmt("--root-path={s}", .{b.root.root_dir.path.?}));
|
||||
|
||||
if (exno) |n| {
|
||||
run.addArg(b.fmt("--only={d}", .{n}));
|
||||
|
||||
@@ -26,8 +26,13 @@ pub fn main() void {
|
||||
// (Problem 2)
|
||||
// Please set this array using repetition.
|
||||
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
||||
const bit_pattern_unit = [_]u8{ ??? };
|
||||
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
|
||||
const bit_pattern_unit = ???;
|
||||
|
||||
// How long should the bit pattern be?
|
||||
const len = ???;
|
||||
|
||||
// For now, don't worry about the use of SIMD.
|
||||
const bit_pattern: [len]u8 = std.simd.repeat(len, bit_pattern_unit);
|
||||
|
||||
// Okay, that's all of the problems. Let's see the results.
|
||||
//
|
||||
@@ -53,3 +58,12 @@ pub fn main() void {
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
// For the curious:
|
||||
//
|
||||
// The `std.simd.repeat` function takes a target length and a pattern,
|
||||
// and returns a vector filled with that pattern repeated to the
|
||||
// desired length.
|
||||
//
|
||||
// For example, `repeat(5, [_]u8{1, 2})` will return a vector
|
||||
// equivalent to `.{1, 2, 1, 2, 1}`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// As with integers, you can pass a pointer to a struct when you
|
||||
// will wish to modify that struct. Pointers are also useful when
|
||||
// wish to modify that struct. Pointers are also useful when
|
||||
// you need to store a reference to a struct (a "link" to it).
|
||||
//
|
||||
// const Vertex = struct{ x: u32, y: u32, z: u32 };
|
||||
|
||||
@@ -37,6 +37,24 @@
|
||||
// self, others use a lowercase version of the type name, but feel
|
||||
// free to use whatever is most appropriate.
|
||||
//
|
||||
// "But hold on," you say, eyeing a() and b() suspiciously, "why
|
||||
// does one take 'self' and another take '*self'?" Sharp eye!
|
||||
//
|
||||
// It all comes down to a single question: does the function need
|
||||
// to CHANGE the struct?
|
||||
//
|
||||
// * Needs to change it? Take a pointer (*Bar). Without it you'd
|
||||
// be scribbling on a COPY, and your changes would evaporate the
|
||||
// instant the function returns. Poof.
|
||||
// * Only reads it? Plain Bar is just fine.
|
||||
// (For a big, bulky struct you might still write *const Bar to
|
||||
// avoid copying it around, but for small ones a copy is cheap.)
|
||||
//
|
||||
// You'll see this below: zap() takes 'self: HeatRay' by value
|
||||
// because it only reads the ray's damage, but it takes the alien
|
||||
// as '*Alien' because zapping is supposed to HURT - and that means
|
||||
// changing the alien's health for real, not on a throwaway copy.
|
||||
//
|
||||
// Okay, you're armed.
|
||||
//
|
||||
// Now, please zap the alien structs until they're all gone or
|
||||
|
||||
@@ -47,7 +47,7 @@ const Narcissus = struct {
|
||||
myself: *Narcissus = undefined,
|
||||
echo: void = undefined, // Alas, poor Echo!
|
||||
|
||||
fn fetchTheMostBeautifulType() type {
|
||||
fn FetchTheMostBeautifulType() type {
|
||||
return @This();
|
||||
}
|
||||
};
|
||||
@@ -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. ", .{
|
||||
@@ -94,7 +94,7 @@ pub fn main() void {
|
||||
print("He has room in his heart for:", .{});
|
||||
|
||||
// `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,
|
||||
// `field_types` is a slice of types 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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// In Exercises 84-91, we learned about Zig's Io interface for
|
||||
// In Exercises 85-94 and quiz 95, we learned about Zig's Io interface for
|
||||
// concurrent execution: io.async(), Group, Select, and Futures.
|
||||
// Under the hood, the Threaded backend manages a pool of real
|
||||
// OS threads for you - including scheduling, cancellation, and
|
||||
@@ -74,11 +74,11 @@ pub fn main() !void {
|
||||
// before the parallel processing begins.
|
||||
std.debug.print("Starting work...\n", .{});
|
||||
|
||||
// These curly brackets are very important, they are necessary
|
||||
// to enclose the area where the threads are called.
|
||||
// Without these brackets, the program would not wait for the
|
||||
// end of the threads and they would continue to run beyond the
|
||||
// end of the program.
|
||||
// These curly braces are very important, they are necessary
|
||||
// to enclose the area where the threads are called and joined.
|
||||
// With these braces, the program will block and wait for all threads
|
||||
// to finish right at the closing brace of this block, ensuring
|
||||
// "Zig is cool!" is always printed last.
|
||||
{
|
||||
// Now we start the first thread, with the number as parameter
|
||||
const handle = try std.Thread.spawn(.{}, thread_function, .{1});
|
||||
@@ -102,8 +102,7 @@ pub fn main() !void {
|
||||
try io.sleep(std.Io.Duration.fromMilliseconds(400), .awake);
|
||||
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
|
||||
}
|
||||
// After we have left the closed area, we wait until
|
||||
// the threads have run through, if this has not yet been the case.
|
||||
// The threads are guaranteed to be finished by the time we reach here.
|
||||
std.debug.print("Zig is cool!\n", .{});
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
// 1,000,000,000 partial values. And for each additional digit we have to
|
||||
// add a zero.
|
||||
// Even fast computers - and I mean really fast computers - get a bit warmer
|
||||
// on the CPU when it comes to really many digits. But the 8 digits are
|
||||
// on the CPU when it comes to a large number of digits. But 8 digits are
|
||||
// enough for us for now, because we want to understand the principle and
|
||||
// nothing more, right?
|
||||
//
|
||||
|
||||
@@ -50,7 +50,7 @@ pub fn main(init: std.process.Init) !void {
|
||||
// wait a minute...
|
||||
// opening a directory might fail!
|
||||
// what should we do here?
|
||||
var output_dir: std.Io.Dir = try cwd.openDir(io, "output", .{});
|
||||
var output_dir: std.Io.Dir = cwd.openDir(io, "output", .{});
|
||||
defer output_dir.close(io);
|
||||
|
||||
// we try to open the file `zigling.txt`,
|
||||
|
||||
@@ -145,3 +145,7 @@ pub fn main() void {
|
||||
print("Max difference (old fn): {d: >5.3}\n", .{mpd_old});
|
||||
print("Max difference (new fn): {d: >5.3}\n", .{mpd_new});
|
||||
}
|
||||
|
||||
// Another cool feature of Vectors is repeating patterns.
|
||||
// Remember the arrays exercise from earlier where we created an array
|
||||
// by repeating a pattern? See `005_arrays2.zig`.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
// A common activity in microcontroller programming is setting and clearing
|
||||
// bits on input and output pins. This lets you control LEDs, sensors, motors
|
||||
// and more! In a previous exercise (097_bit_manipulation.zig) you learned how
|
||||
// and more! In a previous exercise (100_bit_manipulation.zig) you learned how
|
||||
// to swap two bytes using the ^ (XOR - exclusive or) operator. This quiz will
|
||||
// test your knowledge of bit manipulation in Zig while giving you a taste of
|
||||
// what it's like to control registers in a real microcontroller. Included at
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// We've already learned plenty about bit manipulation using bitwise operations
|
||||
// in exercises 097 and 098 and in quiz 110. The techniques we already know work
|
||||
// in exercises 100 and 101 and in quiz 113. The techniques we already know work
|
||||
// just fine, but creating masks and shifting individual bits around can become
|
||||
// quite tedious and unwieldy pretty quickly.
|
||||
// What if there was a better, a more convenient way to control individual bits?
|
||||
@@ -78,7 +78,7 @@ const FLG = packed struct(u8) {
|
||||
content_checksum: bool,
|
||||
content_size: bool,
|
||||
block_checksum: bool,
|
||||
block_indepencence: bool,
|
||||
block_independence: bool,
|
||||
version: u2,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// We've already learned about switch statements in exercises 030, 031 and 108.
|
||||
// We've already learned about switch statements in exercises 030, 031 and 111.
|
||||
// They also work with packed containers:
|
||||
|
||||
const S = packed struct(u2) {
|
||||
@@ -51,11 +51,11 @@ comptime {
|
||||
//
|
||||
// Try to make the float below negative:
|
||||
|
||||
/// IEEE 754 half precision float
|
||||
// IEEE 754 binary16 floating-point format
|
||||
const Float = packed union(u16) {
|
||||
value: f16,
|
||||
bits: packed struct(u16) {
|
||||
mantissa: u10,
|
||||
significand: u10,
|
||||
exponent: u5,
|
||||
sign: u1,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- exercises/005_arrays2.zig 2026-05-04 16:26:32.778330847 +0200
|
||||
+++ answers/005_arrays2.zig 2026-05-04 16:26:13.082917974 +0200
|
||||
@@ -21,12 +21,12 @@
|
||||
--- exercises/005_arrays2.zig 2026-06-27 09:03:29.918124920 +0000
|
||||
+++ answers/005_arrays2.zig 2026-06-27 09:01:13.162138431 +0000
|
||||
@@ -21,15 +21,15 @@
|
||||
// (Problem 1)
|
||||
// Please set this array concatenating the two arrays above.
|
||||
// It should result in: 1 3 3 7
|
||||
@@ -10,8 +10,12 @@
|
||||
// (Problem 2)
|
||||
// Please set this array using repetition.
|
||||
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
||||
- const bit_pattern_unit = [_]u8{ ??? };
|
||||
- const bit_pattern_unit = ???;
|
||||
+ const bit_pattern_unit = [_]u8{ 1, 0, 0, 1 };
|
||||
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
|
||||
|
||||
// Okay, that's all of the problems. Let's see the results.
|
||||
// How long should the bit pattern be?
|
||||
- const len = ???;
|
||||
+ const len = 3 * bit_pattern_unit.len;
|
||||
|
||||
// For now, don't worry about the use of SIMD.
|
||||
const bit_pattern: [len]u8 = std.simd.repeat(len, bit_pattern_unit);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- exercises/047_methods.zig 2023-10-03 22:15:22.122241138 +0200
|
||||
+++ answers/047_methods.zig 2023-10-05 20:04:07.056100214 +0200
|
||||
@@ -88,7 +88,7 @@
|
||||
--- exercises/047_methods.zig 2026-06-21 16:11:59.110876971 +0200
|
||||
+++ answers/047_methods.zig 2026-06-21 16:13:07.066363558 +0200
|
||||
@@ -106,7 +106,7 @@
|
||||
for (&aliens) |*alien| {
|
||||
|
||||
// *** Zap the alien with the heat ray here! ***
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
//
|
||||
// The fix for this is very subtle, but it makes a big
|
||||
// difference!
|
||||
- const Type2 = narcissus.fetchTheMostBeautifulType();
|
||||
+ const Type2 = Narcissus.fetchTheMostBeautifulType();
|
||||
- const Type2 = narcissus.FetchTheMostBeautifulType();
|
||||
+ const Type2 = Narcissus.FetchTheMostBeautifulType();
|
||||
|
||||
// Now we print a pithy statement about Narcissus.
|
||||
print("A {s} loves all {s}es. ", .{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
--- exercises/109_files.zig 2026-03-20 19:23:48.874150121 +0100
|
||||
+++ answers/109_files.zig 2026-04-02 10:51:15.813831695 +0200
|
||||
--- exercises/109_files.zig 2026-06-29 17:08:04.124224900 +0000
|
||||
+++ answers/109_files.zig 2026-06-29 17:13:20.696220533 +0000
|
||||
@@ -41,7 +41,7 @@
|
||||
// by doing nothing
|
||||
//
|
||||
@@ -9,6 +9,15 @@
|
||||
// if there's any other unexpected error we just propagate it through
|
||||
else => return e,
|
||||
};
|
||||
@@ -50,7 +50,7 @@
|
||||
// wait a minute...
|
||||
// opening a directory might fail!
|
||||
// what should we do here?
|
||||
- var output_dir: std.Io.Dir = cwd.openDir(io, "output", .{});
|
||||
+ var output_dir: std.Io.Dir = try cwd.openDir(io, "output", .{});
|
||||
defer output_dir.close(io);
|
||||
|
||||
// we try to open the file `zigling.txt`,
|
||||
@@ -61,7 +61,7 @@
|
||||
// but here we are not yet done writing to the file
|
||||
// if only there were a keyword in Zig that
|
||||
|
||||
+72
-49
@@ -19,12 +19,28 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Io = std.Io;
|
||||
const File = Io.File;
|
||||
const Process = std.process;
|
||||
const Terminal = std.Io.Terminal;
|
||||
const print = std.debug.print;
|
||||
const cutPrefix = std.mem.cutPrefix;
|
||||
|
||||
const progress_filename = ".progress.txt";
|
||||
|
||||
const no_colors_help =
|
||||
\\Colors are not available. Check the NO_COLOR environ variable.
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
const windows_colors_help =
|
||||
\\Windows colors are not supported.
|
||||
\\Install Windows Terminal or update to a more recent Windows version.
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
pub const logo =
|
||||
\\ _ _ _
|
||||
\\ ___(_) __ _| (_)_ __ __ _ ___
|
||||
@@ -109,41 +125,23 @@ const Context = struct {
|
||||
arena: std.mem.Allocator,
|
||||
zig_exe: []const u8,
|
||||
work_path: []const u8,
|
||||
root_path: []const u8,
|
||||
};
|
||||
|
||||
const Error = error{Failed};
|
||||
|
||||
// Ansi colors.
|
||||
var use_color_escapes = false;
|
||||
var red_text: []const u8 = "";
|
||||
var red_bold_text: []const u8 = "";
|
||||
var red_dim_text: []const u8 = "";
|
||||
var green_text: []const u8 = "";
|
||||
var yellow_text: []const u8 = "";
|
||||
var bold_text: []const u8 = "";
|
||||
var reset_text: []const u8 = "";
|
||||
var stderr_term_mode: Terminal.Mode = .no_color;
|
||||
|
||||
fn setupColors(io: std.Io) void {
|
||||
use_color_escapes = false;
|
||||
const stderr = std.Io.File.stderr();
|
||||
if (stderr.supportsAnsiEscapeCodes(io)) |ok| {
|
||||
if (ok) use_color_escapes = true;
|
||||
} else |_| {}
|
||||
if (!use_color_escapes and builtin.os.tag == .windows) {
|
||||
if (stderr.enableAnsiEscapeCodes(io)) {
|
||||
use_color_escapes = true;
|
||||
} else |_| {}
|
||||
}
|
||||
if (use_color_escapes) {
|
||||
red_text = "\x1b[31m";
|
||||
red_bold_text = "\x1b[31;1m";
|
||||
red_dim_text = "\x1b[31;2m";
|
||||
green_text = "\x1b[32m";
|
||||
yellow_text = "\x1b[33m";
|
||||
bold_text = "\x1b[1m";
|
||||
reset_text = "\x1b[0m";
|
||||
}
|
||||
}
|
||||
// Ansi colors.
|
||||
const C = struct {
|
||||
var red: []const u8 = "\x1b[31m";
|
||||
var red_bold: []const u8 = "\x1b[31;1m";
|
||||
var red_dim: []const u8 = "\x1b[31;2m";
|
||||
var green: []const u8 = "\x1b[32m";
|
||||
var yellow: []const u8 = "\x1b[33m";
|
||||
var bold: []const u8 = "\x1b[1m";
|
||||
var reset: []const u8 = "\x1b[0m";
|
||||
};
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const io = init.io;
|
||||
@@ -152,24 +150,51 @@ pub fn main(init: std.process.Init) !void {
|
||||
var args_it = try init.minimal.args.iterateAllocator(arena);
|
||||
if (!args_it.skip()) @panic("expected self arg");
|
||||
|
||||
setupColors(io);
|
||||
const stderr = File.stderr();
|
||||
|
||||
// Setup colors.
|
||||
const NO_COLOR = try init.minimal.environ.containsUnempty(arena, "NO_COLOR");
|
||||
const CLICOLOR_FORCE = try init.minimal.environ.containsUnempty(arena, "CLICOLOR_FORCE");
|
||||
|
||||
const term_mode = try Terminal.Mode.detect(io, stderr, NO_COLOR, CLICOLOR_FORCE);
|
||||
stderr_term_mode = term_mode;
|
||||
|
||||
// Show help in case colors are not available or not supported.
|
||||
switch (term_mode) {
|
||||
.no_color => print(no_colors_help, .{}),
|
||||
.escape_codes => {},
|
||||
.windows_api => print(windows_colors_help, .{}),
|
||||
}
|
||||
|
||||
if (term_mode == .no_color) {
|
||||
C.red = "";
|
||||
C.red_bold = "";
|
||||
C.red_dim = "";
|
||||
C.green = "";
|
||||
C.yellow = "";
|
||||
C.bold = "";
|
||||
C.reset = "";
|
||||
}
|
||||
|
||||
if (!validateExercises()) std.process.exit(1);
|
||||
|
||||
var zig_exe: []const u8 = "zig";
|
||||
var work_path: []const u8 = "exercises";
|
||||
var root_path: []const u8 = "";
|
||||
var mode: Mode = .normal;
|
||||
var only_n: ?usize = null;
|
||||
var start_n: ?usize = null;
|
||||
|
||||
while (args_it.next()) |arg| {
|
||||
if (std.mem.eql(u8, arg, "--logo")) {
|
||||
print("{s}{s}{s}", .{ yellow_text, logo, reset_text });
|
||||
print("{s}{s}{s}", .{ C.yellow, logo, C.reset });
|
||||
return;
|
||||
} else if (cutPrefix(u8, arg, "--zig=")) |v| {
|
||||
zig_exe = v;
|
||||
} else if (cutPrefix(u8, arg, "--work-path=")) |v| {
|
||||
work_path = v;
|
||||
} else if (cutPrefix(u8, arg, "--root-path=")) |v| {
|
||||
root_path = v;
|
||||
} else if (cutPrefix(u8, arg, "--only=")) |v| {
|
||||
only_n = std.fmt.parseInt(usize, v, 10) catch {
|
||||
print("invalid --only value: {s}\n", .{v});
|
||||
@@ -197,6 +222,7 @@ pub fn main(init: std.process.Init) !void {
|
||||
.arena = arena,
|
||||
.zig_exe = zig_exe,
|
||||
.work_path = work_path,
|
||||
.root_path = root_path,
|
||||
};
|
||||
|
||||
switch (mode) {
|
||||
@@ -238,7 +264,7 @@ pub fn main(init: std.process.Init) !void {
|
||||
}
|
||||
} else {
|
||||
// All solved.
|
||||
print("{s}All exercises completed!{s}\n", .{ green_text, reset_text });
|
||||
print("{s}All exercises completed!{s}\n", .{ C.green, C.reset });
|
||||
return;
|
||||
}
|
||||
iterateFrom(ctx, start_index) catch std.process.exit(1);
|
||||
@@ -260,7 +286,7 @@ fn runOne(ctx: Context, ex: Exercise, mode: Mode) Error!void {
|
||||
if (ex.skip) {
|
||||
print("Skipping {s}", .{ex.main_file});
|
||||
if (ex.skip_hint) |hint|
|
||||
print("\n{s}Reason: {s}{s}\n", .{ bold_text, hint, reset_text });
|
||||
print("\n{s}Reason: {s}{s}\n", .{ C.bold, hint, C.reset });
|
||||
print("\n\n", .{});
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +309,7 @@ fn runOne(ctx: Context, ex: Exercise, mode: Mode) Error!void {
|
||||
|
||||
fn hintAndHelp(ex: Exercise, mode: Mode) void {
|
||||
if (ex.hint) |hint|
|
||||
print("\n{s}{s}Ziglings hint: {s}{s}", .{ bold_text, green_text, hint, reset_text });
|
||||
print("\n{s}{s}Ziglings hint: {s}{s}", .{ C.bold, C.green, hint, C.reset });
|
||||
help(ex, mode);
|
||||
}
|
||||
|
||||
@@ -310,7 +336,7 @@ fn runExe(ctx: Context, ex: Exercise) !void {
|
||||
const arena = ctx.arena;
|
||||
print("Compiling {s}...\n", .{ex.main_file});
|
||||
|
||||
const path = std.fs.path.join(arena, &.{ ctx.work_path, ex.main_file }) catch @panic("OOM");
|
||||
const path = std.fs.path.join(arena, &.{ ctx.root_path, ctx.work_path, ex.main_file }) catch @panic("OOM");
|
||||
|
||||
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
||||
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
||||
@@ -328,7 +354,7 @@ fn runExe(ctx: Context, ex: Exercise) !void {
|
||||
.stderr_limit = .limited(1024 * 1024),
|
||||
}) catch |err| {
|
||||
print("{s}error:{s} unable to run {s}: {s}\n", .{
|
||||
red_bold_text, reset_text, ex.main_file, @errorName(err),
|
||||
C.red_bold, C.reset, ex.main_file, @errorName(err),
|
||||
});
|
||||
return err;
|
||||
};
|
||||
@@ -344,8 +370,7 @@ fn runTest(ctx: Context, ex: Exercise) !void {
|
||||
const arena = ctx.arena;
|
||||
print("Compiling {s}...\n", .{ex.main_file});
|
||||
|
||||
const path = std.fs.path.join(arena, &.{ ctx.work_path, ex.main_file }) catch
|
||||
@panic("OOM");
|
||||
const path = std.fs.path.join(arena, &.{ ctx.root_path, ctx.work_path, ex.main_file }) catch @panic("OOM");
|
||||
|
||||
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
||||
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
||||
@@ -362,7 +387,7 @@ fn runTest(ctx: Context, ex: Exercise) !void {
|
||||
.stderr_limit = .limited(1024 * 1024),
|
||||
}) catch |err| {
|
||||
print("{s}error:{s} unable to run test {s}: {s}\n", .{
|
||||
red_bold_text, reset_text, ex.main_file, @errorName(err),
|
||||
C.red_bold, C.reset, ex.main_file, @errorName(err),
|
||||
});
|
||||
return err;
|
||||
};
|
||||
@@ -384,7 +409,7 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
||||
},
|
||||
else => {
|
||||
print("{s}{s} terminated unexpectedly{s}\n", .{
|
||||
red_bold_text, ex.main_file, reset_text,
|
||||
C.red_bold, ex.main_file, C.reset,
|
||||
});
|
||||
return Error.Failed;
|
||||
},
|
||||
@@ -419,8 +444,6 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
||||
}
|
||||
|
||||
if (!std.mem.eql(u8, output, exercise_output)) {
|
||||
const red = red_bold_text;
|
||||
const reset = reset_text;
|
||||
print(
|
||||
\\
|
||||
\\{s}========= expected this output: =========={s}
|
||||
@@ -428,11 +451,11 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
||||
\\{s}========= but found: ====================={s}
|
||||
\\{s}
|
||||
\\{s}=========================================={s}
|
||||
++ "\n", .{ red, reset, exercise_output, red, reset, output, red, reset });
|
||||
++ "\n", .{ C.red_bold, C.reset, exercise_output, C.red_bold, C.reset, output, C.red_bold, C.reset });
|
||||
return Error.Failed;
|
||||
}
|
||||
|
||||
print("{s}PASSED:\n{s}{s}\n\n", .{ green_text, output, reset_text });
|
||||
print("{s}PASSED:\n{s}{s}\n\n", .{ C.green, output, C.reset });
|
||||
}
|
||||
|
||||
fn checkTest(ex: Exercise, result: Process.RunResult) !void {
|
||||
@@ -444,12 +467,12 @@ fn checkTest(ex: Exercise, result: Process.RunResult) !void {
|
||||
},
|
||||
else => {
|
||||
print("{s}{s} terminated unexpectedly{s}\n", .{
|
||||
red_bold_text, ex.main_file, reset_text,
|
||||
C.red_bold, ex.main_file, C.reset,
|
||||
});
|
||||
return Error.Failed;
|
||||
},
|
||||
}
|
||||
print("{s}PASSED{s}\n\n", .{ green_text, reset_text });
|
||||
print("{s}PASSED{s}\n\n", .{ C.green, C.reset });
|
||||
}
|
||||
|
||||
fn help(ex: Exercise, mode: Mode) void {
|
||||
@@ -459,12 +482,12 @@ fn help(ex: Exercise, mode: Mode) void {
|
||||
.random => "zig build -Drandom",
|
||||
};
|
||||
print("\n{s}Edit exercises/{s} and run '{s}' again.{s}\n", .{
|
||||
red_bold_text, ex.main_file, cmd, reset_text,
|
||||
C.red_bold, ex.main_file, cmd, C.reset,
|
||||
});
|
||||
}
|
||||
|
||||
fn resetLine() void {
|
||||
if (use_color_escapes) print("{s}", .{"\x1b[2K\r"});
|
||||
if (stderr_term_mode == .escape_codes) print("{s}", .{"\x1b[2K\r"});
|
||||
}
|
||||
|
||||
// Removes trailing whitespace per line and any trailing LF at the end.
|
||||
|
||||
Reference in New Issue
Block a user