Reputation: 879
I'm trying to make a queries parser in Haskell, but don't understand how I'm supposed to allow different optional paths of parser logic. My attempt:
query :: Parser Query
query = do
-- add more queries
reserved "SELECT"
select <- sequenceOfExpr
reserved "FROM"
table <- identifier
semi
return $ Select select table (BoolConst True)
<|> do
reserved "SELECT"
select <- sequenceOfExpr
reserved "FROM"
table <- identifier
reserved "WHERE"
whereQ <- bExpression
semi
return $ Select select table whereQ
<|> do
reserved "INSERT"
insert <- sequenceOfExpr
reserved "INTO"
table <- identifier
semi
return $ Insert insert table
<|> do
reserved "REMOVE"
reserved "FROM"
table <- identifier
reserved "WHERE"
whereQ <- bExpression
semi
return $ Remove table whereQ
<|> do
reserved "CREATE"
table <- identifier
fields <- sequenceOfExpr
semi
return $ Create table fields
<|> do
reserved "DROP"
table <- identifier
semi
return $ Drop table
Which works when parsing a string that corresponds to the first do stmt structure, e.g.:
"SELECT testField FROM testTable;"
but not for the others. E.g. when parsing:
"SELECT testField FROM testTable WHERE TRUE"
Instead of trying the other paths, it returns:
unexpected "W"
expecting ";"
In other words it seems like it only tries the first logic. What am I doing wrong?
Any help would be much appreciated!
Upvotes: 1
Views: 136
Reputation: 80880
This happens because the SELECT FROM
alternative has succeeded and returned its result, the parsing never got to trying the SELECT FROM WHERE
alternative.
In this specific case, I would just flip their order: try SELECT FROM WHERE
first, and if that doesn't work, fall back to SELECT FROM
. You would also need to wrap it in a try
in order for the parser to roll back to the beginning of the query.
Alternatively, you could make the WHERE
parsing a conditional part of the SELECT FROM
parser, something like this:
do
reserved "SELECT"
select <- sequenceOfExpr
reserved "FROM"
table <- identifier
whereQ <- try (reserved "WHERE" *> bExpression) <|> (pure $ BoolConst True)
semi
return $ Select select table whereQ
Upvotes: 2