shnewto / bnf

Parse BNF grammar definitions
MIT License
256 stars 22 forks source link

Empty String Rules Fail to Match #108

Closed Axiomatic-Mind closed 1 year ago

Axiomatic-Mind commented 1 year ago

When I match a grammar such as

<main> ::= "foo:" <bar>
 <bar> ::= "bar"

against foo:bar, it works. When I match a grammar such as

<main> ::= "foo:" ""

against foo:, it works. However, when I match

<main> ::= "foo:" <baz>
 <baz> ::= ""

against foo:, it doesn't work.

Replicable using this code:

fn main() {
    let grammar1: bnf::Grammar = "
        <main> ::= \"foo:\" <bar>
         <bar> ::= \"bar\"
    ".parse().unwrap();

    let grammar2: bnf::Grammar = "
        <main> ::= \"foo:\" \"\"
    ".parse().unwrap();

    let grammar3: bnf::Grammar = "
        <main> ::= \"foo:\" <baz>
         <baz> ::= \"\"
    ".parse().unwrap();

    assert!(grammar1.parse_input("foo:bar").next().is_some(), "grammar1 failed!");
    assert!(grammar2.parse_input("foo:"   ).next().is_some(), "grammar2 failed!");
    assert!(grammar3.parse_input("foo:"   ).next().is_some(), "grammar3 failed!");
}

Screenshot Why isn't a parse tree like this being generated?

ParseTree {
    lhs: Term::Nonterminal("main"),
    rhs: [
        ParseTreeNode::Terminal("foo:"),
        ParseTreeNode::Nonterminal(ParseTree {
            lhs: Term::Nonterminal("baz"),
            rhs: [
                ParseTreeNode::Terminal(""),
            ],
        }),
    ],
}

Is this intentional/explicable behavior, or a bug? Thanks!

CrockAgile commented 1 year ago

since the behavior is varying across those similar grammars, this seems like a bug to me. I have a hunch! so thanks for the great reproduction steps, and I will start investigating 🕵️

shnewto commented 1 year ago

@Axiomatic-Mind I just merged the PR that addresses this, the release will be publised to crates soon. Thanks for raising the issue!

shnewto commented 1 year ago

okay version 0.4.2 published to crates.io!

Axiomatic-Mind commented 1 year ago

Thanks for fixing this!