Skip to content

Commit e0ba8a5

Browse files
committed
updates for 0.10
1 parent b4a6402 commit e0ba8a5

File tree

8 files changed

+187
-161
lines changed

8 files changed

+187
-161
lines changed

.gitignore

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
/.*
2-
!/.gitignore
3-
!/.jscsrc
4-
!/.jshintrc
5-
!/.travis.yml
6-
/bower_components/
7-
/node_modules/
8-
/output/
1+
.psci*
2+
bower_components/
3+
output/
4+
.psc-package
5+
.psc-ide-port
6+
.psa-stash

bower.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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": "6d9a4ab9d239da4cecb33283994cce56350bbe87"
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: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,104 @@
1-
module Text.Parsing.Parser where
1+
module Text.Parsing.Parser
2+
( ParseError(..)
3+
, ParseState(..)
4+
, ParserT(..)
5+
, Parser
6+
, runParser
7+
, consume
8+
, fail
9+
) where
210

311
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)
12+
import Control.Alt (class Alt)
13+
import Control.Lazy (defer, class Lazy)
14+
import Control.Monad.Except (class MonadError, ExceptT(..), throwError, runExceptT)
15+
import Control.Monad.Rec.Class (class MonadRec)
16+
import Control.Monad.State (runStateT, class MonadState, StateT(..), gets, evalStateT, modify)
17+
import Control.Monad.Trans.Class (lift, class MonadTrans)
18+
import Control.MonadPlus (class Alternative, class MonadZero, class MonadPlus, class Plus)
1019
import Data.Either (Either(..))
11-
import Data.Identity (Identity, runIdentity)
20+
import Data.Identity (Identity)
21+
import Data.Newtype (class Newtype, unwrap)
1222
import Data.Tuple (Tuple(..))
1323
import Text.Parsing.Parser.Pos (Position, initialPos)
1424

1525
-- | A parsing error, consisting of a message and position information.
16-
data ParseError = ParseError
26+
newtype ParseError = ParseError
1727
{ message :: String
1828
, position :: Position
1929
}
2030

2131
instance showParseError :: Show ParseError where
2232
show (ParseError msg) = "ParseError { message: " <> msg.message <> ", position: " <> show msg.position <> " }"
2333

24-
instance eqParseError :: Eq ParseError where
25-
eq (ParseError {message : m1, position : p1}) (ParseError {message : m2, position : p2}) = m1 == m2 && p1 == p2
34+
derive instance eqParseError :: Eq ParseError
2635

2736
-- | `PState` contains the remaining input and current position.
28-
data PState s = PState
37+
newtype ParseState s = ParseState
2938
{ input :: s
3039
, position :: Position
40+
, consumed :: Boolean
3141
}
3242

3343
-- | The Parser monad transformer.
3444
-- |
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 })
45+
-- | The first type argument is the stream type. Typically, this is either `String`,
46+
-- | or some sort of token stream.
47+
newtype ParserT s m a = ParserT (ExceptT ParseError (StateT (ParseState s) m) a)
3748

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
49+
derive instance newtypeParserT :: Newtype (ParserT s m a) _
4150

4251
-- | 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
52+
runParserT :: forall m s a. Monad m => s -> ParserT s m a -> m (Either ParseError a)
53+
runParserT s p = evalStateT (runExceptT (unwrap p)) initialState where
54+
initialState = ParseState { input: s, position: initialPos, consumed: false }
4755

4856
-- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
4957
type Parser s a = ParserT s Identity a
5058

5159
-- | Apply a parser, keeping only the parsed result.
5260
runParser :: forall s a. s -> Parser s a -> Either ParseError a
53-
runParser s = runIdentity <<< runParserT (PState { input: s, position: initialPos })
54-
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 }
61+
runParser s = unwrap <<< runParserT s
5962

60-
instance applyParserT :: Monad m => Apply (ParserT s m) where
61-
apply = ap
63+
instance lazyParserT :: Lazy (ParserT s m a) where
64+
defer f = ParserT (ExceptT (defer (runExceptT <<< unwrap <<< f)))
6265

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 }
66+
derive newtype instance functorParserT :: Functor m => Functor (ParserT s m)
67+
derive newtype instance applyParserT :: Monad m => Apply (ParserT s m)
68+
derive newtype instance applicativeParserT :: Monad m => Applicative (ParserT s m)
69+
derive newtype instance bindParserT :: Monad m => Bind (ParserT s m)
70+
derive newtype instance monadParserT :: Monad m => Monad (ParserT s m)
71+
derive newtype instance monadRecParserT :: MonadRec m => MonadRec (ParserT s m)
72+
derive newtype instance monadStateParserT :: Monad m => MonadState (ParseState s) (ParserT s m)
73+
derive newtype instance monadErrorParserT :: Monad m => MonadError ParseError (ParserT s m)
6574

6675
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
76+
alt p1 p2 = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState { input, position })) -> do
77+
Tuple e (ParseState s') <- runStateT (runExceptT (unwrap p1)) (ParseState { input, position, consumed: false })
78+
case e of
79+
Left err
80+
| not s'.consumed -> runStateT (runExceptT (unwrap p2)) s
81+
_ -> pure (Tuple e (ParseState s'))
7182

7283
instance plusParserT :: Monad m => Plus (ParserT s m) where
7384
empty = fail "No alternative"
7485

7586
instance alternativeParserT :: Monad m => Alternative (ParserT s m)
7687

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

8990
instance monadPlusParserT :: Monad m => MonadPlus (ParserT s m)
9091

9192
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
93+
lift = ParserT <<< lift <<< lift
10194

10295
-- | Set the consumed flag.
10396
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 }
97+
consume = modify \(ParseState { input, position }) ->
98+
ParseState { input, position, consumed: true }
10599

106100
-- | Fail with a message.
107101
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 }
102+
fail message = do
103+
position <- gets \(ParseState s) -> s.position
104+
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)