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.
17module Parsing
2- ( ParseError (..)
3- , parseErrorMessage
4- , parseErrorPosition
5- , ParseState (..)
6- , ParserT (..)
7- , Parser
8+ ( Parser
89 , runParser
10+ , ParserT (..)
911 , runParserT
1012 , runParserT'
11- , hoistParserT
12- , mapParserT
13+ , ParseError (..)
14+ , parseErrorMessage
15+ , parseErrorPosition
16+ , Position (..)
17+ , initialPos
1318 , consume
1419 , position
1520 , fail
1621 , failWithPosition
1722 , region
23+ , ParseState (..)
24+ , hoistParserT
25+ , mapParserT
1826 ) where
1927
2028import Prelude
@@ -29,13 +37,15 @@ import Control.Monad.Trans.Class (class MonadTrans)
2937import Control.MonadPlus (class Alternative , class MonadPlus , class Plus )
3038import Data.Either (Either (..))
3139import Data.Function.Uncurried (Fn2 , Fn5 , mkFn2 , mkFn3 , mkFn5 , runFn2 , runFn3 , runFn5 )
40+ import Data.Generic.Rep (class Generic )
3241import Data.Identity (Identity )
3342import Data.Lazy as Lazy
3443import Data.Newtype (unwrap )
44+ import Data.Show.Generic (genericShow )
3545import Data.Tuple (Tuple (..), fst )
36- import Parsing.Pos (Position , initialPos )
3746
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.
3949data ParseError = ParseError String Position
4050
4151parseErrorMessage :: ParseError -> String
@@ -51,7 +61,13 @@ instance showParseError :: Show ParseError where
5161derive instance eqParseError :: Eq ParseError
5262derive instance ordParseError :: Ord ParseError
5363
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.
5571data ParseState s = ParseState s Position Boolean
5672-- ParseState constructor has three parameters,
5773-- s: the remaining input
@@ -66,10 +82,7 @@ data ParseState s = ParseState s Position Boolean
6682--
6783-- http://blog.ezyang.com/2014/05/parsec-try-a-or-b-considered-harmful/
6884
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`.
7386newtype ParserT s m a = ParserT
7487 -- The parser is implemented using continuation-passing-style with uncurried
7588 -- functions. In addition to the usual error and success continuations, there
@@ -102,13 +115,15 @@ data RunParser s m a
102115 | Lift (m (Unit -> RunParser s m a ))
103116 | Stop (ParseState s ) (Either ParseError a )
104117
105- -- | Apply a parser, keeping only the parsed result .
118+ -- | `runParser` with a monad transfomer parameter `m` .
106119runParserT :: forall m s a . MonadRec m => s -> ParserT s m a -> m (Either ParseError a )
107120runParserT s p = fst <$> runParserT' initialState p
108121 where
109122 initialState :: ParseState s
110123 initialState = ParseState s initialPos false
111124
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.
112127runParserT'
113128 :: forall m s a
114129 . MonadRec m
@@ -132,10 +147,14 @@ runParserT' state1 (ParserT k1) =
132147 Stop s res ->
133148 pure $ Done (Tuple res s)
134149
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.
136154type Parser s = ParserT s Identity
137155
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.
139158runParser :: forall s a . s -> Parser s a -> Either ParseError a
140159runParser s = unwrap <<< runParserT s
141160
@@ -145,7 +164,8 @@ hoistParserT f (ParserT k) = ParserT
145164 runFn5 k state1 more (lift <<< f) throw done
146165 )
147166
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.
149169mapParserT
150170 :: forall b n s a m
151171 . MonadRec m
@@ -366,3 +386,31 @@ failWithPosition message pos = throwError (ParseError message pos)
366386-- | `region` as the parser backs out the call stack.
367387region :: forall m s a . (ParseError -> ParseError ) -> ParserT s m a -> ParserT s m a
368388region 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