2019-11-02 19:34:25 +01:00
|
|
|
defmodule Search.LiteralParser do
|
|
|
|
import NimbleParsec
|
2019-12-30 22:14:57 +01:00
|
|
|
|
|
|
|
defp to_number(input), do: Search.Helpers.to_number(input)
|
2019-11-02 19:34:25 +01:00
|
|
|
|
2019-11-02 22:02:46 +01:00
|
|
|
float =
|
|
|
|
ascii_string([?0..?9], min: 1)
|
|
|
|
|> optional(ascii_char('.') |> ascii_string([?0..?9], min: 1))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> reduce(:to_number)
|
2019-11-02 21:31:55 +01:00
|
|
|
|
2019-11-02 19:34:25 +01:00
|
|
|
edit_distance =
|
|
|
|
ignore(string("~"))
|
2019-11-02 22:02:46 +01:00
|
|
|
|> concat(float)
|
2019-11-02 19:34:25 +01:00
|
|
|
|> unwrap_and_tag(:fuzz)
|
|
|
|
|> eos()
|
|
|
|
|
|
|
|
stopwords =
|
|
|
|
choice([
|
|
|
|
string("*"),
|
|
|
|
string("?"),
|
|
|
|
edit_distance
|
|
|
|
])
|
|
|
|
|
|
|
|
normal =
|
|
|
|
lookahead_not(stopwords)
|
|
|
|
|> choice([
|
|
|
|
ignore(string("\\")) |> utf8_char([]),
|
|
|
|
utf8_char([])
|
|
|
|
])
|
|
|
|
|> repeat()
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:literal)
|
|
|
|
|> optional(edit_distance)
|
|
|
|
|> eos()
|
|
|
|
|
|
|
|
# Runs of Kleene stars are coalesced.
|
|
|
|
# Fuzzy search has no meaning in wildcard mode, so we ignore it.
|
|
|
|
wildcard =
|
|
|
|
lookahead_not(edit_distance)
|
|
|
|
|> choice([
|
|
|
|
ignore(string("\\")) |> utf8_char([]),
|
|
|
|
string("*") |> ignore(repeat(string("*"))),
|
|
|
|
utf8_char([])
|
|
|
|
])
|
|
|
|
|> repeat()
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:wildcard)
|
|
|
|
|> ignore(optional(edit_distance))
|
|
|
|
|> eos()
|
|
|
|
|
|
|
|
literal =
|
|
|
|
choice([
|
|
|
|
normal,
|
|
|
|
wildcard
|
|
|
|
])
|
|
|
|
|
|
|
|
defparsec :parse, literal
|
2019-12-30 22:14:57 +01:00
|
|
|
end
|