Skip to content

Native/abstracted sub-parsers #340

@ckiee

Description

@ckiee

I'm in a similar situation to #199:

many1(block_expr_node).parse("*hi*")

fn block_expr_node<Input>() -> FnOpaque<Input, BlockExprNode>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
    opaque!(no_partial(
        choice!(bold(), char()).message("while parsing block_expr_node")
    ))
}


fn char<Input>() -> impl Parser<Input, Output = BlockExprNode>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
    satisfy(|c: char| !c.is_control())
        .map(|c| BlockExprNode::Char(c))
        .message("while parsing char")
}

fn bold<Input>() -> impl Parser<Input, Output = BlockExprNode>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
    (token('*'), many1(block_expr_node()), token('*'))
        .map(|(_, v, _)| BlockExprNode::Bold(v))
        .message("while parsing bold")
}

I think this does not work because once it starts to parse in bold, the many1(block_expr_node()) picks char and the input is consumed until EOF:

Error: Parse error at line: 1, column: 4
Unexpected end of input
Expected `*`
while parsing bold
while parsing char
while parsing block_expr_node

Replacing the bold implementation with:

fn bold<Input>() -> impl Parser<Input, Output = BlockExprNode>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
    (
        token('*'),
        take_until::<String, _, _>(token('*')).map(|s| {
            // HACK ouch ouch ouch
            many1(block_expr_node())
                .easy_parse(position::Stream::new(&s[..]))
                // this is the except on Result
                .expect("In bold subparser")
                .0
        }),
        token('*'),
    )
        .map(|(_, v, _)| BlockExprNode::Bold(v))
        .message("while parsing bold")
}

..parses correctly but is obviously messy and handling errors correctly as in #199 (comment) only adds more boilerplate. Do you think it could be possible to add an abstraction above flat_map so this could be done like:

fn bold<Input>() -> impl Parser<Input, Output = BlockExprNode>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
    (
        token('*'),
        take_until::<String, _, _>(token('*')).and_reparse_with(many1(block_expr_node()),
        token('*'),
    )
        .map(|(_, v, _)| BlockExprNode::Bold(v))
        .message("while parsing bold")
}

It'd still create the sub-parser in a flat_map but would hide the scary types from me :P

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions