Search code examples
switch-statementzig

How do you return a value from a switch statement's matched case code block in zig?


Zig documentation says to leave the last line as an expression and that expression will be returned.

This documentation doesn't cover this case specifically but also didn't provide any clarity on the subject.

So this should work, as far as I can tell from the documentation.

const token = switch (c) {
        '.' => Token{ .type = .Dot, .value = null },
        '*' => Token{ .type = .Star, .value = null },
        '+' => Token{ .type = .Plus, .value = null },
        '?' => Token{ .type = .Question, .value = null },
        '|' => Token{ .type = .Or, .value = null },
        '(' => Token{ .type = .OpenParen, .value = null },
        ')' => Token{ .type = .CloseParen, .value = null },
        '[' => Token{ .type = .OpenBracket, .value = null },
        ']' => Token{ .type = .CloseBracket, .value = null },
        '^' => Token{ .type = .Caret, .value = null },
        '$' => Token{ .type = .Dollar, .value = null },
        '\\' => {
                if (i + 1 >= pattern.len) return RegexError.InvalidEscapeSequence;
                const next_character = pattern[i + 1];
                i += 1;

                switch (next_character) {
                        's' => Token{ .type = .Whitespace, .value = null },
                        'S' => Token{ .type = .NonWhitespace, .value = null },
                        'd' => Token{ .type = .Digit, .value = null },
                        'D' => Token{ .type = .NonDigit, .value = null },
                        'w' => Token{ .type = .Word, .value = null },
                        'W' => Token{ .type = .NonWord, .value = null },
                        else => Token{ .type = .EscapedCharacter, .value = next_character },
                }
        },
        else => Token{ .type = .Literal, .value = pattern[i] },
};

The nested switch statement should return whatever value it resolves to as the return value for the '\\' case. Except that if I attempt to compile this code I get this error.

src/utils/regex.zig:104:17: error: value of type 'utils.regex.Token' ignored
                switch (next_character) {
                ^~~~~~
src/utils/regex.zig:104:17: note: all non-void values must be used
src/utils/regex.zig:104:17: note: to discard the value, assign it to '_'

So it's not getting returned. Like the dumb javascript dev that I am I threw on a return statement thinking "ok, fuck it, no really return ya-silly-bitch".

        '$' => Token{ .type = .Dollar, .value = null },
        '\\' => {
                if (i + 1 >= pattern.len) return RegexError.InvalidEscapeSequence;
                const next_character = pattern[i + 1];
                i += 1;

                return switch (next_character) {
                        's' => Token{ .type = .Whitespace, .value = null },
                        'S' => Token{ .type = .NonWhitespace, .value = null },
                        'd' => Token{ .type = .Digit, .value = null },

Nope, that tries to return return from the whole function. So yeah, that doesn't work at all.

Since the documentation is inaccurate please someone who knows zig well inform me on how to return a value from a switch. Hahaha

Specs:

  • Mac M1
  • Zig version 0.13.0
  • Zig installed through homebrew

Solution

  • This is how I was able to get it to return a value.

    const token = switch (c) {
            '.' => Token{ .type = .Dot, .value = null },
            '*' => Token{ .type = .Star, .value = null },
            '+' => Token{ .type = .Plus, .value = null },
            '?' => Token{ .type = .Question, .value = null },
            '|' => Token{ .type = .Or, .value = null },
            '(' => Token{ .type = .OpenParen, .value = null },
            ')' => Token{ .type = .CloseParen, .value = null },
            '[' => Token{ .type = .OpenBracket, .value = null },
            ']' => Token{ .type = .CloseBracket, .value = null },
            '^' => Token{ .type = .Caret, .value = null },
            '$' => Token{ .type = .Dollar, .value = null },
            '\\' => |_| something: {
                    if (i + 1 >= pattern.len) return RegexError.InvalidEscapeSequence;
                    i += 1;
    
                    break :something switch (pattern[i]) {
                            's' => Token{ .type = .Whitespace, .value = null },
                            'S' => Token{ .type = .NonWhitespace, .value = null },
                            'd' => Token{ .type = .Digit, .value = null },
                            'D' => Token{ .type = .NonDigit, .value = null },
                            'w' => Token{ .type = .Word, .value = null },
                            'W' => Token{ .type = .NonWord, .value = null },
                            else => Token{ .type = .EscapedCharacter, .value = pattern[i] },
                    };
            },
            else => Token{ .type = .Literal, .value = pattern[i] },
    };