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 23, 2020
1 parent d9d985a commit 057180a
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
10 changes: 7 additions & 3 deletions lib/parsing_nesting/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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('"')
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 057180a

Please sign in to comment.