diff --git a/lib/parsing_nesting/grammar.rb b/lib/parsing_nesting/grammar.rb index b3e8895..82618f1 100644 --- a/lib/parsing_nesting/grammar.rb +++ b/lib/parsing_nesting/grammar.rb @@ -18,11 +18,15 @@ class Grammar < Parslet::Parser # query is actually a list of expressions. rule :query do - (spacing? >> (expression | paren_unit) >> spacing?).repeat + (spacing? >> (expression | paren_unit) >> spacing?).repeat(1) + end + + rule :empty_paren do + (str('()')) end rule :paren_list do - (str('(') >> query >> str(')')).as(:list) + (str('(') >> query.repeat(1) >> str(')')).as(:list) end rule :paren_unit do @@ -59,7 +63,7 @@ class Grammar < Parslet::Parser end rule :token do - match['^ ")('].repeat(1).as(:token) + (match['^ ")('] | empty_paren ).repeat(1).as(:token) end rule :phrase do match('"') >> match['^"'].repeat(1).as(:phrase) >> match('"') diff --git a/spec/parsing_nesting/build_tree_spec.rb b/spec/parsing_nesting/build_tree_spec.rb index c1e33db..af5f84c 100644 --- a/spec/parsing_nesting/build_tree_spec.rb +++ b/spec/parsing_nesting/build_tree_spec.rb @@ -198,6 +198,29 @@ def should_be_not_expression(graph) end end + it "should parse term list with empty parens () " do + should_be_list parse("foo () bar") do |list| + expect(list.length).to eq(3) + expect(list[1].value).to eq('()') + end + end + + it "should parse term list with leading or trailing empty parens () " do + should_be_list parse("() foo ()") do |list| + expect(list.length).to eq(3) + expect(list[0].value).to eq('()') + expect(list[2].value).to eq('()') + end + end + + it "should parse term list with nested parens ()" do + should_be_list parse("(()) foo") do |list| + expect(list.length).to eq(2) + expect(list[0].value).to eq('()') + end + end + + it "should build for a crazy complicated one" do should_be_list parse("mark +twain AND huck OR fun OR ((jim AND river) AND (red -dogs))") do |list| should_be_term list[0], "mark" diff --git a/spec/parsing_nesting/consuming_spec.rb b/spec/parsing_nesting/consuming_spec.rb index 93dc28e..f9777e3 100644 --- a/spec/parsing_nesting/consuming_spec.rb +++ b/spec/parsing_nesting/consuming_spec.rb @@ -29,7 +29,8 @@ "NOT (four five)", "(one two three) OR (four five) AND six", '"foo+bar (baz"', - "(foo bar one AND two) AND (three four ten OR twelve)" + "(foo bar one AND two) AND (three four ten OR twelve)", + "one () two" ].each do |query| it "should consume<<#{query}>>" do expect { @parser.parse(query) }.not_to raise_error