module Language.PureScript.Sugar.Operators.Common where import Prelude.Compat import Control.Monad.State import Data.Functor.Identity import qualified Text.Parsec as P import qualified Text.Parsec.Pos as P import qualified Text.Parsec.Expr as P import Language.PureScript.AST import Language.PureScript.Crash import Language.PureScript.Names type Chain a = [Either a a] toAssoc :: Associativity -> P.Assoc toAssoc Infixl = P.AssocLeft toAssoc Infixr = P.AssocRight toAssoc Infix = P.AssocNone token :: (P.Stream s Identity t) => (t -> Maybe a) -> P.Parsec s u a token = P.token (const "") (const (P.initialPos "")) parseValue :: P.Parsec (Chain a) () a parseValue = token (either Just (const Nothing)) P. "expression" parseOp :: (a -> Maybe (Qualified (OpName nameType))) -> P.Parsec (Chain a) () (Qualified (OpName nameType)) parseOp fromOp = token (either (const Nothing) fromOp) P. "operator" matchOp :: (a -> Maybe (Qualified (OpName nameType))) -> Qualified (OpName nameType) -> P.Parsec (Chain a) () () matchOp fromOp op = do ident <- parseOp fromOp guard $ ident == op opTable :: [[(Qualified (OpName nameType), Associativity)]] -> (a -> Maybe (Qualified (OpName nameType))) -> (Qualified (OpName nameType) -> a -> a -> a) -> [[P.Operator (Chain a) () Identity a]] opTable ops fromOp reapply = map (map (\(name, a) -> P.Infix (P.try (matchOp fromOp name) >> return (reapply name)) (toAssoc a))) ops ++ [[ P.Infix (P.try (parseOp fromOp >>= \ident -> return (reapply ident))) P.AssocLeft ]] matchOperators :: forall a nameType . Show a => (a -> Bool) -> (a -> Maybe (a, a, a)) -> (a -> Maybe (Qualified (OpName nameType))) -> (Qualified (OpName nameType) -> a -> a -> a) -> ([[P.Operator (Chain a) () Identity a]] -> P.OperatorTable (Chain a) () Identity a) -> [[(Qualified (OpName nameType), Associativity)]] -> a -> a matchOperators isBinOp extractOp fromOp reapply modOpTable ops = parseChains where parseChains :: a -> a parseChains ty | True <- isBinOp ty = bracketChain (extendChain ty) | otherwise = ty extendChain :: a -> Chain a extendChain ty | Just (op, l, r) <- extractOp ty = Left l : Right op : extendChain r | otherwise = [Left ty] bracketChain :: Chain a -> a bracketChain = either (\_ -> internalError "matchTypeOperators: cannot reorder operators") id . P.parse opParser "operator expression" opParser = P.buildExpressionParser (modOpTable (opTable ops fromOp reapply)) parseValue <* P.eof