#Inconsistent switch and while behavior

1 messages · Page 1 of 1 (latest)

verbal granite
#

Hi! I am trying to follow Robert Nystrom's book Crafting Interpreters book in zig, and I am in the first section, writing a lexer. The core of the lexer is the scanToken function and it includes a large switch statement. The issue is that the switch expression should return a Token or an error, which is caught, but the compiler thinks a certain switch case returns void instead.

const tok: Token = switch(c) {
    ...
    '"' => blk: {
        const string_start = self.idx_current;
        while (self.bytesLeft() > 0) {
            self.idx_current += 1;
            if (self.match('\n', 0)) {
                self.idx_line += 1;
            }
            if (self.match('"', 0)) {
                break :blk Token{ .token_type = .STRING, .literal = Literal{ .string = self.source[string_start + 1 .. self.idx_current] } };
            }
            }
        else {
            break :blk LexError.UnterminatedString;
        }
    },
    ...
    'A' => blk: {
        while (self.bytesLeft() > 0) {
            break :blk LexError.Impossible;
        }
    },
} catch |err| switch (err) {
    ...
}

Here the first switch statement that matches a string literal compiles and works perfectly fine, it also includes while and break statements. However, the compiler thinks the second case returns a void somehow.

src/tokenizer.zig:173:28: error: incompatible types: 'tokenizer.Token' and 'error{UnknownCharacter,UnexpectedCharacter,NoToken,UnterminatedString,Impossible}!void'
        const tok: Token = switch (c) {
                           ^~~~~~
src/tokenizer.zig:174:25: note: type 'tokenizer.Token' here
            '(' => Token{ .token_type = .LEFT_PAREN },
                   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/tokenizer.zig:264:25: note: type 'error{UnknownCharacter,UnexpectedCharacter,NoToken,UnterminatedString,Impossible}!void' here
            'A' => blk: {
                   ~~~~~^
undone lava
#

if self.bytesLeft() > 0 is never true then you never break from the block with a value

verbal granite
#

yeah, thats it. I forgot to return a default value, because bytesleft is always true at least once but the compiler doesn't know of course.