philomena/lib/search/literal_parser.ex

58 lines
1.2 KiB
Elixir
Raw Normal View History

2019-11-02 19:34:25 +01:00
defmodule Search.LiteralParser do
import NimbleParsec
2019-11-02 22:02:46 +01:00
import Search.Helpers
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
end