Skip to content

Commit da38585

Browse files
authored
Merge pull request #36 from purescript-contrib/0.10
Updates for 0.10
2 parents b4a6402 + 31a1e80 commit da38585

File tree

8 files changed

+207
-183
lines changed

8 files changed

+207
-183
lines changed

LICENSE

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
The MIT License (MIT)
2-
3-
Copyright (c) 2014 PureScript
4-
5-
Permission is hereby granted, free of charge, to any person obtaining a copy of
6-
this software and associated documentation files (the "Software"), to deal in
7-
the Software without restriction, including without limitation the rights to
8-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9-
the Software, and to permit persons to whom the Software is furnished to do so,
10-
subject to the following conditions:
11-
12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
14-
15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1+
Copyright 2014-2016 PureScript
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright notice,
7+
this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above copyright
9+
notice, this list of conditions and the following disclaimer in the
10+
documentation and/or other materials provided with the distribution.
11+
12+
This software is provided by the copyright holders "as is" and any express or
13+
implied warranties, including, but not limited to, the implied warranties of
14+
merchantability and fitness for a particular purpose are disclaimed. In no
15+
event shall the copyright holders be liable for any direct, indirect,
16+
incidental, special, exemplary, or consequential damages (including, but not
17+
limited to, procurement of substitute goods or services; loss of use, data,
18+
or profits; or business interruption) however caused and on any theory of
19+
liability, whether in contract, strict liability, or tort (including
20+
negligence or otherwise) arising in any way out of the use of this software,
21+
even if advised of the possibility of such damage.
2122

2223
-------------------------------------------------------------------------------
2324

bower.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"keywords": [
66
"purescript"
77
],
8-
"license": "MIT",
8+
"license": "BSD3",
99
"repository": {
1010
"type": "git",
1111
"url": "git://github.com/purescript-contrib/purescript-parsing.git"
@@ -20,19 +20,19 @@
2020
"package.json"
2121
],
2222
"dependencies": {
23-
"purescript-arrays": "^1.0.0",
24-
"purescript-either": "^1.0.0",
25-
"purescript-foldable-traversable": "^1.0.0",
26-
"purescript-identity": "^1.0.0",
27-
"purescript-integers": "^1.0.0",
28-
"purescript-lists": "^1.0.0",
29-
"purescript-maybe": "^1.0.0",
30-
"purescript-strings": "^1.0.0",
31-
"purescript-transformers": "^1.0.0",
32-
"purescript-unicode": "^1.0.0"
23+
"purescript-arrays": "^3.0.0",
24+
"purescript-either": "^2.0.0",
25+
"purescript-foldable-traversable": "^2.0.0",
26+
"purescript-identity": "^2.0.0",
27+
"purescript-integers": "^2.0.0",
28+
"purescript-lists": "^2.0.0",
29+
"purescript-maybe": "^2.0.0",
30+
"purescript-strings": "^2.0.0",
31+
"purescript-transformers": "^2.0.0",
32+
"purescript-unicode": "^2.0.0"
3333
},
3434
"devDependencies": {
35-
"purescript-assert": "^1.0.0",
36-
"purescript-console": "^1.0.0"
35+
"purescript-assert": "^2.0.0",
36+
"purescript-console": "^2.0.0"
3737
}
3838
}

src/Text/Parsing/Parser.purs

Lines changed: 63 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,107 @@
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
212

313
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)
1021
import Data.Either (Either(..))
11-
import Data.Identity (Identity, runIdentity)
22+
import Data.Identity (Identity)
23+
import Data.Newtype (class Newtype, unwrap)
1224
import Data.Tuple (Tuple(..))
1325
import Text.Parsing.Parser.Pos (Position, initialPos)
1426

1527
-- | 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
2035

2136
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 <> ")"
2339

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
2642

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
3245

3346
-- | The Parser monad transformer.
3447
-- |
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)
3751

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) _
4153

4254
-- | 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
4758

4859
-- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
4960
type Parser s a = ParserT s Identity a
5061

5162
-- | Apply a parser, keeping only the parsed result.
5263
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
5465

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)))
6268

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)
6577

6678
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')
7185

7286
instance plusParserT :: Monad m => Plus (ParserT s m) where
7387
empty = fail "No alternative"
7488

7589
instance alternativeParserT :: Monad m => Alternative (ParserT s m)
7690

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-
8791
instance monadZeroParserT :: Monad m => MonadZero (ParserT s m)
8892

8993
instance monadPlusParserT :: Monad m => MonadPlus (ParserT s m)
9094

9195
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
10197

10298
-- | Set the consumed flag.
10399
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
105102

106103
-- | Fail with a message.
107104
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)

src/Text/Parsing/Parser/Combinators.purs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
-- | Combinators for creating parsers.
22
-- |
3-
-- | ### Notes:
3+
-- | ### Notes
4+
-- |
45
-- | A few of the known combinators from Parsec are missing in this module. That
56
-- | is because they have already been defined in other libraries.
67
-- |
@@ -16,19 +17,20 @@
1617
-- | ```purescript
1718
-- | Text.Parsec.many (char 'x') <=> fromCharArray <$> Data.Array.many (char 'x')
1819
-- | ```
19-
-- |
20-
-- | ===
2120

