diff options
author | joe <joe@jerkface.net> | 2014-05-09 03:27:54 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-05-09 03:27:54 -0400 |
commit | 13d2a0a61de6477f8966ddf26592010206dec4b1 (patch) | |
tree | cf996efda8446e563528c1b175acc8f7ef96524a /ScanningParser.hs | |
parent | 77744e9231a06739aafd241418683a9ce384df5d (diff) |
scanAndParse export
Diffstat (limited to 'ScanningParser.hs')
-rw-r--r-- | ScanningParser.hs | 77 |
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 #-} |
3 | module ScanningParser | 3 | module ScanningParser |
4 | ( ScanningParser(..) | 4 | ( ScanningParser(..) |
5 | , scanAndParse | ||
5 | ) where | 6 | ) where |
6 | 7 | ||
7 | import Data.Maybe | 8 | import Data.Maybe |
@@ -10,10 +11,6 @@ import Control.Applicative | |||
10 | import Control.Monad | 11 | import Control.Monad |
11 | import Data.Monoid | 12 | import Data.Monoid |
12 | 13 | ||
13 | -- | Utility to operate on the first item of a pair. | ||
14 | first :: (a->b) -> (a,c) -> (b,c) | ||
15 | first 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 | ||
29 | instance 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 | |||
36 | instance 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. |
34 | scanAndParse :: ScanningParser a c -> [a] -> [c] | 50 | scanAndParse :: ScanningParser a c -> [a] -> [c] |
@@ -36,7 +52,8 @@ scanAndParse psr [] = [] | |||
36 | scanAndParse psr@(ScanningParser ffst pbdy) ts = do | 52 | scanAndParse 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 | ||
47 | instance Functor (ScanningParser a) where | ||
48 | fmap f (ScanningParser ffst pbody) | ||
49 | = ScanningParser ffst (\b -> first (fmap f) . pbody b) | ||
50 | |||
51 | instance 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 | ||
60 | parserA@(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? | ||
73 | mapParser :: | ||
74 | (c -> y) | ||
75 | -> (b -> x) | ||
76 | -> (x -> b) | ||
77 | -> ScanningParser a b c | ||
78 | -> ScanningParser a x y | ||
79 | mapParser 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) | ||
87 | mapRight :: ScanningParser a b c -> ScanningParser a (Either x b) (Either y c) | ||
88 | mapRight = mapParser Right Right (\(Right x)->x) | ||
89 | |||
90 | -- | map 'Left' over a 'ScanningParser' | ||
91 | -- | ||
92 | -- > mapLeft = mapParser Left Left (\(Left x)->x) | ||
93 | mapLeft :: ScanningParser a b c -> ScanningParser a (Either b x) (Either c y) | ||
94 | mapLeft = mapParser Left Left (\(Left x)->x) | ||
95 | |||
96 | -} | ||