-- | Parser for conditional restrictions.
module ConditionalRestriction.Internal.Parse.RestrictionParser where

import ConditionalRestriction.Internal.Parse.OpeningHoursParser
  ( pOpeningHours,
  )
import ConditionalRestriction.Internal.Parse.ParserLib
  ( Parser,
    anyOf,
    dbl,
    noneOf,
    strip,
    word,
    ws,
  )
import ConditionalRestriction.Parse.AST
  ( ComparisonOp (..),
    Condition (..),
    ConditionalRestriction (..),
    Expression (..),
  )
import Control.Applicative (Alternative (many, some, (<|>)))
import Data.Functor ()

-- | Parse conditional restrictions, e.g. @"90 \@ 18:00-22:00; 50 \@ wet"@.
pConditionalRestriction :: Parser String ConditionalRestriction
pConditionalRestriction :: Parser String ConditionalRestriction
pConditionalRestriction = [Expression] -> ConditionalRestriction
ConditionalRestriction forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String Expression
pExpression forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (String -> Parser String String
word String
";" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String Expression
pExpression))

pExpression :: Parser String Expression
pExpression :: Parser String Expression
pExpression = String -> [Condition] -> Expression
Expression forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> String
strip forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (String -> Parser String Char
noneOf String
"@")) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (String -> Parser String String
word String
"@" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String [Condition]
pMultipleConditions)

pMultipleConditions :: Parser String [Condition]
pMultipleConditions :: Parser String [Condition]
pMultipleConditions =
  (String -> Parser String String
word String
"(" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String [Condition]
pMultipleConditions forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* String -> Parser String String
word String
")")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String Condition
pCondition forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (String -> Parser String String
word String
"AND" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String Condition
pCondition)

pCondition :: Parser String Condition
pCondition :: Parser String Condition
pCondition =
  (String -> Parser String String
word String
"(" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String Condition
pCondition forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* String -> Parser String String
word String
")")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (OpeningHours -> Condition
OH forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String OpeningHours
pOpeningHours)
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (String -> ComparisonOp -> Double -> Condition
Comparison forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String String
pIdentifier forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String ComparisonOp
pCompOperator forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String Double
dbl forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser String String
ws)
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (String -> Condition
Absolute forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String String
pIdentifier)

pCompOperator :: Parser String ComparisonOp
pCompOperator :: Parser String ComparisonOp
pCompOperator =
  (ComparisonOp
GtEq forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String String
word String
">=")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ComparisonOp
LtEq forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String String
word String
"<=")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ComparisonOp
Eq forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String String
word String
"=")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ComparisonOp
Lt forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String String
word String
"<")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ComparisonOp
Gt forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String String
word String
">")

pIdentifier :: Parser String String
pIdentifier :: Parser String String
pIdentifier = forall (f :: * -> *) a. Alternative f => f a -> f [a]
some (String -> Parser String Char
anyOf forall a b. (a -> b) -> a -> b
$ [Char
'a' .. Char
'z'] forall a. [a] -> [a] -> [a]
++ [Char
'_', Char
'-']) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser String String
ws