{-| Module : Language.Rust.Parser.Reversed Description : Parsing literals Copyright : (c) Alec Theriault, 2017-2018 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental Portability : GHC Datatypes wrapping lists and non-empty lists designed for fast append (as opposed to prepend) along with the usual class instances. -} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} #if __GLASGOW_HASKELL__ < 800 {-# LANGUAGE FlexibleContexts #-} #endif {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE DeriveDataTypeable #-} module Language.Rust.Parser.Reversed ( Reversed(..), toNonEmpty, unsnoc, snoc, NonEmpty(..), ) where import Language.Rust.Data.Position import Data.Foldable ( Foldable(toList) ) import Data.Semigroup as Sem ( Semigroup(..) ) import qualified Language.Rust.Parser.NonEmpty as N import Language.Rust.Parser.NonEmpty (NonEmpty(..), listCons) import qualified GHC.Exts as G import Data.Data (Data(..), Typeable) -- | Wrap a data type where all the operations are reversed newtype Reversed f a = Reversed (f a) instance Functor f => Functor (Reversed f) where fmap f (Reversed xs) = Reversed (fmap f xs) instance Foldable (Reversed []) where foldMap f (Reversed xs) = foldMap f (reverse xs) toList (Reversed xs) = reverse xs instance Foldable (Reversed NonEmpty) where foldMap f (Reversed xs) = foldMap f (N.reverse xs) toList (Reversed xs) = reverse (toList xs) instance Sem.Semigroup (f a) => Sem.Semigroup (Reversed f a) where Reversed xs <> Reversed ys = Reversed (ys Sem.<> xs) instance Monoid (f a) => Monoid (Reversed f a) where mempty = Reversed mempty mappend (Reversed xs) (Reversed ys) = Reversed (mappend ys xs) instance G.IsList (f a) => G.IsList (Reversed f a) where type Item (Reversed f a) = G.Item (f a) fromList xs = Reversed (G.fromList (reverse xs)) toList (Reversed xs) = reverse (G.toList xs) instance Located (f a) => Located (Reversed f a) where spanOf (Reversed xs) = spanOf xs deriving instance (Typeable f, Typeable a, Data (f a)) => Data (Reversed f a) -- | Convert a reversed 'NonEmpty' back into a normal one. {-# INLINE toNonEmpty #-} toNonEmpty :: Reversed NonEmpty a -> NonEmpty a toNonEmpty (Reversed xs) = N.reverse xs -- | Remove an element from the end of a non-empty reversed sequence {-# INLINE unsnoc #-} unsnoc :: Reversed NonEmpty a -> (Reversed [] a, a) unsnoc (Reversed xs) = (Reversed $ N.tail xs, N.head xs) -- | Add an element to the end of a reversed sequence to produce a non-empty -- reversed sequence {-# INLINE snoc #-} snoc :: Reversed [] a -> a -> Reversed NonEmpty a snoc (Reversed xs) x = Reversed (x `listCons` xs)