1
+ -- | Types and operations for monadic parsing.
2
+ -- |
3
+ -- | Combinators are in the `Parsing.Combinators` module.
4
+ -- |
5
+ -- | Primitive parsers for `String` input streams are in the `Parsing.String`
6
+ -- | module.
1
7
module Parsing
2
- ( ParseError (..)
3
- , parseErrorMessage
4
- , parseErrorPosition
5
- , ParseState (..)
6
- , ParserT (..)
7
- , Parser
8
+ ( Parser
8
9
, runParser
10
+ , ParserT (..)
9
11
, runParserT
10
12
, runParserT'
11
- , hoistParserT
12
- , mapParserT
13
+ , ParseError (..)
14
+ , parseErrorMessage
15
+ , parseErrorPosition
16
+ , Position (..)
17
+ , initialPos
13
18
, consume
14
19
, position
15
20
, fail
16
21
, failWithPosition
17
22
, region
23
+ , ParseState (..)
24
+ , hoistParserT
25
+ , mapParserT
18
26
) where
19
27
20
28
import Prelude
@@ -29,13 +37,15 @@ import Control.Monad.Trans.Class (class MonadTrans)
29
37
import Control.MonadPlus (class Alternative , class MonadPlus , class Plus )
30
38
import Data.Either (Either (..))
31
39
import Data.Function.Uncurried (Fn2 , Fn5 , mkFn2 , mkFn3 , mkFn5 , runFn2 , runFn3 , runFn5 )
40
+ import Data.Generic.Rep (class Generic )
32
41
import Data.Identity (Identity )
33
42
import Data.Lazy as Lazy
34
43
import Data.Newtype (unwrap )
44
+ import Data.Show.Generic (genericShow )
35
45
import Data.Tuple (Tuple (..), fst )
36
- import Parsing.Pos (Position , initialPos )
37
46
38
- -- | A parsing error, consisting of a message and position information.
47
+ -- | A parsing error, consisting of an error message and
48
+ -- | the position in the input stream at which the error occurred.
39
49
data ParseError = ParseError String Position
40
50
41
51
parseErrorMessage :: ParseError -> String
@@ -51,7 +61,13 @@ instance showParseError :: Show ParseError where
51
61
derive instance eqParseError :: Eq ParseError
52
62
derive instance ordParseError :: Ord ParseError
53
63
54
- -- | Contains the remaining input and current position.
64
+ -- | The internal state of the `ParserT s m` monad.
65
+ -- |
66
+ -- | Contains the remaining input and current position and the consumed flag.
67
+ -- |
68
+ -- | The consumed flag is used to implement the rule for `alt` that
69
+ -- | - If the left parser fails *without consuming any input*, then backtrack and try the right parser.
70
+ -- | - If the left parser fails and consumes input, then fail immediately.
55
71
data ParseState s = ParseState s Position Boolean
56
72
-- ParseState constructor has three parameters,
57
73
-- s: the remaining input
@@ -66,10 +82,7 @@ data ParseState s = ParseState s Position Boolean
66
82
--
67
83
-- http://blog.ezyang.com/2014/05/parsec-try-a-or-b-considered-harmful/
68
84
69
- -- | The Parser monad transformer.
70
- -- |
71
- -- | The first type argument is the stream type. Typically, this is either `String`,
72
- -- | or some sort of token stream.
85
+ -- | The `Parser s` monad with a monad transformer parameter `m`.
73
86
newtype ParserT s m a = ParserT
74
87
-- The parser is implemented using continuation-passing-style with uncurried
75
88
-- functions. In addition to the usual error and success continuations, there
@@ -102,13 +115,15 @@ data RunParser s m a
102
115
| Lift (m (Unit -> RunParser s m a ))
103
116
| Stop (ParseState s ) (Either ParseError a )
104
117
105
- -- | Apply a parser, keeping only the parsed result .
118
+ -- | `runParser` with a monad transfomer parameter `m` .
106
119
runParserT :: forall m s a . MonadRec m => s -> ParserT s m a -> m (Either ParseError a )
107
120
runParserT s p = fst <$> runParserT' initialState p
108
121
where
109
122
initialState :: ParseState s
110
123
initialState = ParseState s initialPos false
111
124
125
+ -- | Run a parser and produce either an error or the result of the parser
126
+ -- | along with the internal state of the parser when it finishes.
112
127
runParserT'
113
128
:: forall m s a
114
129
. MonadRec m
@@ -132,10 +147,14 @@ runParserT' state1 (ParserT k1) =
132
147
Stop s res ->
133
148
pure $ Done (Tuple res s)
134
149
135
- -- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
150
+ -- | The `Parser s` monad, where `s` is the type of the input stream.
151
+ -- |
152
+ -- | A synonym for the `ParserT` monad transformer applied
153
+ -- | to the `Identity` monad.
136
154
type Parser s = ParserT s Identity
137
155
138
- -- | Apply a parser, keeping only the parsed result.
156
+ -- | Run a parser on an input stream `s` and produce either an error or the
157
+ -- | result `a` of the parser.
139
158
runParser :: forall s a . s -> Parser s a -> Either ParseError a
140
159
runParser s = unwrap <<< runParserT s
141
160
@@ -145,7 +164,8 @@ hoistParserT f (ParserT k) = ParserT
145
164
runFn5 k state1 more (lift <<< f) throw done
146
165
)
147
166
148
- -- | Change the underlying monad action and data type in a ParserT monad action.
167
+ -- | Change the underlying monad action `m` and result data type `a` in
168
+ -- | a `ParserT s m` monad action.
149
169
mapParserT
150
170
:: forall b n s a m
151
171
. MonadRec m
@@ -366,3 +386,31 @@ failWithPosition message pos = throwError (ParseError message pos)
366
386
-- | `region` as the parser backs out the call stack.
367
387
region :: forall m s a . (ParseError -> ParseError ) -> ParserT s m a -> ParserT s m a
368
388
region context p = catchError p $ \err -> throwError $ context err
389
+
390
+ -- | `Position` represents the position of the parser in the input stream.
391
+ -- |
392
+ -- | - `index` is the position since the start of the input. Starts at 0.
393
+ -- | - `line` is the current line in the input. Starts at 1.
394
+ -- | - `column` is the column of the next character in the current line that
395
+ -- | will be parsed. Starts at 1.
396
+ newtype Position = Position
397
+ { index :: Int
398
+ , line :: Int
399
+ , column :: Int
400
+ }
401
+
402
+ derive instance Generic Position _
403
+ instance Show Position where
404
+ show x = genericShow x
405
+
406
+ instance Eq Position where
407
+ eq (Position l) (Position r) = l.index == r.index
408
+
409
+ instance Ord Position where
410
+ compare (Position l) (Position r) = compare l.index r.index
411
+
412
+ -- | The `Position` before any input has been parsed.
413
+ -- |
414
+ -- | `{ index: 0, line: 1, column: 1 }`
415
+ initialPos :: Position
416
+ initialPos = Position { index: 0 , line: 1 , column: 1 }
0 commit comments