|
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