packages feed

syntax-1.0.0.0: Data/Syntax/Combinator.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{- |
Module      :  Data.Syntax.Combinator
Description :  Combinators that work with any sequence type.
Copyright   :  (c) Daan Leijen 1999-2001, Bryan O'Sullivan 2007-2014, Paweł Nowak 2014
License     :  MIT

Maintainer  :  Paweł Nowak <pawel834@gmail.com>
Stability   :  experimental

Combinators that work with any sequence type.
-}
module Data.Syntax.Combinator
    (
    -- * Combinators.
    optional,
    opt,
    opt_,
    choice,
    eitherOf,

    -- * Lists.
    manyTill,
    sepBy,
    sepBy1,

    -- * Arrowized combinators.
    takeArr,

    -- * Vectors.
    vecNSepBy,
    ivecNSepBy,
    vec,
    vecSepBy,
    ivec,
    ivecSepBy,

    -- * Unboxed vectors.
    uvecNSepBy,
    uivecNSepBy,
    uvec,
    uvecSepBy,
    uivec,
    uivecSepBy
    ) where

import           Control.Category
import           Control.Category.Structures
import           Control.Lens
import           Control.Lens.SemiIso
import           Control.SIArrow
import qualified Data.MonoTraversable as Seq
import           Data.Syntax
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as VU
import           Prelude hiding (id, (.), take)

-- | One or zero occurences of @f@.
optional :: SIArrow cat => cat () a -> cat () (Maybe a)
optional f = _Just /$/ f /+/ sipure _Nothing

-- | Like 'optional', but specialized for @()@.
opt :: SIArrow cat => cat () () -> cat () ()
opt f = f /+/ sipure id

-- | Parser one or zero occurences of @f@, but prints nothing.
opt_ :: SIArrow cat => cat () () -> cat () ()
opt_ f =  semiIso (const (Left "opt_")) Right /$/ f
      /+/ sipure id

-- | Tries to apply the actions in the list in order, until one of
-- them succeeds. Returns the value of the succeeding action.
choice :: SIArrow cat => [cat () a] -> cat () a
choice = foldr (/+/) (sifail "choice: all alternatives failed")

-- | Combine two alternatives.
eitherOf :: SIArrow cat => cat () a -> cat () b -> cat () (Either a b)
eitherOf a b = _Left /$/ a /+/ _Right /$/ b

-- | @manyTill p end@ applies action p zero or more times until action
-- end succeeds, and returns the list of values returned by p.
manyTill :: SIArrow cat => cat () a -> cat () () -> cat () [a]
manyTill p end =  _Empty /$/ end
              /+/ _Cons /$/ p /*/ manyTill p end

-- | Zero or more occurences of @v@ separated by @s@.
sepBy :: SIArrow cat => cat () a -> cat () () -> cat () [a]
sepBy v s = sepBy1 v s /+/ sipure _Empty

-- | One or more occurences of @v@ separated by @s@.
sepBy1 :: SIArrow cat => cat () a -> cat () () -> cat () [a]
sepBy1 v s = _Cons /$/ v /*/ (s */ sepBy1 v s /+/ sipure _Empty)

-- | A string of given length.
takeArr :: Syntax syn => syn Int (Seq syn)
takeArr = sibind $ iso (\n -> constant n #>> take n)
                       (\s -> constant (Seq.olength s) #>> take (Seq.olength s))

-- | Constant size vector with separators.
--
-- @vecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
vecNSepBy :: Syntax syn => Int -> syn () a -> syn () () -> syn () (V.Vector a)
vecNSepBy n e sep = ivecNSepBy n (unit ^>> second e) sep

-- | Constant size vector with separators and index-aware elements.
--
-- @ivecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
-- Each element gets its index and should output a value and the index unchanged.
ivecNSepBy :: Syntax syn => Int -> syn Int (Int, a) -> syn () () -> syn () (V.Vector a)
ivecNSepBy n e sep = ivecN n $ sibind $ iso el (el . fst)
  where
    el k | k < n - 1 = unit ^>> e *** sep >># unit
         | otherwise = e

-- | Runtime sized vector. The size can depend on the result of some computation.
--
-- @vec e@ describes a vector with elements @e@.
vec :: Syntax syn => syn () a -> syn Int (V.Vector a)
vec e = vecSepBy e (siarr id)

-- | Runtime sized vector with separators. The size can depend on the result of some
-- computation.
--
-- @vecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
vecSepBy :: Syntax syn => syn () a -> syn () () -> syn Int (V.Vector a)
vecSepBy e sep = ivecSepBy (unit ^>> second e) sep

-- | Runtime sized vector with index-aware elements. The size can depend on the result
-- of some computation.
--
-- @ivec e@ describes a vector with elements @e@.
ivec :: Syntax syn => syn Int (Int, a) -> syn Int (V.Vector a)
ivec e = ivecSepBy e (siarr id)

-- | Runtime sized vector with index-aware elements and separators. The size can depend
-- on the result of some computation.
--
-- @ivecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
ivecSepBy :: Syntax syn => syn Int (Int, a) -> syn () () -> syn Int (V.Vector a)
ivecSepBy e sep = sibind $ iso (\n -> constant n #>> ivecNSepBy n e sep)
                               (\v -> constant (V.length v) #>> ivecNSepBy (V.length v) e sep)

-- | Constant size unboxed vector with separators.
--
-- @uvecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
uvecNSepBy :: (Syntax syn, VU.Unbox a) => Int -> syn () a -> syn () () -> syn () (VU.Vector a)
uvecNSepBy n e sep = uivecNSepBy n (unit ^>> second e) sep

-- | Constant size unboxed vector with separators and index-aware elements.
--
-- @uivecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
-- Each element gets its index and should output a value and the index unchanged.
uivecNSepBy :: (Syntax syn, VU.Unbox a) => Int -> syn Int (Int, a)
            -> syn () () -> syn () (VU.Vector a)
uivecNSepBy n e sep = uivecN n $ sibind $ iso el (el . fst)
  where
    el k | k < n - 1 = unit ^>> e *** sep >># unit
         | otherwise = e

-- | Runtime sized unboxed vector. The size can depend on the result of some computation.
--
-- @uvec e@ describes a vector with elements @e@.
uvec :: (Syntax syn, VU.Unbox a) => syn () a -> syn Int (VU.Vector a)
uvec e = uvecSepBy e (siarr id)

-- | Runtime sized unboxed vector with separators. The size can depend on the result of some
-- computation.
--
-- @uvecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
uvecSepBy :: (Syntax syn, VU.Unbox a) => syn () a -> syn () () -> syn Int (VU.Vector a)
uvecSepBy e sep = uivecSepBy (unit ^>> second e) sep

-- | Runtime sized unboxed vector with index-aware elements. The size can depend on the result
-- of some computation.
--
-- @uivec e@ describes a vector with elements @e@.
uivec :: (Syntax syn, VU.Unbox a) => syn Int (Int, a) -> syn Int (VU.Vector a)
uivec e = uivecSepBy e (siarr id)

-- | Runtime sized unboxed vector with index-aware elements and separators. The size can depend
-- on the result of some computation.
--
-- @uivecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
uivecSepBy :: (Syntax syn, VU.Unbox a) => syn Int (Int, a)
           -> syn () () -> syn Int (VU.Vector a)
uivecSepBy e sep = sibind $ iso (\n -> constant n #>> uivecNSepBy n e sep)
                                (\v -> constant (VU.length v)
                                       #>> uivecNSepBy (VU.length v) e sep)