Hejsil / mecha

A parser combinator library for Zig
MIT License
473 stars 21 forks source link

asStr, oneOf and combine #70

Closed joelreymont closed 3 weeks ago

joelreymont commented 4 weeks ago

I was under the impression that I only needed 1 asStr at the end of my parser for all to be well.

Why does this

test "asStr1" {
    const allocator = testing.failing_allocator;
    const zerothree = comptime ascii.range('0', '3');
    const zeroseven = comptime ascii.range('0', '7');
    const octal_escape = comptime combine(.{
        ascii.char('\\'),
        oneOf(.{
            combine(.{ zerothree, zeroseven, zeroseven }),
            combine(.{ zeroseven, zeroseven }),
            zeroseven,
        }),
    }).asStr();
    try expectResult([]const u8, .{ .value = "\\145" }, octal_escape.parse(allocator, "145"));
}

results in this error then

❯ zig build test --summary all
test
└─ run test
   └─ zig test Debug native 1 errors
mecha.zig:415:28: error: expected type 'error{ParserFailed,OtherError,OutOfMemory}!mecha.Result(meta.CreateUniqueTuple(3,.{ u8, u8, u8 }))', found 'mecha.Result(meta.CreateUniqueTuple(2,.{ u8, u8 }))'
                    return res;
                           ^~~
mecha.zig:37:12: note: struct declared here (2 times)
    return struct {
           ^~~~~~
mecha.zig:412:66: note: function return type declared here
        fn parse(allocator: mem.Allocator, str: []const u8) Error!Result(ParserResult(@TypeOf(parsers[0]))) {
                                                            ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

whereas adding .asStr() to each parser within oneOf fixes it?

joelreymont commented 4 weeks ago

This can be reduced to

test "asStr1" {
    const allocator = testing.failing_allocator;
    const parser = comptime oneOf(.{
        combine(.{ascii.char('0')}),
        combine(.{ ascii.char('1'), ascii.char('2') }),
    }).asStr();
    try expectResult([]const u8, .{ .value = "4" }, parser.parse(allocator, "4"));
}

and the problem seems to be with combine within oneOf.

joelreymont commented 4 weeks ago

The actual problem is that the result type of oneOf is the type of the first parser.

This should be documented somewhere.

Hejsil commented 4 weeks ago

The actual problem is that the result type of oneOf is the type of the first parser.

This should be documented somewhere.

It's kinda documented here

https://github.com/Hejsil/mecha/blob/master/mecha.zig#L405-L406

But I do see how this is not entirely clear.

joelreymont commented 4 weeks ago

Right. It will return the result of the first parser that succeeds but the result type will be the type of the first parser in the combinator.