on master help sign in
Data/Syntax.hs+86−10
since splitsnapshots
unifiedsplit
@@ -10,24 +10,28 @@ License : MIT
10Maintainer : Paweł Nowak <pawel834@gmail.com>
10Maintainer : Paweł Nowak <pawel834@gmail.com>
11Stability : experimental
11Stability : experimental
12
12
13−Abstract syntax descriptions based on semi-isomorphisms.
13+Reversible parsing and pretty-printing.
14-}
14-}
15module Data.Syntax (
15module Data.Syntax (
16 -- * Syntax.
16 -- * Syntax.
17 Syntax(..),
17 Syntax(..),
18+ Isolable(..),
18 -- * Common isomorphisms.
19 -- * Common isomorphisms.
19 packed
20 packed
20 ) where
21 ) where
21
22
22−import Prelude hiding (take, takeWhile)
23+import Prelude hiding (take, takeWhile, id, (.))
23
24
25+import Control.Category
24−import Control.Category.Reader
26+import Control.Category.Reader
25−import Control.Category.Structures
27+import Control.Category.Structures
26−import Control.Lens.Iso
28+import Control.Lens.Iso
27−import Control.Lens.SemiIso
29+import Control.Lens.SemiIso
28−import Control.SIArrow
30+import Control.SIArrow
29−import Data.MonoTraversable
31+import Data.MonoTraversable
30−import Data.Sequences hiding (take, takeWhile)
32+import Data.Sequences hiding (take, takeWhile, replicate)
33+import qualified Data.Vector as V
34+import qualified Data.Vector.Unboxed as VU
31
35
32-- | An isomorphism between a sequence and a list of its elements.
36-- | An isomorphism between a sequence and a list of its elements.
33packed :: IsSequence seq => Iso' seq [Element seq]
37packed :: IsSequence seq => Iso' seq [Element seq]
@@ -36,7 +40,7 @@ packed = iso otoList fromList
36-- | An abstract syntax description based on semi-isomorphisms.
40-- | An abstract syntax description based on semi-isomorphisms.
37--
41--
38-- This class can be implemented by both parsers and printers.
42-- This class can be implemented by both parsers and printers.
39−--
43+--
40-- The usual use is to write a polymorphic syntax description and instantiate it
44-- The usual use is to write a polymorphic syntax description and instantiate it
41-- both as a parser and a printer. Examples are available in 'syntax-example' and
45-- both as a parser and a printer. Examples are available in 'syntax-example' and
42-- 'syntax-example-json' packages.
46-- 'syntax-example-json' packages.
@@ -95,6 +99,58 @@ class ( SIArrow syn
95 takeTill1 :: (Element (Seq syn) -> Bool) -> syn () (Seq syn)
99 takeTill1 :: (Element (Seq syn) -> Bool) -> syn () (Seq syn)
96 takeTill1 p = takeWhile1 (not . p)
100 takeTill1 p = takeWhile1 (not . p)
97
101
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+
98 {-# MINIMAL anyChar #-}
154 {-# MINIMAL anyChar #-}
99
155
100instance Syntax syn => Syntax (ReaderCT env syn) where
156instance Syntax syn => Syntax (ReaderCT env syn) where
@@ -110,3 +166,23 @@ instance Syntax syn => Syntax (ReaderCT env syn) where
110 takeWhile1 = clift . takeWhile1
166 takeWhile1 = clift . takeWhile1
111 takeTill = clift . takeTill
167 takeTill = clift . takeTill
112 takeTill1 = clift . takeTill1
168 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
173+
174+-- | Execute a computation in an isolated context.
175+--
176+-- The motivating example: you want to write a function
177+--
178+-- > serializeList :: Syntax syn => syn () a -> syn () [a]
179+--
180+-- Notice that we cannot just use simany, because the first @syn () a@
181+-- could eat the entire sequence (even though we printed more than 1 value!), so
182+-- we have to insert some kind of separators between the element. But how can we
183+-- be sure that @syn () a@ will not eat our separators? We can't! Thats why we
184+-- have to do the parsing in two stages: first extract the sequence between separators,
185+-- then run the @syn () a@ on this sequence.
186+class Syntax syn => Isolable syn where
187+ -- | Turns a computation into one executed in an isolated context.
188+ isolate :: syn () b -> syn (Seq syn) b
Data/Syntax/Combinator.hs+149−12
@@ -1,3 +1,6 @@
1+{-# LANGUAGE RankNTypes #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE FlexibleContexts #-}
1{- |
4{- |
2Module : Data.Syntax.Combinator
5Module : Data.Syntax.Combinator
3Description : Combinators that work with any sequence type.
6Description : Combinators that work with any sequence type.
@@ -9,12 +12,50 @@ Stability : experimental
9
12
10Combinators that work with any sequence type.
13Combinators that work with any sequence type.
11-}
14-}
12−module Data.Syntax.Combinator where
15+module Data.Syntax.Combinator
16+ (
17+ -- * Combinators.
18+ optional,
19+ opt,
20+ opt_,
21+ choice,
22+ eitherOf,
13
23
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
14−import Control.Category.Structures
50+import Control.Category.Structures
15−import Control.Lens
51+import Control.Lens
16−import Control.Lens.SemiIso
52+import Control.Lens.SemiIso
17−import Control.SIArrow
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)
18
59
19-- | One or zero occurences of @f@.
60-- | One or zero occurences of @f@.
20optional :: SIArrow cat => cat () a -> cat () (Maybe a)
61optional :: SIArrow cat => cat () a -> cat () (Maybe a)
@@ -29,6 +70,15 @@ opt_ :: SIArrow cat => cat () () -> cat () ()
29opt_ f = semiIso (const (Left "opt_")) Right /$/ f
70opt_ f = semiIso (const (Left "opt_")) Right /$/ f
30 /+/ sipure id
71 /+/ sipure id
31
72
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+
32-- | @manyTill p end@ applies action p zero or more times until action
82-- | @manyTill p end@ applies action p zero or more times until action
33-- end succeeds, and returns the list of values returned by p.
83-- end succeeds, and returns the list of values returned by p.
34manyTill :: SIArrow cat => cat () a -> cat () () -> cat () [a]
84manyTill :: SIArrow cat => cat () a -> cat () () -> cat () [a]
@@ -43,11 +93,98 @@ sepBy v s = sepBy1 v s /+/ sipure _Empty
43sepBy1 :: SIArrow cat => cat () a -> cat () () -> cat () [a]
93sepBy1 :: SIArrow cat => cat () a -> cat () () -> cat () [a]
44sepBy1 v s = _Cons /$/ v /*/ (s */ sepBy1 v s /+/ sipure _Empty)
94sepBy1 v s = _Cons /$/ v /*/ (s */ sepBy1 v s /+/ sipure _Empty)
45
95
46−-- | Tries to apply the actions in the list in order, until one of
96+-- | A string of given length.
47−-- them succeeds. Returns the value of the succeeding action.
97+takeArr :: Syntax syn => syn Int (Seq syn)
48−choice :: SIArrow cat => [cat () a] -> cat () a
98+takeArr = sibind $ iso (\n -> constant n #>> take n)
49−choice = foldr (/+/) (sifail "choice: all alternatives failed")
99+ (\s -> constant (Seq.olength s) #>> take (Seq.olength s))
50
100
51−-- | Combine two alternatives.
101+-- | Constant size vector with separators.
52−eitherOf :: SIArrow cat => cat () a -> cat () b -> cat () (Either a b)
102+--
53−eitherOf a b = _Left /$/ a /+/ _Right /$/ b
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)
Data/Syntax/Indent.hs+1−1
@@ -10,7 +10,7 @@ License : MIT
10Maintainer : Paweł Nowak <pawel834@gmail.com>
10Maintainer : Paweł Nowak <pawel834@gmail.com>
11Stability : experimental
11Stability : experimental
12
12
13−Provides a very simple indentation as a category transformer (a functor from Cat to Cat).
13+Provides a very simple indentation as a category transformer.
14-}
14-}
15module Data.Syntax.Indent (
15module Data.Syntax.Indent (
16 Indent,
16 Indent,
syntax.cabal+7−7
@@ -4,9 +4,10 @@ synopsis: Reversible parsing and pretty-printing.
4description:
4description:
5 "syntax" allows you to write a single syntax description and instantiate is both as a parser and a pretty printer.
5 "syntax" allows you to write a single syntax description and instantiate is both as a parser and a pretty printer.
6 .
6 .
7− Syntax descriptions are written in applicative or arrow style. The library uses a custom hierarchy, provided by the
7+ Syntax descriptions are written in applicative or arrow style. The library uses a custom typeclass hierarchy, provided
8− "semi-iso" package. Most of the time you will be using operators like '/$/' and '/*/', just like parser combinators.
8+ by the "semi-iso" package. Most of the time you will be using operators like '/$/', '/*/' and '/+/' (= '<|>'), just
9− When more power is needed - e.g. when the syntax depends on the parsed or printed value - you turn to arrows.
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.
10 .
11 .
11 Semi-isomorphisms from "semi-iso" are the basic building block of syntax descriptions. I recommend reading
12 Semi-isomorphisms from "semi-iso" are the basic building block of syntax descriptions. I recommend reading
12 the hackage page of "semi-iso" first, as it contains much more information.
13 the hackage page of "semi-iso" first, as it contains much more information.
@@ -19,11 +20,10 @@ description:
19 Advanced formatting and parsing (for example indentation, haskell layout rule) is implemented as category transformers
20 Advanced formatting and parsing (for example indentation, haskell layout rule) is implemented as category transformers
20 (similar to monad transformers). Currently only simple indentation is implemented (in "Data.Syntax.Indent") - basically
21 (similar to monad transformers). Currently only simple indentation is implemented (in "Data.Syntax.Indent") - basically
21 a reader category transformer that tracks current indentation level. I plan on implementing Haskell layout rule in the
22 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.
23 .
24 .
24− Note that the library can work with both text and binary data. There are no binary combinators implemented - yet.
25+ The library can work with both text and binary data. Alas, 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 ;).
26+ I will implement them when i have the time (but these category transformers look so much more interesting for now ;).
27 .
27 .
28 EXAMPLES! See @syntax-example@ and @syntax-example-json@ for examples.
28 EXAMPLES! See @syntax-example@ and @syntax-example-json@ for examples.
29 .
29 .