{-# LANGUAGE TupleSections #-} -- | -- The ConditionalRestriction library offers functionality for parsing and -- evaluating of conditional restriction values -- (see [OSM Wiki](https://wiki.openstreetmap.org/wiki/Conditional_restrictions)). -- -- This module offers functions suitable for most basic use cases. module ConditionalRestriction ( needsData, evaluate, parseRestriction, ID, Value (..), Type (..), Token, Result (..), ErrorMsg, ) where import ConditionalRestriction.Internal.Evaluate ( ErrorMsg, result, ) import ConditionalRestriction.Internal.Parse.ParserLib (end, parse) import ConditionalRestriction.Internal.Parse.RestrictionParser ( pConditionalRestriction, ) import ConditionalRestriction.Parse.AST ( ConditionalRestriction, Token, ) import ConditionalRestriction.Parse.InputData ( ID, Type (..), Value (..), ) import ConditionalRestriction.Parse.InputDataParser (pValue) import ConditionalRestriction.Result (Result (..)) import Data.Bifunctor (Bifunctor (first)) -- | Takes a conditional restriction string and returns the data needed in order to evaluate this string. -- If the conditional restriction couldn't be parsed, -- an error message is returned instead. needsData :: String -> Result ErrorMsg [(ID, Type)] needsData s = parseRestriction s >>= \r -> case result [] r of Err (_, neededs) -> Ok neededs Ok _ -> Ok [] -- | Takes a conditional restriction string and some input data. -- It returns the value as a token if any restriction condition was met, or 'Nothing' otherwise. -- If there was a parsing error or a problem with the provided data, a list of error messages -- and a list of needed data is returned. evaluate :: String -> [(ID, String)] -> Result ([ErrorMsg], [(ID, Type)]) (Maybe Token) evaluate s ds = do r <- first (\msg -> (["Parser error in restriction: " ++ msg], [])) $ parseRestriction s ds' <- first (\msg -> (["Parser error in data: " ++ msg], [])) $ mapM (\(id, d) -> (id,) . fst <$> parse (pValue <* end) d) ds result ds' r -- | Takes a conditional restriction string and returns the corresponding AST. -- Take a look at the "ConditionalRestriction.Parse.AST" module for AST manipulation. parseRestriction :: String -> Result ErrorMsg ConditionalRestriction parseRestriction = fmap fst . parse (pConditionalRestriction <* end)