m4rw3r/chomp

`parse!` does not support inline `map`, `map_err` or `bind` for named actions

Closed this issue · 3 comments

Problem

The parse! macro does not allow anything but a standard function call as a named action in its grammar:

NAMED_ACTION  = $ident '(' ($expr ',')* ','? ')'

It is desirable to be able to write code like this:

fn make_it_cool(n: u32) -> u32 { n + 2 }
fn validate_number<I>(i: Input<I>, n: u32) -> ParseResult<I, u32, NumberError> {
    if n == 10 { i.ret(n) } else { i.err(NumberError) }
}

parse!{i;
    let x = decimal().map(make_it_cool);
    let y = decimal().bind(validate_number);
    ret x + y
}

Possible solutions

Explicitly add bind, map and map_err to the grammar

This will enable the syntax above, but only for bind, map and map_err it will not enable any method to be called on the return value of the called function. This comes at the price of a much more complex macro for the actions part because of the explicit parts of the grammar.

Do nothing and instruct people to use the inline-action form

// using the same functions from above
parse!{i;
    let x = i -> decimal(i).map(make_it_cool);
    let x = i -> decimal(i).bind(validate_number);
    ret x + y
}

Drawbacks:

  • The Input<I> type gets exposed needlessly inside of the macro
  • More characters to write for the user

TODO: Any more possible solutions?

dckc commented

I ran into this several times too.

Ah... so that's how the inline action works. I saw documentation of the syntax, but nothing about how it works. Did I miss some documentation?

@dckc I am working on improved documentation for the parse! syntax as a part of #31

Adding support for bind, map and map_err will cause needless complexity in the parse! macro as it looks right now. map can be implemented by using let x = ...; ret ... for simple cases.