I’m having trouble implementing a parser. Either it enters an infinite recursive loop, or it only parses the first part of the input and drops the rest.
For context, I’m writing a parser for a query language, and it contains the ability to nest boolean expressions. Here’s a stripped-down version of what I’m working with:
defmodule CESQL.Parsec do
import NimbleParsec
value_identifier = ascii_string([?a..?z], min: 1, max: 20)
boolean_operation =
parsec(:expr)
|> ignore(string(" "))
|> choice([
string("AND"),
string("OR"),
string("XOR")
])
|> ignore(string(" "))
|> parsec(:expr)
expr =
choice([
value_identifier,
boolean_operation
])
defparsec :expr, expr
end
My end goal is to parse a boolean expression, and I intend to allow for complex nested expressions like (a AND b) OR c
. But for starters, this is what I want out of the above code:
iex> CESQL.Parsec.expr("a AND b")
{:ok, ["a", "AND", "b"], "", _, _, _}
However, when I place value_identifier
first in expr
’s argument to choice/2
, the parser takes the first value and drops the rest of the string, which looks like this:
iex> CESQL.Parsec.expr("a AND b")
{:ok, ["a"], " AND b", _, _, _}
Alternatively, when I place boolean_operation
as the first choice, I believe the parser enters an infinite loop trying to find the start of an expression, because my test times out.
How can I get this working the way I want it to? I’ve tried using NimbleParsec.lookahead/2
every way I can think of, but I might be misunderstanding how it works, because I’ve had no luck.