2221
module Text.Parsing.Parser.Combinators where
2322

24-
import Prelude (class Functor, class Monad, Unit, ($), (*>), (<>), (<$>), bind, flip, pure, unit)
25-
23+
import Prelude
24+
import Control.Monad.Except (runExceptT, ExceptT(..))
25+
import Control.Monad.State (StateT(..), runStateT)
2626
import Control.Plus (empty, (<|>))
2727
import Data.Either (Either(..))
2828
import Data.Foldable (class Foldable, foldl)
2929
import Data.List (List(..), (:), many, some, singleton)
3030
import Data.Maybe (Maybe(..))
31-
import Text.Parsing.Parser (PState(..), ParserT(..), fail, unParserT)
31+
import Data.Newtype (unwrap)
32+
import Data.Tuple (Tuple(..))
33+
import Text.Parsing.Parser (ParseState(..), ParserT(..), fail)
3234

3335
-- | Provide an error message in the case of failure.
3436
withErrorMessage :: forall m s a. Monad m => ParserT s m a -> String -> ParserT s m a
@@ -70,11 +72,18 @@ optionMaybe :: forall m s a. Monad m => ParserT s m a -> ParserT s m (Maybe a)
7072
optionMaybe p = option Nothing (Just <$> p)
7173

7274
-- | In case of failure, reset the stream to the unconsumed state.
73-
try :: forall m s a. (Functor m) => ParserT s m a -> ParserT s m a
74-
try p = ParserT $ \(PState { input: s, position: pos }) -> try' s pos <$> unParserT p (PState { input: s, position: pos })
75-
where
76-
try' s pos o@{ result: Left _ } = { input: s, result: o.result, consumed: false, position: pos }
77-
try' _ _ o = o
75+
try :: forall m s a. Monad m => ParserT s m a -> ParserT s m a
76+
try p = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState _ _ consumed)) -> do
77+
Tuple e s'@(ParseState input position _) <- runStateT (runExceptT (unwrap p)) s
78+
case e of
79+
Left _ -> pure (Tuple e (ParseState input position consumed))
80+
_ -> pure (Tuple e s')
81+
82+
-- | Parse a phrase, without modifying the consumed state or stream position.
83+
lookAhead :: forall s a m. Monad m => ParserT s m a -> ParserT s m a
84+
lookAhead p = (ParserT <<< ExceptT <<< StateT) \s -> do
85+
Tuple e _ <- runStateT (runExceptT (unwrap p)) s
86+
pure (Tuple e s)
7887

7988
-- | Parse phrases delimited by a separator.
8089
-- |
@@ -172,12 +181,6 @@ skipMany1 p = do
172181
xs <- skipMany p
173182
pure unit
174183

175-
-- | Parse a phrase, without modifying the consumed state or stream position.
176-
lookAhead :: forall s a m. Monad m => ParserT s m a -> ParserT s m a
177-
lookAhead (ParserT p) = ParserT \(PState { input: s, position: pos }) -> do
178-
state <- p (PState { input: s, position: pos })
179-
pure state{input = s, consumed = false, position = pos}
180-
181184
-- | Fail if the specified parser matches.
182185
notFollowedBy :: forall s a m. Monad m => ParserT s m a -> ParserT s m Unit
183186
notFollowedBy p = try $ (try p *> fail "Negated parser succeeded") <|> pure unit

src/Text/Parsing/Parser/Pos.purs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
module Text.Parsing.Parser.Pos where
22

33
import Prelude
4-
5-
import Data.String (split)
64
import Data.Foldable (foldl)
5+
import Data.Newtype (wrap)
6+
import Data.String (split)
77

88
-- | `Position` represents the position of the parser in the input.
99
-- |
1010
-- | - `line` is the current line in the input
1111
-- | - `column` is the column of the next character in the current line that will be parsed
12-
data Position = Position
12+
newtype Position = Position
1313
{ line :: Int
1414
, column :: Int
1515
}
@@ -18,17 +18,16 @@ instance showPosition :: Show Position where
1818
show (Position { line: line, column: column }) =
1919
"Position { line: " <> show line <> ", column: " <> show column <> " }"
2020

21-
instance eqPosition :: Eq Position where
22-
eq (Position { line: l1, column: c1 }) (Position { line: l2, column: c2 }) =
23-
l1 == l2 && c1 == c2
21+
derive instance eqPosition :: Eq Position
22+
derive instance ordPosition :: Ord Position
2423

2524
-- | The `Position` before any input has been parsed.
2625
initialPos :: Position
2726
initialPos = Position { line: 1, column: 1 }
2827

2928
-- | Updates a `Position` by adding the columns and lines in `String`.
3029
updatePosString :: Position -> String -> Position
31-
updatePosString pos str = foldl updatePosChar pos (split "" str)
30+
updatePosString pos str = foldl updatePosChar pos (split (wrap "") str)
3231
where
3332
updatePosChar (Position pos) c = case c of
3433
"\n" -> Position { line: pos.line + 1, column: 1 }

0 commit comments

Comments
 (0)