on master help sign in
3 files changed+225−29
since splitsnapshots
unifiedsplit
Data/Syntax.hs+69−10 Data/Syntax/Combinator.hs+149−12 syntax.cabal+7−7
Data/Syntax.hs+69−10
@@ -20,15 +20,18 @@ module Data.Syntax (
2020 packed
2121 ) where
2222
23−import Prelude hiding (take, takeWhile)
24−
25−import Control.Category.Reader
26−import Control.Category.Structures
27−import Control.Lens.Iso
28−import Control.Lens.SemiIso
29−import Control.SIArrow
30−import Data.MonoTraversable
31−import Data.Sequences hiding (take, takeWhile)
23+import Prelude hiding (take, takeWhile, id, (.))
24+
25+import Control.Category
26+import Control.Category.Reader
27+import Control.Category.Structures
28+import Control.Lens.Iso
29+import Control.Lens.SemiIso
30+import Control.SIArrow
31+import Data.MonoTraversable
32+import Data.Sequences hiding (take, takeWhile, replicate)
33+import qualified Data.Vector as V
34+import qualified Data.Vector.Unboxed as VU
3235
3336-- | An isomorphism between a sequence and a list of its elements.
3437packed :: IsSequence seq => Iso' seq [Element seq]
@@ -37,7 +40,7 @@ packed = iso otoList fromList
3740-- | An abstract syntax description based on semi-isomorphisms.
3841--
3942-- This class can be implemented by both parsers and printers.
40−--
43+--
4144-- The usual use is to write a polymorphic syntax description and instantiate it
4245-- both as a parser and a printer. Examples are available in 'syntax-example' and
4346-- 'syntax-example-json' packages.
@@ -96,6 +99,58 @@ class ( SIArrow syn
9699 takeTill1 :: (Element (Seq syn) -> Bool) -> syn () (Seq syn)
97100 takeTill1 p = takeWhile1 (not . p)
98101
102+ -- | Constant size vector. The default implementation uses lists, but
103+ -- "syntax-attoparsec" and "syntax-printer" override it with an efficient
104+ -- implementation that works on a vector directly.
105+ --
106+ -- @vecN n e@ describes a size @n@ vector with elements @e@.
107+ --
108+ -- Also see 'Data.Syntax.Combinator.vec'.
109+ vecN :: Int -> syn () a -> syn () (V.Vector a)
110+ vecN n e = packed /$/ sireplicate n e
111+
112+ -- | Constant size vector with index-aware element. The default implementation
113+ -- uses lists, but "syntax-attoparsec" and "syntax-printer" override it with an
114+ -- efficient implementation that works on a vector directly.
115+ --
116+ -- @ivecN n e@ describes a size @n@ vector with elements @e@. Each element
117+ -- gets its index and should output a value and the index unchanged.
118+ --
119+ -- Also see 'Data.Syntax.Combinator.ivec'.
120+ ivecN :: Int -> syn Int (Int, a) -> syn () (V.Vector a)
121+ ivecN n e = (packed /$/)
122+ $ sisequence
123+ $ map (\(i, e') -> constant i ^>> e'
124+ >>> first (sipure (constant i))
125+ >># unit . swapped)
126+ $ zip [0 .. n-1] (replicate n e)
127+
128+ -- | Constant size unboxed vector. The default implementation uses lists, but
129+ -- "syntax-attoparsec" and "syntax-printer" override it with an efficient
130+ -- implementation that works on a vector directly.
131+ --
132+ -- @vecN n e@ describes a size @n@ vector with elements @e@.
133+ --
134+ -- Also see 'Data.Syntax.Combinator.vec'.
135+ uvecN :: VU.Unbox a => Int -> syn () a -> syn () (VU.Vector a)
136+ uvecN n e = packed /$/ sireplicate n e
137+
138+ -- | Constant size unboxed vector with index-aware element. The default implementation
139+ -- uses lists, but "syntax-attoparsec" and "syntax-printer" override it with an
140+ -- efficient implementation that works on a vector directly.
141+ --
142+ -- @ivecN n e@ describes a size @n@ vector with elements @e@. Each element
143+ -- gets its index and should output a value and the index unchanged.
144+ --
145+ -- Also see 'Data.Syntax.Combinator.ivec'.
146+ uivecN :: VU.Unbox a => Int -> syn Int (Int, a) -> syn () (VU.Vector a)
147+ uivecN n e = (packed /$/)
148+ $ sisequence
149+ $ map (\(i, e') -> constant i ^>> e'
150+ >>> first (sipure (constant i))
151+ >># unit . swapped)
152+ $ zip [0 .. n-1] (replicate n e)
153+
99154 {-# MINIMAL anyChar #-}
100155
101156instance Syntax syn => Syntax (ReaderCT env syn) where
@@ -111,6 +166,10 @@ instance Syntax syn => Syntax (ReaderCT env syn) where
111166 takeWhile1 = clift . takeWhile1
112167 takeTill = clift . takeTill
113168 takeTill1 = clift . takeTill1
169+ vecN n e = ReaderCT $ vecN n . runReaderCT e
170+ ivecN n e = ReaderCT $ ivecN n . runReaderCT e
171+ uvecN n e = ReaderCT $ uvecN n . runReaderCT e
172+ uivecN n e = ReaderCT $ uivecN n . runReaderCT e
114173
115174-- | Execute a computation in an isolated context.
116175--
Data/Syntax/Combinator.hs+149−12
@@ -1,3 +1,6 @@
1+{-# LANGUAGE RankNTypes #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE FlexibleContexts #-}
14{- |
25Module : Data.Syntax.Combinator
36Description : Combinators that work with any sequence type.
@@ -9,12 +12,50 @@ Stability : experimental
912
1013Combinators that work with any sequence type.
1114-}
12−module Data.Syntax.Combinator where
15+module Data.Syntax.Combinator
16+ (
17+ -- * Combinators.
18+ optional,
19+ opt,
20+ opt_,
21+ choice,
22+ eitherOf,
1323
14−import Control.Category.Structures
15−import Control.Lens
16−import Control.Lens.SemiIso
17−import Control.SIArrow
24+ -- * Lists.
25+ manyTill,
26+ sepBy,
27+ sepBy1,
28+
29+ -- * Arrowized combinators.
30+ takeArr,
31+
32+ -- * Vectors.
33+ vecNSepBy,
34+ ivecNSepBy,
35+ vec,
36+ vecSepBy,
37+ ivec,
38+ ivecSepBy,
39+
40+ -- * Unboxed vectors.
41+ uvecNSepBy,
42+ uivecNSepBy,
43+ uvec,
44+ uvecSepBy,
45+ uivec,
46+ uivecSepBy
47+ ) where
48+
49+import Control.Category
50+import Control.Category.Structures
51+import Control.Lens
52+import Control.Lens.SemiIso
53+import Control.SIArrow
54+import qualified Data.MonoTraversable as Seq
55+import Data.Syntax
56+import qualified Data.Vector as V
57+import qualified Data.Vector.Unboxed as VU
58+import Prelude hiding (id, (.), take)
1859
1960-- | One or zero occurences of @f@.
2061optional :: SIArrow cat => cat () a -> cat () (Maybe a)
@@ -29,6 +70,15 @@ opt_ :: SIArrow cat => cat () () -> cat () ()
2970opt_ f = semiIso (const (Left "opt_")) Right /$/ f
3071 /+/ sipure id
3172
73+-- | Tries to apply the actions in the list in order, until one of
74+-- them succeeds. Returns the value of the succeeding action.
75+choice :: SIArrow cat => [cat () a] -> cat () a
76+choice = foldr (/+/) (sifail "choice: all alternatives failed")
77+
78+-- | Combine two alternatives.
79+eitherOf :: SIArrow cat => cat () a -> cat () b -> cat () (Either a b)
80+eitherOf a b = _Left /$/ a /+/ _Right /$/ b
81+
3282-- | @manyTill p end@ applies action p zero or more times until action
3383-- end succeeds, and returns the list of values returned by p.
3484manyTill :: SIArrow cat => cat () a -> cat () () -> cat () [a]
@@ -43,11 +93,98 @@ sepBy v s = sepBy1 v s /+/ sipure _Empty
4393sepBy1 :: SIArrow cat => cat () a -> cat () () -> cat () [a]
4494sepBy1 v s = _Cons /$/ v /*/ (s */ sepBy1 v s /+/ sipure _Empty)
4595
46−-- | Tries to apply the actions in the list in order, until one of
47−-- them succeeds. Returns the value of the succeeding action.
48−choice :: SIArrow cat => [cat () a] -> cat () a
49−choice = foldr (/+/) (sifail "choice: all alternatives failed")
96+-- | A string of given length.
97+takeArr :: Syntax syn => syn Int (Seq syn)
98+takeArr = sibind $ iso (\n -> constant n #>> take n)
99+ (\s -> constant (Seq.olength s) #>> take (Seq.olength s))
50100
51−-- | Combine two alternatives.
52−eitherOf :: SIArrow cat => cat () a -> cat () b -> cat () (Either a b)
53−eitherOf a b = _Left /$/ a /+/ _Right /$/ b
101+-- | Constant size vector with separators.
102+--
103+-- @vecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
104+vecNSepBy :: Syntax syn => Int -> syn () a -> syn () () -> syn () (V.Vector a)
105+vecNSepBy n e sep = ivecNSepBy n (unit ^>> second e) sep
106+
107+-- | Constant size vector with separators and index-aware elements.
108+--
109+-- @ivecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
110+-- Each element gets its index and should output a value and the index unchanged.
111+ivecNSepBy :: Syntax syn => Int -> syn Int (Int, a) -> syn () () -> syn () (V.Vector a)
112+ivecNSepBy n e sep = ivecN n $ sibind $ iso el (el . fst)
113+ where
114+ el k | k < n - 1 = unit ^>> e *** sep >># unit
115+ | otherwise = e
116+
117+-- | Runtime sized vector. The size can depend on the result of some computation.
118+--
119+-- @vec e@ describes a vector with elements @e@.
120+vec :: Syntax syn => syn () a -> syn Int (V.Vector a)
121+vec e = vecSepBy e (siarr id)
122+
123+-- | Runtime sized vector with separators. The size can depend on the result of some
124+-- computation.
125+--
126+-- @vecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
127+vecSepBy :: Syntax syn => syn () a -> syn () () -> syn Int (V.Vector a)
128+vecSepBy e sep = ivecSepBy (unit ^>> second e) sep
129+
130+-- | Runtime sized vector with index-aware elements. The size can depend on the result
131+-- of some computation.
132+--
133+-- @ivec e@ describes a vector with elements @e@.
134+ivec :: Syntax syn => syn Int (Int, a) -> syn Int (V.Vector a)
135+ivec e = ivecSepBy e (siarr id)
136+
137+-- | Runtime sized vector with index-aware elements and separators. The size can depend
138+-- on the result of some computation.
139+--
140+-- @ivecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
141+ivecSepBy :: Syntax syn => syn Int (Int, a) -> syn () () -> syn Int (V.Vector a)
142+ivecSepBy e sep = sibind $ iso (\n -> constant n #>> ivecNSepBy n e sep)
143+ (\v -> constant (V.length v) #>> ivecNSepBy (V.length v) e sep)
144+
145+-- | Constant size unboxed vector with separators.
146+--
147+-- @uvecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
148+uvecNSepBy :: (Syntax syn, VU.Unbox a) => Int -> syn () a -> syn () () -> syn () (VU.Vector a)
149+uvecNSepBy n e sep = uivecNSepBy n (unit ^>> second e) sep
150+
151+-- | Constant size unboxed vector with separators and index-aware elements.
152+--
153+-- @uivecNSepBy n e sep@ describes a size @n@ vector with elements @e@ separated by @sep@.
154+-- Each element gets its index and should output a value and the index unchanged.
155+uivecNSepBy :: (Syntax syn, VU.Unbox a) => Int -> syn Int (Int, a)
156+ -> syn () () -> syn () (VU.Vector a)
157+uivecNSepBy n e sep = uivecN n $ sibind $ iso el (el . fst)
158+ where
159+ el k | k < n - 1 = unit ^>> e *** sep >># unit
160+ | otherwise = e
161+
162+-- | Runtime sized unboxed vector. The size can depend on the result of some computation.
163+--
164+-- @uvec e@ describes a vector with elements @e@.
165+uvec :: (Syntax syn, VU.Unbox a) => syn () a -> syn Int (VU.Vector a)
166+uvec e = uvecSepBy e (siarr id)
167+
168+-- | Runtime sized unboxed vector with separators. The size can depend on the result of some
169+-- computation.
170+--
171+-- @uvecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
172+uvecSepBy :: (Syntax syn, VU.Unbox a) => syn () a -> syn () () -> syn Int (VU.Vector a)
173+uvecSepBy e sep = uivecSepBy (unit ^>> second e) sep
174+
175+-- | Runtime sized unboxed vector with index-aware elements. The size can depend on the result
176+-- of some computation.
177+--
178+-- @uivec e@ describes a vector with elements @e@.
179+uivec :: (Syntax syn, VU.Unbox a) => syn Int (Int, a) -> syn Int (VU.Vector a)
180+uivec e = uivecSepBy e (siarr id)
181+
182+-- | Runtime sized unboxed vector with index-aware elements and separators. The size can depend
183+-- on the result of some computation.
184+--
185+-- @uivecSepBy e sep@ describes a vector with elements @e@ separated by @sep@.
186+uivecSepBy :: (Syntax syn, VU.Unbox a) => syn Int (Int, a)
187+ -> syn () () -> syn Int (VU.Vector a)
188+uivecSepBy e sep = sibind $ iso (\n -> constant n #>> uivecNSepBy n e sep)
189+ (\v -> constant (VU.length v)
190+ #>> uivecNSepBy (VU.length v) e sep)
syntax.cabal+7−7
@@ -4,9 +4,10 @@ synopsis: Reversible parsing and pretty-printing.
44description:
55 "syntax" allows you to write a single syntax description and instantiate is both as a parser and a pretty printer.
66 .
7− Syntax descriptions are written in applicative or arrow style. The library uses a custom hierarchy, provided by the
8− "semi-iso" package. Most of the time you will be using operators like '/$/' and '/*/', just like parser combinators.
9− When more power is needed - e.g. when the syntax depends on the parsed or printed value - you turn to arrows.
7+ Syntax descriptions are written in applicative or arrow style. The library uses a custom typeclass hierarchy, provided
8+ by the "semi-iso" package. Most of the time you will be using operators like '/$/', '/*/' and '/+/' (= '<|>'), just
9+ like parser combinators. When more power is needed - e.g. when the syntax depends on the parsed or printed value -
10+ you turn to arrows.
1011 .
1112 Semi-isomorphisms from "semi-iso" are the basic building block of syntax descriptions. I recommend reading
1213 the hackage page of "semi-iso" first, as it contains much more information.
@@ -19,11 +20,10 @@ description:
1920 Advanced formatting and parsing (for example indentation, haskell layout rule) is implemented as category transformers
2021 (similar to monad transformers). Currently only simple indentation is implemented (in "Data.Syntax.Indent") - basically
2122 a reader category transformer that tracks current indentation level. I plan on implementing Haskell layout rule in the
22− future (as a reusable transformer).
23+ future.
2324 .
24− Note that the library can work with both text and binary data. There are no binary combinators implemented - yet.
25− Alas, these are not only useful combinators missing! I will slowly but steadily implement them over time
26− (but these category transformers look so much more interesting for now ;).
25+ The library can work with both text and binary data. Alas, there are no binary combinators implemented yet.
26+ I will implement them when i have the time (but these category transformers look so much more interesting for now ;).
2727 .
2828 EXAMPLES! See @syntax-example@ and @syntax-example-json@ for examples.
2929 .