Skip to content

Commit

Permalink
Allow empty parens in a string to be safely parsed
Browse files Browse the repository at this point in the history
This change allows an empty set of parens, `()`, to be in a string and to be parsed as a token. Prior to this change, and empty set of parens would be parsed as a list with no contents which could not be successfully parsed, but instead results in a error as described in projectblacklight#101.

This change fixes issue projectblacklight#101.
  • Loading branch information
Chad Nelson committed Sep 24, 2020
1 parent 4173fef commit 17973c3
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
7 changes: 6 additions & 1 deletion lib/parsing_nesting/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ class Grammar < Parslet::Parser
paren_list
end

rule :empty_paren do
(str('()'))
end


# Note well: It was tricky to parse the thing we want where you can
# have a flat list with boolean operators, but where 'OR' takes precedence.
# eg "A AND B OR C AND C" or "A OR B AND C OR D". Tricky to parse at all,
Expand Down Expand Up @@ -59,7 +64,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('"')
Expand Down
23 changes: 23 additions & 0 deletions spec/parsing_nesting/build_tree_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion spec/parsing_nesting/consuming_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 17973c3

Please sign in to comment.