Просмотр исходного кода

Merge pull request 'Add a new exercise for a labeled switch' (#161) from nm-remarkable/exercises:main into main

Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/161
Chris Boesch 11 месяцев назад
Родитель
Сommit
94b5b4bf4b
4 измененных файлов с 105 добавлено и 3 удалено
  1. 3 2
      README.md
  2. 7 1
      build.zig
  3. 77 0
      exercises/108_labeled_switch.zig
  4. 18 0
      patches/patches/108_labeled_switch.patch

+ 3 - 2
README.md

@@ -88,7 +88,8 @@ that if you update one, you may need to also update the other.
 
 ### Version Changes
 
-Version-0.14.0-dev.1224
+Version-0.14.0-dev.1573
+* *2024-09-16* zig 0.14.0-dev.1573 - introduction of labeled switch, see [#21257](https://github.com/ziglang/zig/pull/21257)
 * *2024-09-02* zig 0.14.0-dev.1409 - several changes in std.builtin, see [#21225](https://github.com/ziglang/zig/pull/21225)
 * *2024-08-04* zig 0.14.0-dev.1224 - several changes in build system, see [#21115](https://github.com/ziglang/zig/pull/21115)
 * *2024-08-04* zig 0.14.0-dev.839 - several changes in build system, see [#20580](https://github.com/ziglang/zig/pull/20580), [#20600](https://github.com/ziglang/zig/issues/20600)
@@ -229,7 +230,7 @@ Zig Core Language
 * [X] Bit manipulation
 * [X] Working with C
 * [X] Threading
-* [ ] Labeled switch (#21257)
+* [x] Labeled switch
 
 Zig Standard Library
 

+ 7 - 1
build.zig

@@ -15,7 +15,7 @@ const print = std.debug.print;
 //     1) Getting Started
 //     2) Version Changes
 comptime {
-    const required_zig = "0.14.0-dev.1409";
+    const required_zig = "0.14.0-dev.1573";
     const current_zig = builtin.zig_version;
     const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable;
     if (current_zig.order(min_zig) == .lt) {
@@ -1198,6 +1198,12 @@ const exercises = [_]Exercise{
         ,
     },
     .{
+        .main_file = "108_labeled_switch.zig",
+        .output =
+        \\The pull request has been merged
+        ,
+    },
+    .{
         .main_file = "999_the_end.zig",
         .output =
         \\

+ 77 - 0
exercises/108_labeled_switch.zig

@@ -0,0 +1,77 @@
+//
+// You've heard of while loops in exercises 011,012,013 and 014
+// You've also heard of switch expressions in exercises 030 and 31.
+// You've also seen how labels can be used in exercise 063.
+//
+// By combining while loops and switch statements with continue and break statements
+// one can create very concise State Machines.
+//
+// One such example would be:
+//
+//      pub fn main() void {
+//          var op: u8 = 1;
+//          while (true) {
+//              switch (op) {
+//                  1 => { op = 2; continue; },
+//                  2 => { op = 3; continue; },
+//                  3 => return,
+//                  4 => {},
+//              }
+//              break;
+//          }
+//      std.debug.print("This statement cannot be reached");
+//      }
+//
+// By combining all we've learned so far, we can now proceed with a labeled switch
+//
+// A labeled switch is some extra syntatic sugar, which comes with all sorts of
+// candy (performance benefits). Don't believe me? Directly to source https://github.com/ziglang/zig/pull/21367
+//
+// Here is the previous excerpt implemented as a labeled switch instead:
+//
+//      pub fn main() void {
+//          foo: switch (@as(u8, 1)) {
+//              1 => continue :foo 2,
+//              2 => continue :foo 3,
+//              3 => return,
+//              4 => {},
+//          }
+//          std.debug.print("This statement cannot be reached");
+//      }
+//
+// The flow of execution on this second case is:
+//  1. The switch starts with value '1';
+//  2. The switch evaluates to case '1' which in turn uses the continue statement
+//        to re-evaluate the labeled switch again, now providing the value '2';
+//  3. In the case '2' we repeat the same pattern as case '1'
+//        but instead the value to be evaluated is now '3';
+//  4. Finally we get to case '3', where we return from the function as a whole.
+//
+// Since step 4 or a break stament do not exist in this switch, the debug statement is
+// never executed
+//
+const std = @import("std");
+
+const PullRequestState = enum(u8) {
+    Draft,
+    InReview,
+    Approved,
+    Rejected,
+    Merged,
+};
+
+pub fn main() void {
+    // Oh no, your pull request keeps being rejected,
+    // how would you fix it?
+    pr: switch (@as(PullRequestState, PullRequestState.Draft)) {
+        PullRequestState.Draft => continue :pr PullRequestState.InReview,
+        PullRequestState.InReview => continue :pr PullRequestState.Rejected,
+        PullRequestState.Approved => continue :pr PullRequestState.Merged,
+        PullRequestState.Rejected => {
+            std.debug.print("The pull request has been rejected", .{});
+            return;
+        },
+        PullRequestState.Merged => break, // Would you know where to break to?
+    }
+    std.debug.print("The pull request has been merged", .{});
+}

+ 18 - 0
patches/patches/108_labeled_switch.patch

@@ -0,0 +1,18 @@
+--- a/exercises/108_labeled_switch.zig
++++ b/exercises/108_labeled_switch.zig
+@@ -65,13 +65,13 @@ pub fn main() void {
+     // how would you fix it?
+     pr: switch (@as(PullRequestState, PullRequestState.Draft)) {
+         PullRequestState.Draft => continue :pr PullRequestState.InReview,
+-        PullRequestState.InReview => continue :pr PullRequestState.Rejected,
++        PullRequestState.InReview => continue :pr PullRequestState.Approved,
+         PullRequestState.Approved => continue :pr PullRequestState.Merged,
+         PullRequestState.Rejected => {
+             std.debug.print("The pull request has been rejected", .{});
+             return;
+         },
+-        PullRequestState.Merged => break, // Would you know where to break to?
++        PullRequestState.Merged => break :pr, // Would you know where to break to?
+     }
+     std.debug.print("The pull request has been merged", .{});
+ }