diff --git a/lib/philomena/search/lexer.ex b/lib/philomena/search/lexer.ex index 35a76f76..55abc3ff 100644 --- a/lib/philomena/search/lexer.ex +++ b/lib/philomena/search/lexer.ex @@ -8,6 +8,7 @@ defmodule Philomena.Search.Lexer do cond do is_float(float_val) -> float_val + is_integer(int_val) -> int_val end @@ -44,7 +45,7 @@ defmodule Philomena.Search.Lexer do quot = string("\"") - quoted_term = + quoted_term = ignore(quot) |> choice([ ignore(string("\\")) |> string("\""), @@ -57,47 +58,51 @@ defmodule Philomena.Search.Lexer do |> reduce({List, :to_string, []}) |> unwrap_and_tag(:term) - stop_words = choice([ - string("\\") |> eos(), - string(","), - concat(space, l_and), - concat(space, l_or), - concat(space, l_not), - rparen, - fuzz, - boost - ]) + stop_words = + choice([ + string("\\") |> eos(), + string(","), + concat(space, l_and), + concat(space, l_or), + concat(space, l_not), + rparen, + fuzz, + boost + ]) - defcombinatorp :simple_term, + defcombinatorp( + :simple_term, lookahead_not(stop_words) |> choice([ string("\\") |> utf8_char([]), string("(") |> parsec(:simple_term) |> string(")"), - utf8_char([]), + utf8_char([]) ]) |> times(min: 1) + ) unquoted_term = parsec(:simple_term) |> reduce({List, :to_string, []}) |> unwrap_and_tag(:term) - outer = choice([ - l_and, - l_or, - l_not, - lparen, - rparen, - boost, - fuzz, - space, - quoted_term, - unquoted_term - ]) + outer = + choice([ + l_and, + l_or, + l_not, + lparen, + rparen, + boost, + fuzz, + space, + quoted_term, + unquoted_term + ]) search = times(outer, min: 1) |> eos() - defparsec :search, search -end \ No newline at end of file + defparsec(:search, search) +end diff --git a/lib/philomena/search/parser.ex b/lib/philomena/search/parser.ex index 9fa3d66f..5f13d07e 100644 --- a/lib/philomena/search/parser.ex +++ b/lib/philomena/search/parser.ex @@ -1,13 +1,12 @@ defmodule Philomena.Search.Parser do - alias Philomena.Search.Lexer - def parse(ctx, tokens) do - {tree, [eof: "$"]} = search_top(ctx, tokens) + {tree, []} = search_top(ctx, tokens) {:ok, tree} rescue e in ArgumentError -> {:error, e.message} + _ -> {:error, "Parsing error."} end @@ -20,11 +19,13 @@ defmodule Philomena.Search.Parser do # # Boolean OR # + defp search_or(ctx, tokens) do case search_and(ctx, tokens) do {left, [{:or, _} | r_tokens]} -> {right, rest} = search_top(ctx, r_tokens) {%{bool: %{should: [left, right]}}, rest} + {child, rest} -> {child, rest} end @@ -33,11 +34,13 @@ defmodule Philomena.Search.Parser do # # Boolean AND # + defp search_and(ctx, tokens) do case search_boost(ctx, tokens) do {left, [{:and, _} | r_tokens]} -> {right, rest} = search_top(ctx, r_tokens) {%{bool: %{must: [left, right]}}, rest} + {child, rest} -> {child, rest} end @@ -46,10 +49,12 @@ defmodule Philomena.Search.Parser do # # Subquery score boosting # + defp search_boost(ctx, tokens) do case search_not(ctx, tokens) do {child, [{:boost, _}, {:float, value} | r_tokens]} -> {%{function_score: %{query: child, boost_factor: value}}, r_tokens} + {child, rest} -> {child, rest} end @@ -58,40 +63,52 @@ defmodule Philomena.Search.Parser do # # Boolean NOT # + defp search_not(ctx, [{:not, _} | r_tokens]) do {child, rest} = search_top(ctx, r_tokens) {%{bool: %{must_not: child}}, rest} end + defp search_not(ctx, tokens), do: search_group(ctx, tokens) # # Logical grouping # + defp search_group(ctx, [{:lparen, _} | rest]) do case search_top(ctx, rest) do {child, [{:rparen, _} | r_tokens]} -> {child, r_tokens} + _ -> raise ArgumentError, "Imbalanced parentheses." end end - defp search_group(_ctx, [{:rparen, _} | _rest]), do: raise ArgumentError, "Imbalanced parentheses." + + defp search_group(_ctx, [{:rparen, _} | _rest]), + do: raise(ArgumentError, "Imbalanced parentheses.") + defp search_group(ctx, tokens), do: search_fuzz(ctx, tokens) # # Term fuzzing # + defp search_fuzz(ctx, tokens) do - nil + search_term(ctx, tokens) end # # Search terms # - defp search_term(ctx, [{:term, t} | rest]) do - {TermParser.parse(ctx, t), rest} + + defp search_term(_ctx, [{:term, _t} | rest]) do + {[], rest} end - defp search_term(_ctx, [eof: "$"]), do: raise ArgumentError, "Expected a term, got ." - defp search_term(_ctx, [{_, text} | _rest]), do: raise ArgumentError, "Expected a term, got `#{text}'." -end \ No newline at end of file + + defp search_term(_ctx, []), do: raise(ArgumentError, "Expected a term, got .") + + defp search_term(_ctx, [{_, text} | _rest]), + do: raise(ArgumentError, "Expected a term, got `#{text}'.") +end diff --git a/mix.exs b/mix.exs index 38b82378..d47c1910 100644 --- a/mix.exs +++ b/mix.exs @@ -50,7 +50,7 @@ defmodule Philomena.MixProject do {:pot, "~> 0.10.1"}, {:secure_compare, "~> 0.1.0"}, {:elastix, "~> 0.7.1"}, - {:nimble_parsec, "~> 0.5.1"}, + {:nimble_parsec, "~> 0.5.1"} ] end