J-F-Liu / pom

PEG parser combinators using operator overloading without macros.
MIT License
496 stars 30 forks source link

Exponential blow-up in compilation time #23

Closed MageSlayer closed 5 years ago

MageSlayer commented 5 years ago

Hi

We are trying to use "pom" for heavy/branchy grammar and looks like intermediate types generated by '|' cause exponential time taken by Rust compiler.

I am wondering - is there any way to reduce their size? You might have experience the same.

BR

singaraiona commented 5 years ago

Hi! Piece of code causes exponential grow compile time:

...
#[cfg_attr(rustfmt, rustfmt_skip)]
fn _noun<'a>(c: Context) -> Combinator<impl Parser<'a, u8, Output = AST>> {
    call_verb(c.clone()) |
    call_lambda(c.clone()) |
    v_bool(c.clone()).map(|(v, c)| new_vector_bool(&v, c.alloc()))                                   |
    v_symbol(c.clone()).map(|(v, c)| new_vector_symbol(&v, c.alloc()))                               |
    v_char(c.clone()).map(|(v, c)| new_string(&v, c.alloc()))                                        |
    v_num(c.clone())                                                                                 |
    plist(b'(', b')', c.clone()).map(|(v, c)| {
        vec2ast(v, true, c, |mut v, c| { v.insert(0, monad(&[b','])); new_list(&v, c.alloc()).lazy() }) }) |
    plist(b'[', b']', c.clone()).map(|(v, c)| new_list(&v, c.alloc()).lazy())                        |
    assign(c.clone()) |
    (s_symbol(c.clone()) - ende()).map(|(v, c)| symbol_or_primitive(v, c.clone()))                   |
    call_symbol(None, c.clone()) |
    endp().map(|_| new_scalar_nil())                                                                 |
    ende().map(|_| new_scalar_nil())
}
//
#[cfg_attr(rustfmt, rustfmt_skip)]
fn _expr<'a>(n: AST, c: Context) -> Combinator<impl Parser<'a, u8, Output = AST>> {
    grab!((n) (comment().opt() - endl()).map(move |_| n.clone())) |
    grab!((n,c) (verb2() + wd(c.clone())).map(move |(v,e)| new_list(&[dyad(v), n.clone(), e], c.alloc())))    |
    grab!((n,c) (verb1() + wd(c.clone())).map(move |(v,e)| new_list(&[dyad(&[v]), n.clone(), e], c.alloc()))) |
    grab!((n,c) call_symbol(Some(n), c.clone())) |
    grab!((n,c) (not_at(b")]};") * wd(c.clone())).map(move |e| new_list(&[dyad(&[b'@']), n.clone(), e], c.alloc()))) |
    grab!((n) empty().map(move |_| n.clone()))
}
...

Most of code omitted due to readability. The problem seems to be in too long type with | combinators.

J-F-Liu commented 5 years ago

I think this relates to Rust compiler implementation. You may try pom 1.x.

MageSlayer commented 5 years ago

Too bad. But thanks anyway.