summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2014-05-09 03:27:54 -0400
committerjoe <joe@jerkface.net>2014-05-09 03:27:54 -0400
commit13d2a0a61de6477f8966ddf26592010206dec4b1 (patch)
treecf996efda8446e563528c1b175acc8f7ef96524a
parent77744e9231a06739aafd241418683a9ce384df5d (diff)
scanAndParse export
-rw-r--r--ScanningParser.hs77
1 files changed, 22 insertions, 55 deletions
diff --git a/ScanningParser.hs b/ScanningParser.hs
index 9eed080..a0a5d23 100644
--- a/ScanningParser.hs
+++ b/ScanningParser.hs
@@ -2,6 +2,7 @@
2{-# LANGUAGE ExistentialQuantification #-} 2{-# LANGUAGE ExistentialQuantification #-}
3module ScanningParser 3module ScanningParser
4 ( ScanningParser(..) 4 ( ScanningParser(..)
5 , scanAndParse
5 ) where 6 ) where
6 7
7import Data.Maybe 8import Data.Maybe
@@ -10,10 +11,6 @@ import Control.Applicative
10import Control.Monad 11import Control.Monad
11import Data.Monoid 12import Data.Monoid
12 13
13-- | Utility to operate on the first item of a pair.
14first :: (a->b) -> (a,c) -> (b,c)
15first f (x,y) = (f x, y)
16
17-- | This type provides the means to parse a stream of 'tok' and extract all 14-- | This type provides the means to parse a stream of 'tok' and extract all
18-- the 'obj' parses that occur. 15-- the 'obj' parses that occur.
19-- 16--
@@ -29,6 +26,25 @@ data ScanningParser tok obj = forall partial. ScanningParser
29 -- parse an object and return the unconsumed tokens. 26 -- parse an object and return the unconsumed tokens.
30 } 27 }
31 28
29instance Functor (ScanningParser a) where
30 fmap f (ScanningParser ffst pbody)
31 = ScanningParser ffst (\b -> first (fmap f) . pbody b)
32 where
33 first f (x,y) = (f x, y)
34
35
36instance Monoid (ScanningParser a b) where
37 mempty = ScanningParser (const Nothing) (const $ const (Nothing,[]))
38 mappend (ScanningParser ffstA pbdyA)
39 (ScanningParser ffstB pbdyB)
40 = ScanningParser ffst pbody
41 where
42 ffst x = mplus (Left <$> ffstA x)
43 (Right <$> ffstB x)
44 pbody (Left apart) = pbdyA apart
45 pbody (Right bpart) = pbdyB bpart
46
47
32-- | Apply a 'ScanningParser' to a list of tokens, yielding a list of parsed 48-- | Apply a 'ScanningParser' to a list of tokens, yielding a list of parsed
33-- objects. 49-- objects.
34scanAndParse :: ScanningParser a c -> [a] -> [c] 50scanAndParse :: ScanningParser a c -> [a] -> [c]
@@ -36,7 +52,8 @@ scanAndParse psr [] = []
36scanAndParse psr@(ScanningParser ffst pbdy) ts = do 52scanAndParse psr@(ScanningParser ffst pbdy) ts = do
37 (b,xs) <- take 1 $ mapMaybe findfst' tss 53 (b,xs) <- take 1 $ mapMaybe findfst' tss
38 let (mc,ts') = pbdy b xs 54 let (mc,ts') = pbdy b xs
39 maybe [] (:scanAndParse psr ts') mc 55 rec = scanAndParse psr ts'
56 maybe rec (:rec) mc
40 where 57 where
41 tss = tails ts 58 tss = tails ts
42 findfst' ts = do 59 findfst' ts = do
@@ -44,53 +61,3 @@ scanAndParse psr@(ScanningParser ffst pbdy) ts = do
44 b <- ffst x 61 b <- ffst x
45 return (b,drop 1 ts) 62 return (b,drop 1 ts)
46 63
47instance Functor (ScanningParser a) where
48 fmap f (ScanningParser ffst pbody)
49 = ScanningParser ffst (\b -> first (fmap f) . pbody b)
50
51instance Monoid (ScanningParser a b) where
52 mempty = ScanningParser (const Nothing) (const $ const (Nothing,[]))
53 mappend a b = a <+> b
54
55-- | Combine two parsers into one that tries either.
56(<+>) ::
57 ScanningParser tok obj
58 -> ScanningParser tok obj
59 -> ScanningParser tok obj
60parserA@(ScanningParser ffstA pbdyA) <+> parserB@(ScanningParser ffstB pbdyB) = ScanningParser ffst pbody
61 where
62 ffst x = mplus (Left <$> ffstA x)
63 (Right <$> ffstB x)
64 pbody (Left apart) = pbdyA apart
65 pbody (Right bpart) = pbdyB bpart
66
67{-
68
69-- | Map a parser into a sum type. This is useful for combining multiple
70-- 'ScanningParser's for a single pass scan.
71--
72-- HELP: Can this be done with one function argument instead of three?
73mapParser ::
74 (c -> y)
75 -> (b -> x)
76 -> (x -> b)
77 -> ScanningParser a b c
78 -> ScanningParser a x y
79mapParser g f invf psr =
80 psr { findFirst = fmap f . findFirst psr
81 , parseBody = \b as -> first (fmap g) $ parseBody psr (invf b) as
82 }
83
84-- | map 'Right' over a 'ScanningParser'
85--
86-- > mapRight = mapParser Right Right (\(Right x)->x)
87mapRight :: ScanningParser a b c -> ScanningParser a (Either x b) (Either y c)
88mapRight = mapParser Right Right (\(Right x)->x)
89
90-- | map 'Left' over a 'ScanningParser'
91--
92-- > mapLeft = mapParser Left Left (\(Left x)->x)
93mapLeft :: ScanningParser a b c -> ScanningParser a (Either b x) (Either c y)
94mapLeft = mapParser Left Left (\(Left x)->x)
95
96-}