|
1 |
| -module Text.Parsing.Parser where |
| 1 | +module Text.Parsing.Parser |
| 2 | + ( ParseError |
| 3 | + , parseErrorMessage |
| 4 | + , parseErrorPosition |
| 5 | + , ParseState(..) |
| 6 | + , ParserT(..) |
| 7 | + , Parser |
| 8 | + , runParser |
| 9 | + , consume |
| 10 | + , fail |
| 11 | + ) where |
2 | 12 |
|
3 | 13 | import Prelude
|
4 |
| - |
5 |
| -import Control.Lazy (class Lazy) |
6 |
| -import Control.Monad.State.Class (class MonadState) |
7 |
| -import Control.Monad.Trans (class MonadTrans) |
8 |
| -import Control.MonadPlus (class MonadPlus, class MonadZero, class Alternative) |
9 |
| -import Control.Plus (class Plus, class Alt) |
| 14 | +import Control.Alt (class Alt) |
| 15 | +import Control.Lazy (defer, class Lazy) |
| 16 | +import Control.Monad.Except (class MonadError, ExceptT(..), throwError, runExceptT) |
| 17 | +import Control.Monad.Rec.Class (class MonadRec) |
| 18 | +import Control.Monad.State (runStateT, class MonadState, StateT(..), gets, evalStateT, modify) |
| 19 | +import Control.Monad.Trans.Class (lift, class MonadTrans) |
| 20 | +import Control.MonadPlus (class Alternative, class MonadZero, class MonadPlus, class Plus) |
10 | 21 | import Data.Either (Either(..))
|
11 |
| -import Data.Identity (Identity, runIdentity) |
| 22 | +import Data.Identity (Identity) |
| 23 | +import Data.Newtype (class Newtype, unwrap) |
12 | 24 | import Data.Tuple (Tuple(..))
|
13 | 25 | import Text.Parsing.Parser.Pos (Position, initialPos)
|
14 | 26 |
|
15 | 27 | -- | A parsing error, consisting of a message and position information.
|
16 |
| -data ParseError = ParseError |
17 |
| - { message :: String |
18 |
| - , position :: Position |
19 |
| - } |
| 28 | +data ParseError = ParseError String Position |
| 29 | + |
| 30 | +parseErrorMessage :: ParseError -> String |
| 31 | +parseErrorMessage (ParseError msg _) = msg |
| 32 | + |
| 33 | +parseErrorPosition :: ParseError -> Position |
| 34 | +parseErrorPosition (ParseError _ pos) = pos |
20 | 35 |
|
21 | 36 | instance showParseError :: Show ParseError where
|
22 |
| - show (ParseError msg) = "ParseError { message: " <> msg.message <> ", position: " <> show msg.position <> " }" |
| 37 | + show (ParseError msg pos) = |
| 38 | + "(ParseError " <> show msg <> show pos <> ")" |
23 | 39 |
|
24 |
| -instance eqParseError :: Eq ParseError where |
25 |
| - eq (ParseError {message : m1, position : p1}) (ParseError {message : m2, position : p2}) = m1 == m2 && p1 == p2 |
| 40 | +derive instance eqParseError :: Eq ParseError |
| 41 | +derive instance ordParseError :: Ord ParseError |
26 | 42 |
|
27 |
| --- | `PState` contains the remaining input and current position. |
28 |
| -data PState s = PState |
29 |
| - { input :: s |
30 |
| - , position :: Position |
31 |
| - } |
| 43 | +-- | Contains the remaining input and current position. |
| 44 | +data ParseState s = ParseState s Position Boolean |
32 | 45 |
|
33 | 46 | -- | The Parser monad transformer.
|
34 | 47 | -- |
|
35 |
| --- | The first type argument is the stream type. Typically, this is either `String`, or some sort of token stream. |
36 |
| -newtype ParserT s m a = ParserT (PState s -> m { input :: s, result :: Either ParseError a, consumed :: Boolean, position :: Position }) |
| 48 | +-- | The first type argument is the stream type. Typically, this is either `String`, |
| 49 | +-- | or some sort of token stream. |
| 50 | +newtype ParserT s m a = ParserT (ExceptT ParseError (StateT (ParseState s) m) a) |
37 | 51 |
|
38 |
| --- | Apply a parser by providing an initial state. |
39 |
| -unParserT :: forall m s a. ParserT s m a -> PState s -> m { input :: s, result :: Either ParseError a, consumed :: Boolean, position :: Position } |
40 |
| -unParserT (ParserT p) = p |
| 52 | +derive instance newtypeParserT :: Newtype (ParserT s m a) _ |
41 | 53 |
|
42 | 54 | -- | Apply a parser, keeping only the parsed result.
|
43 |
| -runParserT :: forall m s a. Monad m => PState s -> ParserT s m a -> m (Either ParseError a) |
44 |
| -runParserT s p = do |
45 |
| - o <- unParserT p s |
46 |
| - pure o.result |
| 55 | +runParserT :: forall m s a. Monad m => s -> ParserT s m a -> m (Either ParseError a) |
| 56 | +runParserT s p = evalStateT (runExceptT (unwrap p)) initialState where |
| 57 | + initialState = ParseState s initialPos false |
47 | 58 |
|
48 | 59 | -- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
|
49 | 60 | type Parser s a = ParserT s Identity a
|
50 | 61 |
|
51 | 62 | -- | Apply a parser, keeping only the parsed result.
|
52 | 63 | runParser :: forall s a. s -> Parser s a -> Either ParseError a
|
53 |
| -runParser s = runIdentity <<< runParserT (PState { input: s, position: initialPos }) |
| 64 | +runParser s = unwrap <<< runParserT s |
54 | 65 |
|
55 |
| -instance functorParserT :: (Functor m) => Functor (ParserT s m) where |
56 |
| - map f p = ParserT $ \s -> f' <$> unParserT p s |
57 |
| - where |
58 |
| - f' o = { input: o.input, result: f <$> o.result, consumed: o.consumed, position: o.position } |
59 |
| - |
60 |
| -instance applyParserT :: Monad m => Apply (ParserT s m) where |
61 |
| - apply = ap |
| 66 | +instance lazyParserT :: Lazy (ParserT s m a) where |
| 67 | + defer f = ParserT (ExceptT (defer (runExceptT <<< unwrap <<< f))) |
62 | 68 |
|
63 |
| -instance applicativeParserT :: Monad m => Applicative (ParserT s m) where |
64 |
| - pure a = ParserT $ \(PState { input: s, position: pos }) -> pure { input: s, result: Right a, consumed: false, position: pos } |
| 69 | +derive newtype instance functorParserT :: Functor m => Functor (ParserT s m) |
| 70 | +derive newtype instance applyParserT :: Monad m => Apply (ParserT s m) |
| 71 | +derive newtype instance applicativeParserT :: Monad m => Applicative (ParserT s m) |
| 72 | +derive newtype instance bindParserT :: Monad m => Bind (ParserT s m) |
| 73 | +derive newtype instance monadParserT :: Monad m => Monad (ParserT s m) |
| 74 | +derive newtype instance monadRecParserT :: MonadRec m => MonadRec (ParserT s m) |
| 75 | +derive newtype instance monadStateParserT :: Monad m => MonadState (ParseState s) (ParserT s m) |
| 76 | +derive newtype instance monadErrorParserT :: Monad m => MonadError ParseError (ParserT s m) |
65 | 77 |
|
66 | 78 | instance altParserT :: Monad m => Alt (ParserT s m) where
|
67 |
| - alt p1 p2 = ParserT $ \s -> unParserT p1 s >>= \o -> |
68 |
| - case o.result of |
69 |
| - Left _ | not o.consumed -> unParserT p2 s |
70 |
| - _ -> pure o |
| 79 | + alt p1 p2 = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState i p _)) -> do |
| 80 | + Tuple e s'@(ParseState i' p' c') <- runStateT (runExceptT (unwrap p1)) (ParseState i p false) |
| 81 | + case e of |
| 82 | + Left err |
| 83 | + | not c' -> runStateT (runExceptT (unwrap p2)) s |
| 84 | + _ -> pure (Tuple e s') |
71 | 85 |
|
72 | 86 | instance plusParserT :: Monad m => Plus (ParserT s m) where
|
73 | 87 | empty = fail "No alternative"
|
74 | 88 |
|
75 | 89 | instance alternativeParserT :: Monad m => Alternative (ParserT s m)
|
76 | 90 |
|
77 |
| -instance bindParserT :: Monad m => Bind (ParserT s m) where |
78 |
| - bind p f = ParserT $ \s -> unParserT p s >>= \o -> |
79 |
| - case o.result of |
80 |
| - Left err -> pure { input: o.input, result: Left err, consumed: o.consumed, position: o.position } |
81 |
| - Right a -> updateConsumedFlag o.consumed <$> unParserT (f a) (PState { input: o.input, position: o.position }) |
82 |
| - where |
83 |
| - updateConsumedFlag c o = { input: o.input, consumed: c || o.consumed, result: o.result, position: o.position } |
84 |
| - |
85 |
| -instance monadParserT :: Monad m => Monad (ParserT s m) |
86 |
| - |
87 | 91 | instance monadZeroParserT :: Monad m => MonadZero (ParserT s m)
|
88 | 92 |
|
89 | 93 | instance monadPlusParserT :: Monad m => MonadPlus (ParserT s m)
|
90 | 94 |
|
91 | 95 | instance monadTransParserT :: MonadTrans (ParserT s) where
|
92 |
| - lift m = ParserT $ \(PState { input: s, position: pos }) -> (\a -> { input: s, consumed: false, result: Right a, position: pos }) <$> m |
93 |
| - |
94 |
| -instance monadStateParserT :: Monad m => MonadState s (ParserT s m) where |
95 |
| - state f = ParserT $ \(PState { input: s, position: pos }) -> |
96 |
| - pure $ case f s of |
97 |
| - Tuple a s' -> { input: s', consumed: false, result: Right a, position: pos } |
98 |
| - |
99 |
| -instance lazyParserT :: Lazy (ParserT s m a) where |
100 |
| - defer f = ParserT $ \s -> unParserT (f unit) s |
| 96 | + lift = ParserT <<< lift <<< lift |
101 | 97 |
|
102 | 98 | -- | Set the consumed flag.
|
103 | 99 | consume :: forall s m. Monad m => ParserT s m Unit
|
104 |
| -consume = ParserT $ \(PState { input: s, position: pos }) -> pure { consumed: true, input: s, result: Right unit, position: pos } |
| 100 | +consume = modify \(ParseState input position _) -> |
| 101 | + ParseState input position true |
105 | 102 |
|
106 | 103 | -- | Fail with a message.
|
107 | 104 | fail :: forall m s a. Monad m => String -> ParserT s m a
|
108 |
| -fail message = ParserT $ \(PState { input: s, position: pos }) -> pure $ parseFailed s pos message |
109 |
| - |
110 |
| --- | Creates a failed parser state for the remaining input `s` and current position |
111 |
| --- | with an error message. |
112 |
| --- | |
113 |
| --- | Most of the time, `fail` should be used instead. |
114 |
| -parseFailed :: forall s a. s -> Position -> String -> { input :: s, result :: Either ParseError a, consumed :: Boolean, position :: Position } |
115 |
| -parseFailed s pos message = { input: s, consumed: false, result: Left (ParseError { message: message, position: pos }), position: pos } |
| 105 | +fail message = do |
| 106 | + position <- gets \(ParseState _ pos _) -> pos |
| 107 | + throwError (ParseError message position) |
0 commit comments