git.iko.soy/rowtype-yoga/purescript-parsing-dataview
on master help sign in
Remove all purescript-parsing
commit2f2ea9693481f291a75c915956d1997e4317aee4 authorJames Brock <jamesbrock@gmail.com> dateWed 26 Feb 2020, 11:01 (7 years ago) parent075049d
13 files changed+76−2265
LICENSE+26 README.md+14−33 bower.json+5−14 psc-package.json+3−13 src/Text/Parsing/Parser.purs−138 src/Text/Parsing/Parser/Combinators.purs−200 src/Text/Parsing/Parser/Expr.purs−107 src/Text/Parsing/Parser/Indent.purs−219 src/Text/Parsing/Parser/Language.purs−118 src/Text/Parsing/Parser/Pos.purs−36 src/Text/Parsing/Parser/String.purs−92 src/Text/Parsing/Parser/Token.purs−809 test/Main.purs+28−486
LICENSE+26
@@ -1,3 +1,29 @@
1+Copyright 2020 James Dawson Brock
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.
22+
23+This library is based on purescript-parsing, copyright follows.
24+
25+--------------------------------------------------------------------------------
26+
127Copyright 2014-2016 PureScript
228
329Redistribution and use in source and binary forms, with or without
README.md+14−33
@@ -1,47 +1,28 @@
11# purescript-parsing
22
3−[![Latest release](http://img.shields.io/github/release/purescript-contrib/purescript-parsing.svg)](https://github.com/purescript-contrib/purescript-parsing/releases)
4−[![Build status](https://travis-ci.org/purescript-contrib/purescript-parsing.svg?branch=master)](https://travis-ci.org/purescript-contrib/purescript-parsing)
5−[![Pursuit](http://pursuit.purescript.org/packages/purescript-parsing/badge)](http://pursuit.purescript.org/packages/purescript-parsing/)
6−[![Maintainer: garyb](https://img.shields.io/badge/maintainer-garyb-lightgrey.svg)](http://github.com/garyb)
7−[![Maintainer: thomashoneyman](https://img.shields.io/badge/maintainer-thomashoneyman-lightgrey.svg)](http://github.com/thomashoneyman)
3+[![Build status](https://travis-ci.org/jamesdbrock/purescript-parsing-dataview.svg?branch=master)](https://travis-ci.org/jamesdbrock/purescript-parsing-dataview)
4+[![Pursuit](http://pursuit.purescript.org/packages/purescript-parsing-dataview/badge)](http://pursuit.purescript.org/packages/purescript-parsing-dataview/)
85
9−-- | Primitive parsers for parsing Javascript ArrayBuffers with the
10−-- | `Text.Parsing.Parser` module in package __purescript-parsing__.
11−-- |
12−-- | This module brings __purescript-parsing__ into rough feature parity
13−-- | with __Megaparsec__:
14−-- |
15−-- | | Built-in stream support | purescript-parsing | Megaparsec |
16−-- | |----|-----|----|
17−-- | | UTF-16 strings | String | Text |
18−-- | | Listy strings | Token | String |
19−-- | | Binary blobs | __DataView__ | Bytestring |
6+The module `Text.Parsing.Parser.DataView` provides primitive parsers for parsing
7+DataViews on Javascript ArrayBuffers with the package
8+[__purescript-parsing__](https://github.com/purescript-contrib/purescript-parsing).
209
21−A parser combinator library based on Haskell's Parsec.
10+This module brings __purescript-parsing__ into rough feature parity
11+with __Megaparsec__:
2212
23−## Parsers
24−
25−There are three sets of parsing primitives included in this library.
26−
27−* `Text.Parsing.Parser.String` module for native `String` parsing.
28−* `Text.Parsing.Parser.Token` module for parsing `List`s of any type of token.
29−* `Text.Parsing.Parser.DataView` module for parsing native Javascript `ArrayBuffer`.
30−
31−All parsing primitives are “auto-backtracking”, meaning that if they fail,
32−then they consume no input.
13+| Built-in stream support | purescript-parsing | Megaparsec |
14+|----|-----|----|
15+| UTF-16 strings | String | Text |
16+| Listy strings | Token | String |
17+| Binary blobs | __DataView__ | Bytestring |
3318
3419## Installation
3520
3621```
37−bower install purescript-parsing
22+bower install purescript-parsing-dataview
3823```
3924
4025## Documentation
4126
4227- [See the tests](test/Main.purs) for some example usages.
43−- Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-parsing).
44−
45−## Contributing
46−
47−Read the [contribution guidelines](https://github.com/purescript-contrib/purescript-parsing/blob/master/.github/contributing.md) to get started and see helpful related resources.
28+- Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-parsing-dataview).
bower.json+5−14
@@ -1,14 +1,14 @@
11{
2− "name": "purescript-parsing",
3− "homepage": "https://github.com/purescript-contrib/purescript-parsing",
4− "description": "Parser combinator library",
2+ "name": "purescript-parsing-dataview",
3+ "homepage": "https://github.com/jamesdbrock/purescript-parsing-dataview",
4+ "description": "ArrayBuffer DataView input stream support for purescript-parsing",
55 "keywords": [
66 "purescript"
77 ],
88 "license": "BSD-3-Clause",
99 "repository": {
1010 "type": "git",
11− "url": "git://github.com/purescript-contrib/purescript-parsing.git"
11+ "url": "git://github.com/jamesdbrock/purescript-parsing-dataview.git"
1212 },
1313 "ignore": [
1414 "**/.*",
@@ -20,16 +20,7 @@
2020 "package.json"
2121 ],
2222 "dependencies": {
23− "purescript-arrays": "^5.0.0",
24− "purescript-either": "^4.0.0",
25− "purescript-foldable-traversable": "^4.0.0",
26− "purescript-identity": "^4.0.0",
27− "purescript-integers": "^4.0.0",
28− "purescript-lists": "^5.0.0",
29− "purescript-maybe": "^4.0.0",
30− "purescript-strings": "^4.0.0",
31− "purescript-transformers": "^4.1.0",
32− "purescript-unicode": "^4.0.0",
23+ "purescript-parsing": "^5.0.0",
3324 "purescript-arraybuffer": "^10.0.0"
3425 },
3526 "devDependencies": {
psc-package.json+3−13
@@ -1,19 +1,9 @@
11{
2− "name": "purescript-parsing",
2+ "name": "purescript-parsing-dataview",
33 "set": "psc-0.12.0",
44 "source": "https://github.com/purescript/package-sets.git",
55 "depends": [
6− "arrays",
7− "either",
8− "foldable-traversable",
9− "identity",
10− "integers",
11− "lists",
12− "maybe",
13− "prelude",
14− "psci-support",
15− "strings",
16− "transformers",
17− "unicode"
6+ "parsing",
7+ "arraybuffers"
188 ]
199}
src/Text/Parsing/Parser.pursdeleted−138
@@ -1,138 +0,0 @@
1−module Text.Parsing.Parser
2− ( ParseError(..)
3− , parseErrorMessage
4− , parseErrorPosition
5− , ParseState(..)
6− , ParserT(..)
7− , Parser
8− , runParser
9− , runParserT
10− , hoistParserT
11− , mapParserT
12− , consume
13− , position
14− , fail
15− , failWithPosition
16− ) where
17−
18−import Prelude
19−
20−import Control.Alt (class Alt)
21−import Control.Apply (lift2)
22−import Control.Lazy (defer, class Lazy)
23−import Control.Monad.Error.Class (class MonadThrow, throwError)
24−import Control.Monad.Except (class MonadError, ExceptT(..), runExceptT, mapExceptT)
25−import Control.Monad.Rec.Class (class MonadRec)
26−import Control.Monad.State (class MonadState, StateT(..), evalStateT, gets, mapStateT, modify_, runStateT)
27−import Control.Monad.Trans.Class (class MonadTrans, lift)
28−import Control.MonadPlus (class Alternative, class MonadZero, class MonadPlus, class Plus)
29−import Data.Either (Either(..))
30−import Data.Identity (Identity)
31−import Data.Newtype (class Newtype, unwrap, over)
32−import Data.Tuple (Tuple(..))
33−import Text.Parsing.Parser.Pos (Position, initialPos)
34−
35−-- | A parsing error, consisting of a message and position information.
36−data ParseError = ParseError String Position
37−
38−parseErrorMessage :: ParseError -> String
39−parseErrorMessage (ParseError msg _) = msg
40−
41−parseErrorPosition :: ParseError -> Position
42−parseErrorPosition (ParseError _ pos) = pos
43−
44−instance showParseError :: Show ParseError where
45− show (ParseError msg pos) =
46− "(ParseError " <> show msg <> " " <> show pos <> ")"
47−
48−derive instance eqParseError :: Eq ParseError
49−derive instance ordParseError :: Ord ParseError
50−
51−-- | Contains the remaining input and current position.
52−data ParseState s = ParseState s Position Boolean
53−
54−-- | The Parser monad transformer.
55−-- |
56−-- | The first type argument is the stream type. Typically, this is either `String`,
57−-- | or some sort of token stream.
58−newtype ParserT s m a = ParserT (ExceptT ParseError (StateT (ParseState s) m) a)
59−
60−derive instance newtypeParserT :: Newtype (ParserT s m a) _
61−
62−-- | Apply a parser, keeping only the parsed result.
63−runParserT :: forall m s a. Monad m => s -> ParserT s m a -> m (Either ParseError a)
64−runParserT s p = evalStateT (runExceptT (unwrap p)) initialState where
65− initialState = ParseState s initialPos false
66−
67−-- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
68−type Parser s = ParserT s Identity
69−
70−-- | Apply a parser, keeping only the parsed result.
71−runParser :: forall s a. s -> Parser s a -> Either ParseError a
72−runParser s = unwrap <<< runParserT s
73−
74−hoistParserT :: forall s m n a. (m ~> n) -> ParserT s m a -> ParserT s n a
75−hoistParserT = mapParserT
76−
77−-- | Change the underlying monad action and data type in a ParserT monad action.
78−mapParserT :: forall b n s a m.
79− ( m (Tuple (Either ParseError a) (ParseState s))
80− -> n (Tuple (Either ParseError b) (ParseState s))
81− ) -> ParserT s m a -> ParserT s n b
82−mapParserT = over ParserT <<< mapExceptT <<< mapStateT
83−
84−instance lazyParserT :: Lazy (ParserT s m a) where
85− defer f = ParserT (ExceptT (defer (runExceptT <<< unwrap <<< f)))
86−
87−instance semigroupParserT :: (Monad m, Semigroup a) => Semigroup (ParserT s m a) where
88− append = lift2 (<>)
89−
90−instance monoidParserT :: (Monad m, Monoid a) => Monoid (ParserT s m a) where
91− mempty = pure mempty
92−
93−derive newtype instance functorParserT :: Functor m => Functor (ParserT s m)
94−derive newtype instance applyParserT :: Monad m => Apply (ParserT s m)
95−derive newtype instance applicativeParserT :: Monad m => Applicative (ParserT s m)
96−derive newtype instance bindParserT :: Monad m => Bind (ParserT s m)
97−derive newtype instance monadParserT :: Monad m => Monad (ParserT s m)
98−derive newtype instance monadRecParserT :: MonadRec m => MonadRec (ParserT s m)
99−derive newtype instance monadStateParserT :: Monad m => MonadState (ParseState s) (ParserT s m)
100−derive newtype instance monadThrowParserT :: Monad m => MonadThrow ParseError (ParserT s m)
101−derive newtype instance monadErrorParserT :: Monad m => MonadError ParseError (ParserT s m)
102−
103−instance altParserT :: Monad m => Alt (ParserT s m) where
104− alt p1 p2 = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState i p _)) -> do
105− Tuple e s'@(ParseState i' p' c') <- runStateT (runExceptT (unwrap p1)) (ParseState i p false)
106− case e of
107− Left err
108− | not c' -> runStateT (runExceptT (unwrap p2)) s
109− _ -> pure (Tuple e s')
110−
111−instance plusParserT :: Monad m => Plus (ParserT s m) where
112− empty = fail "No alternative"
113−
114−instance alternativeParserT :: Monad m => Alternative (ParserT s m)
115−
116−instance monadZeroParserT :: Monad m => MonadZero (ParserT s m)
117−
118−instance monadPlusParserT :: Monad m => MonadPlus (ParserT s m)
119−
120−instance monadTransParserT :: MonadTrans (ParserT s) where
121− lift = ParserT <<< lift <<< lift
122−
123−-- | Set the consumed flag.
124−consume :: forall s m. Monad m => ParserT s m Unit
125−consume = modify_ \(ParseState input pos _) ->
126− ParseState input pos true
127−
128−-- | Returns the current position in the stream.
129−position :: forall s m. Monad m => ParserT s m Position
130−position = gets \(ParseState _ pos _) -> pos
131−
132−-- | Fail with a message.
133−fail :: forall m s a. Monad m => String -> ParserT s m a
134−fail message = failWithPosition message =<< position
135−
136−-- | Fail with a message and a position.
137−failWithPosition :: forall m s a. Monad m => String -> Position -> ParserT s m a
138−failWithPosition message pos = throwError (ParseError message pos)
src/Text/Parsing/Parser/Combinators.pursdeleted−200
@@ -1,200 +0,0 @@
1−-- | Combinators for creating parsers.
2−-- |
3−-- | ### Notes
4−-- |
5−-- | A few of the known combinators from Parsec are missing in this module. That
6−-- | is because they have already been defined in other libraries.
7−-- |
8−-- | ```purescript
9−-- | Text.Parsec.many = Data.(Array|List).many
10−-- | Text.Parsec.many1 = Data.(Array|List).some
11−-- | Text.Parsec.(<|>) = Control.Alt.alt (<|>)
12−-- | ```
13−-- |
14−-- | Because Strings are not Char Arrays in PureScript `many` and `some` on Char Parsers need to
15−-- | be used in conjunction with `Data.String.CodeUnits.fromCharArray` to achieve "Parsec-like" results.
16−-- |
17−-- | ```purescript
18−-- | Text.Parsec.many (char 'x') <=> fromCharArray <$> Data.Array.many (char 'x')
19−-- | ```
20−-- |
21−-- | Note that `Data.(Array|List).(many|some)` are not stack safe. If you need to parse
22−-- | large numbers of items then consider using `Data.List.(manyRec|someRec)` instead.
23−
24−module Text.Parsing.Parser.Combinators where
25−
26−import Prelude
27−import Control.Monad.Except (runExceptT, ExceptT(..))
28−import Control.Monad.State (StateT(..), runStateT)
29−import Control.Plus (empty, (<|>))
30−import Data.Either (Either(..))
31−import Data.Foldable (class Foldable, foldl)
32−import Data.List (List(..), (:), many, some, singleton)
33−import Data.Maybe (Maybe(..))
34−import Data.Newtype (unwrap)
35−import Data.Tuple (Tuple(..))
36−import Text.Parsing.Parser (ParseState(..), ParserT(..), ParseError(..), fail)
37−
38−-- | Provide an error message in the case of failure.
39−withErrorMessage :: forall m s a. Monad m => ParserT s m a -> String -> ParserT s m a
40−withErrorMessage p msg = p <|> fail ("Expected " <> msg)
41−
42−infixl 3 withErrorMessage as <?>
43−
44−-- | Flipped `(<?>)`.
45−asErrorMessage :: forall m s a. Monad m => String -> ParserT s m a -> ParserT s m a
46−asErrorMessage = flip (<?>)
47−
48−infixl 3 asErrorMessage as <??>
49−
50−-- | Wrap a parser with opening and closing markers.
51−-- |
52−-- | For example:
53−-- |
54−-- | ```purescript
55−-- | parens = between (string "(") (string ")")
56−-- | ```
57−between :: forall m s a open close. Monad m => ParserT s m open -> ParserT s m close -> ParserT s m a -> ParserT s m a
58−between open close p = open *> p <* close
59−
60−-- | Provide a default result in the case where a parser fails without consuming input.
61−option :: forall m s a. Monad m => a -> ParserT s m a -> ParserT s m a
62−option a p = p <|> pure a
63−
64−-- | Optionally parse something, failing quietly.
65−optional :: forall m s a. Monad m => ParserT s m a -> ParserT s m Unit
66−optional p = void p <|> pure unit
67−
68−-- | pure `Nothing` in the case where a parser fails without consuming input.
69−optionMaybe :: forall m s a. Monad m => ParserT s m a -> ParserT s m (Maybe a)
70−optionMaybe p = option Nothing (Just <$> p)
71−
72−-- | In case of failure, reset the stream to the unconsumed state.
73−try :: forall m s a. Monad m => ParserT s m a -> ParserT s m a
74−try p = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState _ _ consumed)) -> do
75− Tuple e s'@(ParseState input position _) <- runStateT (runExceptT (unwrap p)) s
76− case e of
77− Left _ -> pure (Tuple e (ParseState input position consumed))
78− _ -> pure (Tuple e s')
79−
80−-- | Like `try`, but will reannotate the error location to the `try` point.
81−tryRethrow :: forall m s a. Monad m => ParserT s m a -> ParserT s m a
82−tryRethrow p = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState _ position consumed)) -> do
83− Tuple e s'@(ParseState input' position' _) <- runStateT (runExceptT (unwrap p)) s
84− case e of
85− Left (ParseError err _) -> pure (Tuple (Left (ParseError err position)) (ParseState input' position' consumed))
86− _ -> pure (Tuple e s')
87−
88−-- | Parse a phrase, without modifying the consumed state or stream position.
89−lookAhead :: forall s a m. Monad m => ParserT s m a -> ParserT s m a
90−lookAhead p = (ParserT <<< ExceptT <<< StateT) \s -> do
91− Tuple e _ <- runStateT (runExceptT (unwrap p)) s
92− pure (Tuple e s)
93−
94−-- | Parse phrases delimited by a separator.
95−-- |
96−-- | For example:
97−-- |
98−-- | ```purescript
99−-- | digit `sepBy` string ","
100−-- | ```
101−sepBy :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
102−sepBy p sep = sepBy1 p sep <|> pure Nil
103−
104−-- | Parse phrases delimited by a separator, requiring at least one match.
105−sepBy1 :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
106−sepBy1 p sep = do
107− a <- p
108− as <- many $ sep *> p
109− pure (a : as)
110−
111−-- | Parse phrases delimited and optionally terminated by a separator.
112−sepEndBy :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
113−sepEndBy p sep = sepEndBy1 p sep <|> pure Nil
114−
115−-- | Parse phrases delimited and optionally terminated by a separator, requiring at least one match.
116−sepEndBy1 :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
117−sepEndBy1 p sep = do
118− a <- p
119− (do _ <- sep
120− as <- sepEndBy p sep
121− pure (a : as)) <|> pure (singleton a)
122−
123−-- | Parse phrases delimited and terminated by a separator, requiring at least one match.
124−endBy1 :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
125−endBy1 p sep = some $ p <* sep
126−
127−-- | Parse phrases delimited and terminated by a separator.
128−endBy :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
129−endBy p sep = many $ p <* sep
130−
131−-- | Parse phrases delimited by a right-associative operator.
132−-- |
133−-- | For example:
134−-- |
135−-- | ```purescript
136−-- | chainr digit (string "+" *> add) 0
137−-- | ```
138−chainr :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
139−chainr p f a = chainr1 p f <|> pure a
140−
141−-- | Parse phrases delimited by a left-associative operator.
142−chainl :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
143−chainl p f a = chainl1 p f <|> pure a
144−
145−-- | Parse phrases delimited by a left-associative operator, requiring at least one match.
146−chainl1 :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
147−chainl1 p f = do
148− a <- p
149− chainl1' p f a
150−
151−chainl1' :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
152−chainl1' p f a = (do f' <- f
153− a' <- p
154− chainl1' p f (f' a a')) <|> pure a
155−
156−-- | Parse phrases delimited by a right-associative operator, requiring at least one match.
157−chainr1 :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
158−chainr1 p f = do
159− a <- p
160− chainr1' p f a
161−
162−chainr1' :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
163−chainr1' p f a = (do f' <- f
164− a' <- chainr1 p f
165− pure $ f' a a') <|> pure a
166−
167−-- | Parse one of a set of alternatives.
168−choice :: forall f m s a. Foldable f => Monad m => f (ParserT s m a) -> ParserT s m a
169−choice = foldl (<|>) empty
170−
171−-- | Skip many instances of a phrase.
172−skipMany :: forall s a m. Monad m => ParserT s m a -> ParserT s m Unit
173−skipMany p = skipMany1 p <|> pure unit
174−
175−-- | Skip at least one instance of a phrase.
176−skipMany1 :: forall s a m. Monad m => ParserT s m a -> ParserT s m Unit
177−skipMany1 p = do
178− x <- p
179− xs <- skipMany p
180− pure unit
181−
182−-- | Fail if the specified parser matches.
183−notFollowedBy :: forall s a m. Monad m => ParserT s m a -> ParserT s m Unit
184−notFollowedBy p = try $ (try p *> fail "Negated parser succeeded") <|> pure unit
185−
186−-- | Parse several phrases until the specified terminator matches.
187−manyTill :: forall s a m e. Monad m => ParserT s m a -> ParserT s m e -> ParserT s m (List a)
188−manyTill p end = scan
189− where
190− scan = (end $> Nil)
191− <|> do x <- p
192− xs <- scan
193− pure (x:xs)
194−
195−-- | Parse several phrases until the specified terminator matches, requiring at least one match.
196−many1Till :: forall s a m e. Monad m => ParserT s m a -> ParserT s m e -> ParserT s m (List a)
197−many1Till p end = do
198− x <- p
199− xs <- manyTill p end
200− pure (x:xs)
src/Text/Parsing/Parser/Expr.pursdeleted−107
@@ -1,107 +0,0 @@
1−module Text.Parsing.Parser.Expr
2− ( Assoc(..)
3− , Operator(..)
4− , OperatorTable()
5− , buildExprParser
6− ) where
7−
8−import Prelude hiding (between)
9−
10−import Control.Alt ((<|>))
11−import Data.Foldable (foldr, foldl)
12−import Data.List (List(..), (:))
13−import Text.Parsing.Parser (ParserT)
14−import Text.Parsing.Parser.Combinators (choice, (<?>))
15−
16−data Assoc = AssocNone | AssocLeft | AssocRight
17−
18−data Operator m s a = Infix (ParserT s m (a -> a -> a)) Assoc
19− | Prefix (ParserT s m (a -> a))
20− | Postfix (ParserT s m (a -> a))
21−
22−type OperatorTable m s a = Array (Array (Operator m s a))
23−
24−type SplitAccum m s a = { rassoc :: List (ParserT s m (a -> a -> a))
25− , lassoc :: List (ParserT s m (a -> a -> a))
26− , nassoc :: List (ParserT s m (a -> a -> a))
27− , prefix :: List (ParserT s m (a -> a))
28− , postfix :: List (ParserT s m (a -> a)) }
29−
30−-- | Build a parser from an `OperatorTable`.
31−-- |
32−-- | For example:
33−-- |
34−-- | ```purescript
35−-- | buildExprParser [ [ Infix (string "/" $> div) AssocRight ]
36−-- | , [ Infix (string "*" $> mul) AssocRight ]
37−-- | , [ Infix (string "-" $> sub) AssocRight ]
38−-- | , [ Infix (string "+" $> add) AssocRight ]
39−-- | ] digit
40−-- | ```
41−buildExprParser :: forall m s a. Monad m => OperatorTable m s a -> ParserT s m a -> ParserT s m a
42−buildExprParser operators simpleExpr = foldl makeParser simpleExpr operators
43−
44−makeParser :: forall m s a. Monad m => ParserT s m a -> Array (Operator m s a) -> ParserT s m a
45−makeParser term ops = do
46− x <- termP prefixP term postfixP
47− rassocP x rassocOp prefixP term postfixP
48− <|> lassocP x lassocOp prefixP term postfixP
49− <|> nassocP x nassocOp prefixP term postfixP
50− <|> pure x
51− <?> "operator"
52− where
53− accum = foldr splitOp { rassoc: Nil
54− , lassoc: Nil
55− , nassoc: Nil
56− , prefix: Nil
57− , postfix: Nil
58− } ops
59−
60− rassocOp = choice accum.rassoc
61− lassocOp = choice accum.lassoc
62− nassocOp = choice accum.nassoc
63− prefixOp = choice accum.prefix <?> ""
64− postfixOp = choice accum.postfix <?> ""
65−
66− postfixP = postfixOp <|> pure identity
67− prefixP = prefixOp <|> pure identity
68−
69−splitOp :: forall m s a. Operator m s a -> SplitAccum m s a -> SplitAccum m s a
70−splitOp (Infix op AssocNone) accum = accum { nassoc = op : accum.nassoc }
71−splitOp (Infix op AssocLeft) accum = accum { lassoc = op : accum.lassoc }
72−splitOp (Infix op AssocRight) accum = accum { rassoc = op : accum.rassoc }
73−splitOp (Prefix op) accum = accum { prefix = op : accum.prefix }
74−splitOp (Postfix op) accum = accum { postfix = op : accum.postfix }
75−
76−rassocP :: forall m a b c s. Monad m => a -> ParserT s m (a -> a -> a) -> ParserT s m (b -> c) -> ParserT s m b -> ParserT s m (c -> a) -> ParserT s m a
77−rassocP x rassocOp prefixP term postfixP = do
78− f <- rassocOp
79− y <- do
80− z <- termP prefixP term postfixP
81− rassocP1 z rassocOp prefixP term postfixP
82− pure (f x y)
83−
84−rassocP1 :: forall m a b c s. Monad m => a -> ParserT s m (a -> a -> a) -> ParserT s m (b -> c) -> ParserT s m b -> ParserT s m (c -> a) -> ParserT s m a
85−rassocP1 x rassocOp prefixP term postfixP = rassocP x rassocOp prefixP term postfixP <|> pure x
86−
87−lassocP :: forall m a b c s. Monad m => a -> ParserT s m (a -> a -> a) -> ParserT s m (b -> c) -> ParserT s m b -> ParserT s m (c -> a) -> ParserT s m a
88−lassocP x lassocOp prefixP term postfixP = do
89− f <- lassocOp
90− y <- termP prefixP term postfixP
91− lassocP1 (f x y) lassocOp prefixP term postfixP
92−
93−lassocP1 :: forall m a b c s. Monad m => a -> ParserT s m (a -> a -> a) -> ParserT s m (b -> c) -> ParserT s m b -> ParserT s m (c -> a) -> ParserT s m a
94−lassocP1 x lassocOp prefixP term postfixP = lassocP x lassocOp prefixP term postfixP <|> pure x
95−
96−nassocP :: forall m a b c d e s. Monad m => a -> ParserT s m (a -> d -> e) -> ParserT s m (b -> c) -> ParserT s m b -> ParserT s m (c -> d) -> ParserT s m e
97−nassocP x nassocOp prefixP term postfixP = do
98− f <- nassocOp
99− y <- termP prefixP term postfixP
100− pure (f x y)
101−
102−termP :: forall m s a b c. Monad m => ParserT s m (a -> b) -> ParserT s m a -> ParserT s m (b -> c) -> ParserT s m c
103−termP prefixP term postfixP = do
104− pre <- prefixP
105− x <- term
106− post <- postfixP
107− pure (post (pre x))
src/Text/Parsing/Parser/Indent.pursdeleted−219
@@ -1,219 +0,0 @@
1−-- | This is purescript-port of Text.Parsing.Indent
2−-- | <https://hackage.haskell.org/package/indents-0.3.3/docs/Text-Parsec-Indent.html>, 05.07.2016.
3−-- | A module to construct indentation aware parsers. Many programming
4−-- | language have indentation based syntax rules e.g. python and Haskell.
5−-- | This module exports combinators to create such parsers.
6−-- |
7−-- | The input source can be thought of as a list of tokens. Abstractly
8−-- | each token occurs at a line and a column and has a width. The column
9−-- | number of a token measures is indentation. If t1 and t2 are two tokens
10−-- | then we say that indentation of t1 is more than t2 if the column
11−-- | number of occurrence of t1 is greater than that of t2.
12−-- |
13−-- | Currently this module supports two kind of indentation based syntactic
14−-- | structures which we now describe:
15−-- |
16−-- | - **Block**
17−-- |
18−-- | A block of indentation /c/ is a sequence of tokens with
19−-- | indentation at least /c/. Examples for a block is a where clause of
20−-- | Haskell with no explicit braces.
21−-- |
22−-- | - **Line fold**
23−-- |
24−-- | A line fold starting at line /l/ and indentation /c/ is a
25−-- | sequence of tokens that start at line /l/ and possibly continue to
26−-- | subsequent lines as long as the indentation is greater than /c/. Such
27−-- | a sequence of lines need to be /folded/ to a single line. An example
28−-- | is MIME headers. Line folding based binding separation is used in
29−-- | Haskell as well.
30−module Text.Parsing.Indent
31− ( IndentParser
32− , runIndent
33− , withBlock
34− , withBlock'
35− , block
36− , block1
37− , indented
38− , indented'
39− , sameLine
40− , sameOrIndented
41− , checkIndent
42− , withPos
43− , indentAp
44− , (<+/>)
45− , indentNoAp
46− , (<-/>)
47− , indentMany
48− , (<*/>)
49− , indentOp
50− , (<?/>)
51− , Optional(..)
52− ) where
53−
54−import Prelude
55−import Control.Alt ((<|>))
56−import Control.Apply (lift2)
57−import Control.Monad.State (gets, State, evalState)
58−import Control.Monad.State.Trans (get, put)
59−import Control.Monad.Trans.Class (lift)
60−import Data.List (List(..), many)
61−import Data.Maybe (Maybe(..))
62−import Text.Parsing.Parser (ParserT, ParseState(ParseState), fail)
63−import Text.Parsing.Parser.Combinators (option, optionMaybe)
64−import Text.Parsing.Parser.Pos (Position(..), initialPos)
65−import Text.Parsing.Parser.String (string, oneOf)
66−
67−-- | Indentation sensitive parser type. Usually @ m @ will
68−-- | be @ Identity @ as with any @ ParserT @
69−type IndentParser s a = ParserT s (State Position) a
70−
71−-- | @ getPosition @ returns current position
72−-- | should probably be added to Text.Parsing.Parser.Pos
73−getPosition :: forall m s. (Monad m) => ParserT s m Position
74−getPosition = gets \(ParseState _ pos _) -> pos
75−
76−-- | simple helper function to avoid typ-problems with MonadState instance
77−get' :: forall s. IndentParser s Position
78−get' = do
79− g <- lift get
80− pure g
81−
82−-- | simple helper function to avoid typ-problems with MonadState instance
83−put' :: forall s. Position -> IndentParser s Unit
84−put' p = lift (put p)
85−
86−sourceColumn :: Position -> Int
87−sourceColumn (Position {line: _, column: c}) = c
88−
89−sourceLine :: Position -> Int
90−sourceLine (Position {line: l, column: _}) = l
91−
92−setSourceLine :: Position -> Int -> Position
93−setSourceLine (Position {line: _, column: c}) l = Position {line: l, column: c}
94−
95−biAp :: forall a b c. (a -> b) -> (b -> b -> c) -> a -> a -> c
96−biAp f c v1 v2 = c (f v1) (f v2)
97−
98−-- | @ many1 @ should prabably be inside Text.Parsing.Parser.Combinators
99−many1 :: forall s m a. (Monad m) => ParserT s m a -> ParserT s m (List a)
100−many1 p = lift2 Cons p (many p)
101−
102−symbol :: forall m. (Monad m) => String -> ParserT String m String
103−symbol name = (many $ oneOf [' ','\t']) *> (string name)
104−
105−-- | `withBlock f a p` parses `a`
106−-- | followed by an indented block of `p`
107−-- | combining them with `f`.
108−withBlock :: forall a b c s. (a -> List b -> c) -> IndentParser s a -> IndentParser s b -> IndentParser s c
109−withBlock f a p = withPos $ do
110− r1 <- a
111− r <- optionMaybe $ indented *> block p
112− case r of
113− Nothing -> pure (f r1 Nil)
114− Just r2 -> pure (f r1 r2)
115−
116−-- | Like 'withBlock', but throws away initial parse result
117−withBlock' :: forall a b s. IndentParser s a -> IndentParser s b -> IndentParser s (List b)
118−withBlock' = withBlock (flip const)
119−
120−-- | Parses only when indented past the level of the reference
121−indented :: forall s. IndentParser s Unit
122−indented = do
123− pos <- getPosition
124− s <- get'
125− if biAp sourceColumn (<=) pos s then fail "not indented" else do
126− put' $ setSourceLine s (sourceLine pos)
127− pure unit
128−
129−-- | Same as `indented`, but does not change internal state
130−indented' :: forall s. IndentParser s Unit
131−indented' = do
132− pos <- getPosition
133− s <- get'
134− if biAp sourceColumn (<=) pos s then fail "not indented" else pure unit
135−
136−-- | Parses only when indented past the level of the reference or on the same line
137−sameOrIndented :: forall s. IndentParser s Unit
138−sameOrIndented = sameLine <|> indented
139−
140−-- | Parses only on the same line as the reference
141−sameLine :: forall s. IndentParser s Unit
142−sameLine = do
143− pos <- getPosition
144− s <- get'
145− if biAp sourceLine (==) pos s then pure unit else fail "over one line"
146−
147−-- | Parses a block of lines at the same indentation level
148−block1 :: forall s a. IndentParser s a -> IndentParser s (List a)
149−block1 p = withPos $ do
150− r <- many1 $ checkIndent *> p
151− pure r
152−
153−-- | Parses a block of lines at the same indentation level , empty Blocks allowed
154−block :: forall s a. IndentParser s a -> IndentParser s (List a)
155−block p = withPos $ do
156− r <- many $ checkIndent *> p
157− pure r
158−
159−-- | Parses using the current location for indentation reference
160−withPos :: forall s a. IndentParser s a -> IndentParser s a
161−withPos x = do
162− a <- get'
163− p <- getPosition
164− r <- put' p *> x
165− put' a *> pure r
166−
167−-- | Ensures the current indentation level matches that of the reference
168−checkIndent :: forall s. IndentParser s Unit
169−checkIndent = do
170− s <- get'
171− p <- getPosition
172− if biAp sourceColumn (==) p s then pure unit else fail "indentation doesn't match"
173−
174−-- | Run the result of an indentation sensitive parse
175−runIndent :: forall a. State Position a -> a
176−runIndent = flip evalState initialPos
177−
178−-- | `<+/>` is to indentation sensitive parsers what `ap` is to monads
179−indentAp :: forall s a b. IndentParser s (a -> b) -> IndentParser s a -> IndentParser s b
180−indentAp a b = ap a $ sameOrIndented *> b
181−
182−infixl 9 indentAp as <+/>
183−
184−-- | Like `<+/>` but doesn't apply the function to the parsed value
185−indentNoAp :: forall s a b. IndentParser s a -> IndentParser s b -> IndentParser s a
186−indentNoAp a b = lift2 const a $ sameOrIndented *> b
187−
188−infixl 10 indentNoAp as <-/>
189−
190−-- | Like `<+/>` but applies the second parser many times
191−indentMany :: forall s a b. IndentParser s (List a -> b) -> IndentParser s a -> IndentParser s b
192−indentMany a b = ap a (many (sameOrIndented *> b))
193−
194−infixl 11 indentMany as <*/>
195−
196−-- | Data type used to optional parsing
197−data Optional s a = Opt a (IndentParser s a)
198−
199−-- | Like `<+/>` but applies the second parser optionally using the `Optional` datatype
200−indentOp :: forall s a b. IndentParser s (a -> b) -> Optional s a -> IndentParser s b
201−indentOp a (Opt b c) = ap a (option b (sameOrIndented *> c))
202−
203−infixl 12 indentOp as <?/>
204−
205−-- | Parses with surrounding brackets
206−indentBrackets :: forall a. IndentParser String a -> IndentParser String a
207−indentBrackets p = withPos $ pure identity <-/> symbol "[" <+/> p <-/> symbol "]"
208−
209−-- | Parses with surrounding angle brackets
210−indentAngles :: forall a. IndentParser String a -> IndentParser String a
211−indentAngles p = withPos $ pure identity <-/> symbol "<" <+/> p <-/> symbol ">"
212−
213−-- | Parses with surrounding braces
214−indentBraces :: forall a. IndentParser String a -> IndentParser String a
215−indentBraces p = withPos $ pure identity <-/> symbol "{" <+/> p <-/> symbol "}"
216−
217−-- | Parses with surrounding parentheses
218−indentParens :: forall a. IndentParser String a -> IndentParser String a
219−indentParens p = withPos $ pure identity <-/> symbol "(" <+/> p <-/> symbol ")"
src/Text/Parsing/Parser/Language.pursdeleted−118
@@ -1,118 +0,0 @@
1−
2−module Text.Parsing.Parser.Language
3− ( haskellDef
4− , haskell
5− , emptyDef
6− , haskellStyle
7− , javaStyle
8− )
9− where
10−
11−import Prelude
12−
13−import Control.Alt ((<|>))
14−import Text.Parsing.Parser (ParserT)
15−import Text.Parsing.Parser.String (char, oneOf)
16−import Text.Parsing.Parser.Token (LanguageDef, TokenParser, GenLanguageDef(..), unGenLanguageDef, makeTokenParser, alphaNum, letter)
17−
18−-----------------------------------------------------------
19−-- Styles: haskellStyle, javaStyle
20−-----------------------------------------------------------
21−
22−-- | This is a minimal token definition for Haskell style languages. It
23−-- | defines the style of comments, valid identifiers and case
24−-- | sensitivity. It does not define any reserved words or operators.
25−haskellStyle :: LanguageDef
26−haskellStyle = LanguageDef (unGenLanguageDef emptyDef)
27− { commentStart = "{-"
28− , commentEnd = "-}"
29− , commentLine = "--"
30− , nestedComments = true
31− , identStart = letter
32− , identLetter = alphaNum <|> oneOf ['_', '\'']
33− , opStart = op'
34− , opLetter = op'
35− , reservedOpNames = []
36− , reservedNames = []
37− , caseSensitive = true
38− }
39− where
40− op' :: forall m . (Monad m) => ParserT String m Char
41− op' = oneOf [':', '!', '#', '$', '%', '&', '*', '+', '.', '/', '<', '=', '>', '?', '@', '\\', '^', '|', '-', '~']
42−
43−-- | This is a minimal token definition for Java style languages. It
44−-- | defines the style of comments, valid identifiers and case
45−-- | sensitivity. It does not define any reserved words or operators.
46−javaStyle :: LanguageDef
47−javaStyle = LanguageDef (unGenLanguageDef emptyDef)
48− { commentStart = "/*"
49− , commentEnd = "*/"
50− , commentLine = "//"
51− , nestedComments = true
52− , identStart = letter <|> oneOf ['_', '$']
53− , identLetter = alphaNum <|> oneOf ['_', '$']
54− , reservedNames = []
55− , reservedOpNames = []
56− , caseSensitive = false
57− }
58−
59−-----------------------------------------------------------
60−-- minimal language definition
61−--------------------------------------------------------
62−
63−-- | This is the most minimal token definition. It is recommended to use
64−-- | this definition as the basis for other definitions. `emptyDef` has
65−-- | no reserved names or operators, is case sensitive and doesn't accept
66−-- | comments, identifiers or operators.
67−emptyDef :: LanguageDef
68−emptyDef = LanguageDef
69− { commentStart: ""
70− , commentEnd: ""
71− , commentLine: ""
72− , nestedComments: true
73− , identStart: letter <|> char '_'
74− , identLetter: alphaNum <|> oneOf ['_', '\'']
75− , opStart: op'
76− , opLetter: op'
77− , reservedOpNames: []
78− , reservedNames: []
79− , caseSensitive: true
80− }
81− where
82− op' :: forall m . (Monad m) => ParserT String m Char
83− op' = oneOf [':', '!', '#', '$', '%', '&', '*', '+', '.', '/', '<', '=', '>', '?', '@', '\\', '^', '|', '-', '~']
84−
85−-- -----------------------------------------------------------
86−-- -- Haskell
87−-- -----------------------------------------------------------
88−
89−-- | A lexer for the haskell language.
90−haskell :: TokenParser
91−haskell = makeTokenParser haskellDef
92−
93−-- | The language definition for the Haskell language.
94−haskellDef :: LanguageDef
95−haskellDef =
96− case haskell98Def of
97− (LanguageDef def) -> LanguageDef def
98− { identLetter = def.identLetter <|> char '#'
99− , reservedNames = def.reservedNames <>
100− ["foreign","import","export","primitive"
101− ,"_ccall_","_casm_"
102− ,"forall"
103− ]
104− }
105−
106−-- | The language definition for the language Haskell98.
107−haskell98Def :: LanguageDef
108−haskell98Def = LanguageDef (unGenLanguageDef haskellStyle)
109− { reservedOpNames = ["::","..","=","\\","|","<-","->","@","~","=>"]
110− , reservedNames = [ "let","in","case","of","if","then","else"
111− , "data","type"
112− , "class","default","deriving","do","import"
113− , "infix","infixl","infixr","instance","module"
114− , "newtype","where"
115− , "primitive"
116− -- "as","qualified","hiding"
117− ]
118− }
src/Text/Parsing/Parser/Pos.pursdeleted−36
@@ -1,36 +0,0 @@
1−module Text.Parsing.Parser.Pos where
2−
3−import Prelude
4−import Data.Foldable (foldl)
5−import Data.Newtype (wrap)
6−import Data.String (split)
7−
8−-- | `Position` represents the position of the parser in the input.
9−-- |
10−-- | - `line` is the current line in the input
11−-- | - `column` is the column of the next character in the current line that will be parsed
12−newtype Position = Position
13− { line :: Int
14− , column :: Int
15− }
16−
17−instance showPosition :: Show Position where
18− show (Position { line: line, column: column }) =
19− "(Position { line: " <> show line <> ", column: " <> show column <> " })"
20−
21−derive instance eqPosition :: Eq Position
22−derive instance ordPosition :: Ord Position
23−
24−-- | The `Position` before any input has been parsed is line 1, column 1.
25−initialPos :: Position
26−initialPos = Position { line: 1, column: 1 }
27−
28−-- | Updates a `Position` by adding the columns and lines in `String`.
29−updatePosString :: Position -> String -> Position
30−updatePosString pos' str = foldl updatePosChar pos' (split (wrap "") str)
31− where
32− updatePosChar (Position pos) c = case c of
33− "\n" -> Position { line: pos.line + 1, column: 1 }
34− "\r" -> Position { line: pos.line + 1, column: 1 }
35− "\t" -> Position { line: pos.line, column: pos.column + 8 - ((pos.column - 1) `mod` 8) }
36− _ -> Position { line: pos.line, column: pos.column + 1 }
src/Text/Parsing/Parser/String.pursdeleted−92
@@ -1,92 +0,0 @@
1−-- | Primitive parsers for working with an input stream of type `String`.
2−
3−module Text.Parsing.Parser.String where
4−
5−import Prelude hiding (between)
6−
7−import Control.Monad.State (gets, modify_)
8−import Data.Array (many)
9−import Data.Foldable (elem, notElem)
10−import Data.Maybe (Maybe(..))
11−import Data.Newtype (wrap)
12−import Data.String (Pattern, length)
13−import Data.String as S
14−import Data.String.CodeUnits as SCU
15−import Text.Parsing.Parser (ParseState(..), ParserT, fail)
16−import Text.Parsing.Parser.Combinators (tryRethrow, (<?>))
17−import Text.Parsing.Parser.Pos (updatePosString)
18−
19−-- | This class exists to abstract over streams which support the string-like
20−-- | operations which this modules needs.
21−class StringLike s where
22− drop :: Int -> s -> s
23− indexOf :: Pattern -> s -> Maybe Int
24− null :: s -> Boolean
25− uncons :: s -> Maybe { head :: Char, tail :: s }
26−
27−instance stringLikeString :: StringLike String where
28− uncons = SCU.uncons
29− drop = S.drop
30− indexOf = S.indexOf
31− null = S.null
32−
33−-- | Match end-of-file.
34−eof :: forall s m. StringLike s => Monad m => ParserT s m Unit
35−eof = do
36− input <- gets \(ParseState input _ _) -> input
37− unless (null input) (fail "Expected EOF")
38−
39−-- | Match the specified string.
40−string :: forall s m. StringLike s => Monad m => String -> ParserT s m String
41−string str = do
42− input <- gets \(ParseState input _ _) -> input
43− case indexOf (wrap str) input of
44− Just 0 -> do
45− modify_ \(ParseState _ position _) ->
46− ParseState (drop (length str) input)
47− (updatePosString position str)
48− true
49− pure str
50− _ -> fail ("Expected " <> show str)
51−
52−-- | Match any character.
53−anyChar :: forall s m. StringLike s => Monad m => ParserT s m Char
54−anyChar = do
55− input <- gets \(ParseState input _ _) -> input
56− case uncons input of
57− Nothing -> fail "Unexpected EOF"
58− Just { head, tail } -> do
59− modify_ \(ParseState _ position _) ->
60− ParseState tail
61− (updatePosString position (SCU.singleton head))
62− true
63− pure head
64−
65−-- | Match a character satisfying the specified predicate.
66−satisfy :: forall s m. StringLike s => Monad m => (Char -> Boolean) -> ParserT s m Char
67−satisfy f = tryRethrow do
68− c <- anyChar
69− if f c then pure c
70− else fail $ "Character '" <> SCU.singleton c <> "' did not satisfy predicate"
71−
72−-- | Match the specified character
73−char :: forall s m. StringLike s => Monad m => Char -> ParserT s m Char
74−char c = satisfy (_ == c) <?> show c
75−
76−-- | Match zero or more whitespace characters.
77−whiteSpace :: forall s m. StringLike s => Monad m => ParserT s m String
78−whiteSpace = do
79− cs <- many $ satisfy \c -> c == '\n' || c == '\r' || c == ' ' || c == '\t'
80− pure $ SCU.fromCharArray cs
81−
82−-- | Skip whitespace characters.
83−skipSpaces :: forall s m. StringLike s => Monad m => ParserT s m Unit
84−skipSpaces = void whiteSpace
85−
86−-- | Match one of the characters in the array.
87−oneOf :: forall s m. StringLike s => Monad m => Array Char -> ParserT s m Char
88−oneOf ss = satisfy (flip elem ss) <?> ("one of " <> show ss)
89−
90−-- | Match any character not in the array.
91−noneOf :: forall s m. StringLike s => Monad m => Array Char -> ParserT s m Char
92−noneOf ss = satisfy (flip notElem ss) <?> ("none of " <> show ss)
src/Text/Parsing/Parser/Token.pursdeleted−809
@@ -1,809 +0,0 @@
1−-- | Functions for working with streams of tokens.
2−
3−module Text.Parsing.Parser.Token
4− ( token
5− , when
6− , match
7− , LanguageDef
8− , GenLanguageDef(LanguageDef)
9− , unGenLanguageDef
10− , TokenParser
11− , GenTokenParser
12− , makeTokenParser
13− -- should these be exported? Maybe they should go in a different module?
14− , digit
15− , hexDigit
16− , octDigit
17− , upper
18− , space
19− , letter
20− , alphaNum
21− )
22− where
23−
24−import Prelude hiding (when,between)
25−
26−import Control.Lazy (fix)
27−import Control.Monad.State (gets, modify_)
28−import Control.MonadPlus (guard, (<|>))
29−import Data.Array as Array
30−import Data.Char (fromCharCode, toCharCode)
31−import Data.Char.Unicode (digitToInt, isAlpha, isAlphaNum, isDigit, isHexDigit, isOctDigit, isSpace, isUpper)
32−import Data.Char.Unicode as Unicode
33−import Data.Either (Either(..))
34−import Data.Foldable (foldl, foldr)
35−import Data.Identity (Identity)
36−import Data.Int (toNumber)
37−import Data.List (List(..))
38−import Data.List as List
39−import Data.Maybe (Maybe(..), maybe)
40−import Data.String (null, toLower)
41−import Data.String.CodeUnits as SCU
42−import Data.Tuple (Tuple(..))
43−import Math (pow)
44−import Text.Parsing.Parser (ParseState(..), ParserT, fail)
45−import Text.Parsing.Parser.Combinators (skipMany1, try, tryRethrow, skipMany, notFollowedBy, option, choice, between, sepBy1, sepBy, (<?>), (<??>))
46−import Text.Parsing.Parser.Pos (Position)
47−import Text.Parsing.Parser.String (satisfy, oneOf, noneOf, string, char)
48−
49−-- | Create a parser which Returns the first token in the stream.
50−token :: forall m a. Monad m => (a -> Position) -> ParserT (List a) m a
51−token tokpos = do
52− input <- gets \(ParseState input _ _) -> input
53− case List.uncons input of
54− Nothing -> fail "Unexpected EOF"
55− Just { head, tail } -> do
56− modify_ \(ParseState _ position _) ->
57− ParseState tail (tokpos head) true
58− pure head
59−
60−-- | Create a parser which matches any token satisfying the predicate.
61−when :: forall m a. Monad m => (a -> Position) -> (a -> Boolean) -> ParserT (List a) m a
62−when tokpos f = tryRethrow do
63− a <- token tokpos
64− guard $ f a
65− pure a
66−
67−-- | Match the specified token at the head of the stream.
68−match :: forall a m. Monad m => Eq a => (a -> Position) -> a -> ParserT (List a) m a
69−match tokpos tok = when tokpos (_ == tok)
70−
71−type LanguageDef = GenLanguageDef String Identity
72−
73−-- | The `GenLanguageDef` type is a record that contains all parameterizable
74−-- | features of the "Text.Parsec.Token" module. The module `Text.Parsec.Language`
75−-- | contains some default definitions.
76−newtype GenLanguageDef s m
77− = LanguageDef {
78− -- | Describes the start of a block comment. Use the empty string if the
79− -- | language doesn't support block comments. For example `/*`.
80− commentStart :: String,
81− -- | Describes the end of a block comment. Use the empty string if the
82− -- | language doesn't support block comments. For example `*/`.
83− commentEnd :: String,
84− -- | Describes the start of a line comment. Use the empty string if the
85− -- | language doesn't support line comments. For example `//`.
86− commentLine :: String,
87− -- | Set to `true` if the language supports nested block comments.
88− nestedComments :: Boolean,
89− -- | This parser should accept any start characters of identifiers. For
90− -- | example `letter <|> char '_'`.
91− identStart :: ParserT s m Char,
92− -- | This parser should accept any legal tail characters of identifiers.
93− -- | For example `alphaNum <|> char '_'`.
94− identLetter :: ParserT s m Char,
95− -- | This parser should accept any start characters of operators. For
96− -- | example `oneOf [':', '+', '=']`.
97− opStart :: ParserT s m Char,
98− -- | This parser should accept any legal tail characters of operators.
99− -- | Note that this parser should even be defined if the language doesn't
100− -- | support user-defined operators, or otherwise the `reservedOp`
101− -- | parser won't work correctly.
102− opLetter :: ParserT s m Char,
103− -- | The list of reserved identifiers.
104− reservedNames :: Array String,
105− -- | The list of reserved operators.
106− reservedOpNames:: Array String,
107− -- | Set to `true` if the language is case sensitive.
108− caseSensitive :: Boolean
109− }
110−
111−unGenLanguageDef :: forall s m . GenLanguageDef s m -> { caseSensitive :: Boolean
112− , reservedOpNames :: Array String
113− , reservedNames :: Array String
114− , opLetter :: ParserT s m Char
115− , opStart :: ParserT s m Char
116− , identLetter :: ParserT s m Char
117− , identStart :: ParserT s m Char
118− , nestedComments :: Boolean
119− , commentLine :: String
120− , commentEnd :: String
121− , commentStart :: String
122− }
123−unGenLanguageDef (LanguageDef langDef) = langDef
124−
125−-----------------------------------------------------------
126−-- A first class module: TokenParser
127−-----------------------------------------------------------
128−
129−type TokenParser = GenTokenParser String Identity
130−
131−-- | The type of the record that holds lexical parsers that work on
132−-- | `s` streams over a monad `m`.
133−type GenTokenParser s m
134− = {
135− -- | This lexeme parser parses a legal identifier. Returns the identifier
136− -- | string. This parser will fail on identifiers that are reserved
137− -- | words. Legal identifier (start) characters and reserved words are
138− -- | defined in the `LanguageDef` that is passed to
139− -- | `makeTokenParser`. An `identifier` is treated as
140− -- | a single token using `try`.
141− identifier :: ParserT s m String,
142− -- | The lexeme parser `reserved name` parses `symbol
143− -- | name`, but it also checks that the `name` is not a prefix of a
144− -- | valid identifier. A `reserved` word is treated as a single token
145− -- | using `try`.
146− reserved :: String -> ParserT s m Unit,
147− -- | This lexeme parser parses a legal operator. Returns the name of the
148− -- | operator. This parser will fail on any operators that are reserved
149− -- | operators. Legal operator (start) characters and reserved operators
150− -- | are defined in the `LanguageDef` that is passed to
151− -- | `makeTokenParser`. An `operator` is treated as a
152− -- | single token using `try`.
153− operator :: ParserT s m String,
154− -- |The lexeme parser `reservedOp name` parses `symbol
155− -- | name`, but it also checks that the `name` is not a prefix of a
156− -- | valid operator. A `reservedOp` is treated as a single token using
157− -- | `try`.
158− reservedOp :: String -> ParserT s m Unit,
159− -- | This lexeme parser parses a single literal character. Returns the
160− -- | literal character value. This parsers deals correctly with escape
161− -- | sequences. The literal character is parsed according to the grammar
162− -- | rules defined in the Haskell report (which matches most programming
163− -- | languages quite closely).
164− charLiteral :: ParserT s m Char,
165− -- | This lexeme parser parses a literal string. Returns the literal
166− -- | string value. This parsers deals correctly with escape sequences and
167− -- | gaps. The literal string is parsed according to the grammar rules
168− -- | defined in the Haskell report (which matches most programming
169− -- | languages quite closely).
170− stringLiteral :: ParserT s m String,
171− -- | This lexeme parser parses a natural number (a positive whole
172− -- | number). Returns the value of the number. The number can be
173− -- | specified in `decimal`, `hexadecimal` or
174− -- | `octal`. The number is parsed according to the grammar
175− -- | rules in the Haskell report.
176− natural :: ParserT s m Int,
177− -- | This lexeme parser parses an integer (a whole number). This parser
178− -- | is like `natural` except that it can be prefixed with
179− -- | sign (i.e. `-` or `+`). Returns the value of the number. The
180− -- | number can be specified in `decimal`, `hexadecimal`
181− -- | or `octal`. The number is parsed according
182− -- | to the grammar rules in the Haskell report.
183− integer :: ParserT s m Int,
184− -- | This lexeme parser parses a floating point value. Returns the value
185− -- | of the number. The number is parsed according to the grammar rules
186− -- | defined in the Haskell report.
187− float :: ParserT s m Number,
188− -- | This lexeme parser parses either `natural` or a `float`.
189− -- | Returns the value of the number. This parsers deals with
190− -- | any overlap in the grammar rules for naturals and floats. The number
191− -- | is parsed according to the grammar rules defined in the Haskell report.
192− naturalOrFloat :: ParserT s m (Either Int Number),
193− -- | Parses a positive whole number in the decimal system. Returns the
194− -- | value of the number.
195− decimal :: ParserT s m Int,
196− -- | Parses a positive whole number in the hexadecimal system. The number
197− -- | should be prefixed with `0x` or `0X`. Returns the value of the
198− -- | number.
199− hexadecimal :: ParserT s m Int,
200− -- | Parses a positive whole number in the octal system. The number
201− -- | should be prefixed with `0o` or `0O`. Returns the value of the
202− -- | number.
203− octal :: ParserT s m Int,
204− -- | Lexeme parser `symbol s` parses `string` `s` and skips
205− -- | trailing white space.
206− symbol :: String -> ParserT s m String,
207− -- | `lexeme p` first applies parser `p` and than the `whiteSpace`
208− -- | parser, returning the value of `p`. Every lexical
209− -- | token (lexeme) is defined using `lexeme`, this way every parse
210− -- | starts at a point without white space. Parsers that use `lexeme` are
211− -- | called *lexeme* parsers in this document.
212− -- |
213− -- | The only point where the `whiteSpace` parser should be
214− -- | called explicitly is the start of the main parser in order to skip
215− -- | any leading white space.
216− -- |
217− -- | ```purescript
218− -- | mainParser = do
219− -- | whiteSpace
220− -- | ds <- many (lexeme digit)
221− -- | eof
222− -- | pure (sum ds)
223− -- | ```
224− lexeme :: forall a. ParserT s m a -> ParserT s m a,
225− -- | Parses any white space. White space consists of *zero* or more
226− -- | occurrences of a `space`, a line comment or a block (multi
227− -- | line) comment. Block comments may be nested. How comments are
228− -- | started and ended is defined in the `LanguageDef`
229− -- | that is passed to `makeTokenParser`.
230− whiteSpace :: ParserT s m Unit,
231− -- | Lexeme parser `parens p` parses `p` enclosed in parenthesis,
232− -- | returning the value of `p`.
233− parens :: forall a. ParserT s m a -> ParserT s m a,
234− -- | Lexeme parser `braces p` parses `p` enclosed in braces (`{` and
235− -- | `}`), returning the value of `p`.
236− braces :: forall a. ParserT s m a -> ParserT s m a,
237− -- | Lexeme parser `angles p` parses `p` enclosed in angle brackets (`<`
238− -- | and `>`), returning the value of `p`.
239− angles :: forall a. ParserT s m a -> ParserT s m a,
240− -- | Lexeme parser `brackets p` parses `p` enclosed in brackets (`[`
241− -- | and `]`), returning the value of `p`.
242− brackets :: forall a. ParserT s m a -> ParserT s m a,
243− -- | Lexeme parser `semi` parses the character `;` and skips any
244− -- | trailing white space. Returns the string `;`.
245− semi :: ParserT s m String,
246− -- | Lexeme parser `comma` parses the character `,` and skips any
247− -- | trailing white space. Returns the string `,`.
248− comma :: ParserT s m String,
249− -- | Lexeme parser `colon` parses the character `:` and skips any
250− -- | trailing white space. Returns the string `:`.
251− colon :: ParserT s m String,
252− -- | Lexeme parser `dot` parses the character `.` and skips any
253− -- | trailing white space. Returns the string `.`.
254− dot :: ParserT s m String,
255− -- | Lexeme parser `semiSep p` parses *zero* or more occurrences of `p`
256− -- | separated by `semi`. Returns a list of values pureed by
257− -- | `p`.
258− semiSep :: forall a . ParserT s m a -> ParserT s m (List a),
259− -- | Lexeme parser `semiSep1 p` parses *one* or more occurrences of `p`
260− -- | separated by `semi`. Returns a list of values pureed by `p`.
261− semiSep1 :: forall a . ParserT s m a -> ParserT s m (List a),
262− -- | Lexeme parser `commaSep p` parses *zero* or more occurrences of
263− -- | `p` separated by `comma`. Returns a list of values pureed
264− -- | by `p`.
265− commaSep :: forall a . ParserT s m a -> ParserT s m (List a),
266− -- | Lexeme parser `commaSep1 p` parses *one* or more occurrences of
267− -- | `p` separated by `comma`. Returns a list of values pureed
268− -- | by `p`.
269− commaSep1 :: forall a . ParserT s m a -> ParserT s m (List a)
270− }
271−
272−-----------------------------------------------------------
273−-- Given a LanguageDef, create a token parser.
274−-----------------------------------------------------------
275−
276−-- | The expression `makeTokenParser language` creates a `GenTokenParser`
277−-- | record that contains lexical parsers that are
278−-- | defined using the definitions in the `language` record.
279−-- |
280−-- | The use of this function is quite stylized - one imports the
281−-- | appropiate language definition and selects the lexical parsers that
282−-- | are needed from the resulting `GenTokenParser`.
283−-- |
284−-- | ```purescript
285−-- | module Main where
286−-- |
287−-- | import Text.Parsing.Parser.Language (haskellDef)
288−-- | import Text.Parsing.Parser.Token (makeTokenParser)
289−-- |
290−-- | -- The parser
291−-- | expr = parens expr
292−-- | <|> identifier
293−-- | <|> ...
294−-- |
295−-- |
296−-- | -- The lexer
297−-- | tokenParser = makeTokenParser haskellDef
298−-- | parens = tokenParser.parens
299−-- | braces = tokenParser.braces
300−-- | identifier = tokenParser.identifier
301−-- | reserved = tokenParser.reserved
302−-- | ...
303−-- | ```
304−makeTokenParser :: forall m . Monad m => GenLanguageDef String m -> GenTokenParser String m
305−makeTokenParser (LanguageDef languageDef)
306− = { identifier: identifier
307− , reserved: reserved
308− , operator: operator
309− , reservedOp: reservedOp
310−
311− , charLiteral: charLiteral
312− , stringLiteral: stringLiteral
313− , natural: natural
314− , integer: integer
315− , float: float
316− , naturalOrFloat: naturalOrFloat
317− , decimal: decimal
318− , hexadecimal: hexadecimal
319− , octal: octal
320−
321− , symbol: symbol
322− , lexeme: lexeme
323− , whiteSpace: whiteSpace' (LanguageDef languageDef)
324−
325− , parens: parens
326− , braces: braces
327− , angles: angles
328− , brackets: brackets
329− , semi: semi
330− , comma: comma
331− , colon: colon
332− , dot: dot
333− , semiSep: semiSep
334− , semiSep1: semiSep1
335− , commaSep: commaSep
336− , commaSep1: commaSep1
337− }
338− where
339− -----------------------------------------------------------
340− -- Bracketing
341− -----------------------------------------------------------
342− parens :: forall a . ParserT String m a -> ParserT String m a
343− parens p = between (symbol "(") (symbol ")") p
344−
345− braces :: forall a . ParserT String m a -> ParserT String m a
346− braces p = between (symbol "{") (symbol "}") p
347−
348− angles :: forall a . ParserT String m a -> ParserT String m a
349− angles p = between (symbol "<") (symbol ">") p
350−
351− brackets :: forall a . ParserT String m a -> ParserT String m a
352− brackets p = between (symbol "[") (symbol "]") p
353−
354− semi :: ParserT String m String
355− semi = symbol ";"
356−
357− comma :: ParserT String m String
358− comma = symbol ","
359−
360− dot :: ParserT String m String
361− dot = symbol "."
362−
363− colon :: ParserT String m String
364− colon = symbol ":"
365−
366− commaSep :: forall a . ParserT String m a -> ParserT String m (List a)
367− commaSep p = sepBy p comma
368−
369− semiSep :: forall a . ParserT String m a -> ParserT String m (List a)
370− semiSep p = sepBy p semi
371−
372− commaSep1 :: forall a . ParserT String m a -> ParserT String m (List a)
373− commaSep1 p = sepBy1 p comma
374−
375− semiSep1 :: forall a . ParserT String m a -> ParserT String m (List a)
376− semiSep1 p = sepBy1 p semi
377−
378− -----------------------------------------------------------
379− -- Chars & Strings
380− -----------------------------------------------------------
381− charLiteral :: ParserT String m Char
382− charLiteral = lexeme go <?> "character"
383− where
384− go :: ParserT String m Char
385− go = between (char '\'') (char '\'' <?> "end of character") characterChar
386−
387− characterChar :: ParserT String m Char
388− characterChar = charLetter <|> charEscape <?> "literal character"
389−
390− charEscape :: ParserT String m Char
391− charEscape = char '\\' *> escapeCode
392−
393− charLetter :: ParserT String m Char
394− charLetter = satisfy \c -> (c /= '\'') && (c /= '\\') && (c > '\x1A')
395−
396− stringLiteral :: ParserT String m String
397− stringLiteral = lexeme (go <?> "literal string")
398− where
399− go :: ParserT String m String
400− go = do
401− maybeChars <- between (char '"') (char '"' <?> "end of string") (List.many stringChar)
402− pure $ SCU.fromCharArray $ List.toUnfoldable $ foldr folder Nil maybeChars
403−
404− folder :: Maybe Char -> List Char -> List Char
405− folder Nothing chars = chars
406− folder (Just c) chars = Cons c chars
407−
408−
409− stringChar :: ParserT String m (Maybe Char)
410− stringChar = (Just <$> stringLetter)
411− <|> stringEscape
412− <?> "string character"
413−
414− stringLetter :: ParserT String m Char
415− stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\x1A'))
416−
417− stringEscape :: ParserT String m (Maybe Char)
418− stringEscape = do
419− _ <- char '\\'
420− (escapeGap $> Nothing) <|> (escapeEmpty $> Nothing) <|> (Just <$> escapeCode)
421−
422− escapeEmpty :: ParserT String m Char
423− escapeEmpty = char '&'
424−
425− escapeGap :: ParserT String m Char
426− escapeGap = Array.some space *> char '\\' <?> "end of string gap"
427−
428− -- -- escape codes
429− escapeCode :: ParserT String m Char
430− escapeCode = charEsc <|> charNum <|> charAscii <|> charControl
431− <?> "escape code"
432−
433− charControl :: ParserT String m Char
434− charControl = do
435− _ <- char '^'
436− code <- upper
437− case fromCharCode (toCharCode code - toCharCode 'A' + 1) of
438− Just c -> pure c
439− Nothing -> fail "invalid character code (should not happen)"
440−
441− charNum :: ParserT String m Char
442− charNum = do
443− code <- decimal
444− <|> ( char 'o' *> number 8 octDigit )
445− <|> ( char 'x' *> number 16 hexDigit )
446− if code > 0x10FFFF
447− then fail "invalid escape sequence"
448− else case fromCharCode code of
449− Just c -> pure c
450− Nothing -> fail "invalid character code (should not happen)"
451−
452− charEsc :: ParserT String m Char
453− charEsc = choice (map parseEsc escMap)
454− where
455− parseEsc :: Tuple Char Char -> ParserT String m Char
456− parseEsc (Tuple c code) = char c $> code
457−
458− charAscii :: ParserT String m Char
459− charAscii = choice (map parseAscii asciiMap)
460− where
461− parseAscii :: Tuple String Char -> ParserT String m Char
462− parseAscii (Tuple asc code) = try $ string asc $> code
463−
464− -- escape code tables
465− escMap :: Array (Tuple Char Char)
466− escMap = Array.zip [ 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\"', '\'' ]
467− [ '\x7', '\x8', '\xC', '\n', '\r', '\t', '\xB', '\\', '\"', '\'' ]
468−
469− asciiMap :: Array (Tuple String Char)
470− asciiMap = Array.zip (ascii3codes <> ascii2codes) (ascii3 <> ascii2)
471−
472− ascii2codes :: Array String
473− ascii2codes = [ "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "EM", "FS", "GS", "RS", "US", "SP" ]
474−
475− ascii3codes :: Array String
476− ascii3codes = [ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL"
477− , "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB"
478− , "CAN", "SUB", "ESC", "DEL"
479− ]
480−
481− ascii2 :: Array Char
482− ascii2 = [ '\x8', '\x9', '\xA', '\xB', '\xC', '\xD', '\xE', '\xF'
483− , '\x19', '\x1C', '\x1D', '\x1E', '\x1F', '\x20'
484− ]
485−
486− ascii3 :: Array Char
487− ascii3 = [ '\x0', '\x1', '\x2', '\x3', '\x4', '\x5', '\x6'
488− , '\x7', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15'
489− , '\x16', '\x17', '\x18', '\x1A', '\x1B', '\x7F'
490− ]
491−
492− -----------------------------------------------------------
493− -- Numbers
494− -----------------------------------------------------------
495−
496− naturalOrFloat :: ParserT String m (Either Int Number)
497− naturalOrFloat = lexeme (natFloat) <?> "number"
498−
499− float :: ParserT String m Number
500− float = lexeme floating <?> "float"
501−
502− integer :: ParserT String m Int
503− integer = lexeme int <?> "integer"
504−
505− natural :: ParserT String m Int
506− natural = lexeme nat <?> "natural"
507−
508− -- floats
509− floating :: ParserT String m Number
510− floating = decimal >>= fractExponent
511−
512− natFloat :: ParserT String m (Either Int Number)
513− natFloat = char '0' *> zeroNumFloat
514− <|> decimalFloat
515−
516− zeroNumFloat :: ParserT String m (Either Int Number)
517− zeroNumFloat = Left <$> (hexadecimal <|> octal)
518− <|> decimalFloat
519− <|> fractFloat 0
520− <|> pure (Left 0)
521−
522− decimalFloat :: ParserT String m (Either Int Number)
523− decimalFloat = do
524− n <- decimal
525− option (Left n) (fractFloat n)
526−
527− fractFloat :: forall a . Int -> ParserT String m (Either a Number)
528− fractFloat n = Right <$> fractExponent n
529−
530− fractExponent :: Int -> ParserT String m Number
531− fractExponent n = fractExponent' <|> justExponent
532− where
533− fractExponent' :: ParserT String m Number
534− fractExponent' = do
535− fract <- fraction
536− expo <- option 1.0 exponent'
537− pure $ (toNumber n + fract) * expo
538−
539− justExponent :: ParserT String m Number
540− justExponent = do
541− expo <- exponent'
542− pure $ (toNumber n * expo)
543−
544− fraction :: ParserT String m Number
545− fraction = "fraction" <??> do
546− _ <- char '.'
547− digits <- Array.some digit <?> "fraction"
548− maybe (fail "not digit") pure $ foldr op (Just 0.0) digits
549− where
550− op :: Char -> Maybe Number -> Maybe Number
551− op _ Nothing = Nothing
552− op d (Just f) = do
553− int' <- digitToInt d
554− pure $ ( f + toNumber int' ) / 10.0
555−
556− exponent' :: ParserT String m Number
557− exponent' = "exponent" <??> do
558− _ <- oneOf ['e', 'E']
559− f <- sign
560− e <- decimal <?> "exponent"
561− pure $ power (f e)
562− where
563− power :: Int -> Number
564− power e | e < 0 = 1.0 / power (-e)
565− | otherwise = 10.0 `pow` toNumber e
566−
567− -- integers and naturals
568− int :: ParserT String m Int
569− int = do
570− f <- lexeme sign
571− n <- nat
572− pure $ f n
573−
574− sign :: forall a . (Ring a) => ParserT String m (a -> a)
575− sign = (char '-' $> negate)
576− <|> (char '+' $> identity)
577− <|> pure identity
578−
579− nat :: ParserT String m Int
580− nat = zeroNumber <|> decimal
581−
582− zeroNumber :: ParserT String m Int
583− zeroNumber = char '0' *>
584− ( hexadecimal <|> octal <|> decimal <|> pure 0 ) <?> ""
585−
586− decimal :: ParserT String m Int
587− decimal = number 10 digit
588−
589− hexadecimal :: ParserT String m Int
590− hexadecimal = oneOf ['x', 'X'] *> number 16 hexDigit
591−
592− octal :: ParserT String m Int
593− octal = oneOf ['o', 'O'] *> number 8 octDigit
594−
595− number :: Int -> ParserT String m Char -> ParserT String m Int
596− number base baseDigit = do
597− digits <- Array.some baseDigit
598− maybe (fail "not digits") pure $ foldl folder (Just 0) digits
599− where
600− folder :: Maybe Int -> Char -> Maybe Int
601− folder Nothing _ = Nothing
602− folder (Just x) d = ((base * x) + _) <$> digitToInt d
603−
604− -----------------------------------------------------------
605− -- Operators & reserved ops
606− -----------------------------------------------------------
607−
608− reservedOp :: String -> ParserT String m Unit
609− reservedOp name = lexeme $ try go
610− where
611− go :: ParserT String m Unit
612− go = do
613− _ <- string name
614− notFollowedBy languageDef.opLetter <?> "end of " <> name
615−
616− operator :: ParserT String m String
617− operator = lexeme $ try go
618− where
619− go :: ParserT String m String
620− go = do
621− name <- oper
622− if (isReservedOp name)
623− then fail ("reserved operator " <> name)
624− else pure name
625−
626− oper :: ParserT String m String
627− oper = go <?> "operator"
628− where
629− go :: ParserT String m String
630− go = do
631− c <- languageDef.opStart
632− cs <- Array.many languageDef.opLetter
633− pure $ SCU.singleton c <> SCU.fromCharArray cs
634−
635− isReservedOp :: String -> Boolean
636− isReservedOp name = isReserved (Array.sort languageDef.reservedOpNames) name
637−
638−
639− -----------------------------------------------------------
640− -- Identifiers & Reserved words
641− -----------------------------------------------------------
642−
643− reserved :: String -> ParserT String m Unit
644− reserved name = lexeme $ try go
645− where
646− go :: ParserT String m Unit
647− go = caseString name *> (notFollowedBy languageDef.identLetter <?> "end of " <> name)
648−
649− caseString :: String -> ParserT String m String
650− caseString name | languageDef.caseSensitive = string name $> name
651− | otherwise = walk name $> name
652− where
653− walk :: String -> ParserT String m Unit
654− walk name' = case SCU.uncons name' of
655− Nothing -> pure unit
656− Just { head: c, tail: cs } -> (caseChar c <?> msg) *> walk cs
657−
658− caseChar :: Char -> ParserT String m Char
659− caseChar c | isAlpha c = char (Unicode.toLower c) <|> char (Unicode.toUpper c)
660− | otherwise = char c
661−
662− msg :: String
663− msg = show name
664−
665−
666− identifier :: ParserT String m String
667− identifier = lexeme $ try go
668− where
669− go :: ParserT String m String
670− go = do
671− name <- ident
672− if (isReservedName (LanguageDef languageDef) name)
673− then fail ("reserved word " <> show name)
674− else pure name
675−
676−
677− ident :: ParserT String m String
678− ident = go <?> "identifier"
679− where
680− go :: ParserT String m String
681− go = do
682− c <- languageDef.identStart
683− cs <- Array.many languageDef.identLetter
684− pure $ SCU.singleton c <> SCU.fromCharArray cs
685−
686−
687− -----------------------------------------------------------
688− -- White space & symbols
689− -----------------------------------------------------------
690− symbol :: String -> ParserT String m String
691− symbol name = lexeme (string name) $> name
692−
693− lexeme :: forall a . ParserT String m a -> ParserT String m a
694− lexeme p = p <* whiteSpace' (LanguageDef languageDef)
695−
696−
697−-- ================================================================================ --
698−-- The following functions should really be in the where-clause of makeTokenParser, --
699−-- but they can't go there because they are mutually recursive. --
700−-- ================================================================================ --
701−
702−-----------------------------------------------------------
703−-- Identifiers & Reserved words
704−-----------------------------------------------------------
705−
706−isReservedName :: forall m . Monad m => GenLanguageDef String m -> String -> Boolean
707−isReservedName langDef@(LanguageDef languageDef) name =
708− isReserved (theReservedNames langDef) caseName
709− where
710− caseName | languageDef.caseSensitive = name
711− | otherwise = toLower name
712−
713−isReserved :: Array String -> String -> Boolean
714−isReserved names name =
715− case Array.uncons names of
716− Nothing -> false
717− Just { head: r, tail: rs } -> case (compare r name) of
718− LT -> isReserved rs name
719− EQ -> true
720− GT -> false
721−
722−theReservedNames :: forall m . Monad m => GenLanguageDef String m -> Array String
723−theReservedNames (LanguageDef languageDef)
724− | languageDef.caseSensitive = Array.sort languageDef.reservedNames
725− | otherwise = Array.sort $ map toLower languageDef.reservedNames
726−
727−-----------------------------------------------------------
728−-- White space & symbols
729−-----------------------------------------------------------
730−
731−whiteSpace' :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
732−whiteSpace' langDef@(LanguageDef languageDef)
733− | null languageDef.commentLine && null languageDef.commentStart =
734− skipMany (simpleSpace <?> "")
735− | null languageDef.commentLine =
736− skipMany (simpleSpace <|> multiLineComment langDef <?> "")
737− | null languageDef.commentStart =
738− skipMany (simpleSpace <|> oneLineComment langDef <?> "")
739− | otherwise =
740− skipMany (simpleSpace <|> oneLineComment langDef <|> multiLineComment langDef <?> "")
741−
742−simpleSpace :: forall m . Monad m => ParserT String m Unit
743−simpleSpace = skipMany1 (satisfy isSpace)
744−
745−oneLineComment :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
746−oneLineComment (LanguageDef languageDef) =
747− try (string languageDef.commentLine) *> skipMany (satisfy (_ /= '\n'))
748−
749−multiLineComment :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
750−multiLineComment langDef@(LanguageDef languageDef) =
751− try (string languageDef.commentStart) *> inComment langDef
752−
753−inComment :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
754−inComment langDef@(LanguageDef languageDef) =
755− if languageDef.nestedComments then inCommentMulti langDef else inCommentSingle langDef
756−
757−inCommentMulti :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
758−inCommentMulti langDef@(LanguageDef languageDef) =
759− fix \p -> ( void $ try (string languageDef.commentEnd) )
760− <|> ( multiLineComment langDef *> p )
761− <|> ( skipMany1 (noneOf startEnd) *> p )
762− <|> ( oneOf startEnd *> p )
763− <?> "end of comment"
764− where
765− startEnd :: Array Char
766− startEnd = SCU.toCharArray languageDef.commentEnd <> SCU.toCharArray languageDef.commentStart
767−
768−inCommentSingle :: forall m . Monad m => GenLanguageDef String m -> ParserT String m Unit
769−inCommentSingle (LanguageDef languageDef) =
770− fix \p -> ( void $ try (string languageDef.commentEnd) )
771− <|> ( skipMany1 (noneOf startEnd) *> p )
772− <|> ( oneOf startEnd *> p )
773− <?> "end of comment"
774− where
775− startEnd :: Array Char
776− startEnd = SCU.toCharArray languageDef.commentEnd <> SCU.toCharArray languageDef.commentStart
777−
778−-------------------------------------------------------------------------
779−-- Helper functions that should maybe go in Text.Parsing.Parser.String --
780−-------------------------------------------------------------------------
781−
782−-- | Parse a digit. Matches any char that satisfies `Data.Char.Unicode.isDigit`.
783−digit :: forall m . Monad m => ParserT String m Char
784−digit = satisfy isDigit <?> "digit"
785−
786−-- | Parse a hex digit. Matches any char that satisfies `Data.Char.Unicode.isHexDigit`.
787−hexDigit :: forall m . Monad m => ParserT String m Char
788−hexDigit = satisfy isHexDigit <?> "hex digit"
789−
790−-- | Parse an octal digit. Matches any char that satisfies `Data.Char.Unicode.isOctDigit`.
791−octDigit :: forall m . Monad m => ParserT String m Char
792−octDigit = satisfy isOctDigit <?> "oct digit"
793−
794−-- | Parse an uppercase letter. Matches any char that satisfies `Data.Char.Unicode.isUpper`.
795−upper :: forall m . Monad m => ParserT String m Char
796−upper = satisfy isUpper <?> "uppercase letter"
797−
798−-- | Parse a space character. Matches any char that satisfies `Data.Char.Unicode.isSpace`.
799−space :: forall m . Monad m => ParserT String m Char
800−space = satisfy isSpace <?> "space"
801−
802−-- | Parse an alphabetical character. Matches any char that satisfies `Data.Char.Unicode.isAlpha`.
803−letter :: forall m . Monad m => ParserT String m Char
804−letter = satisfy isAlpha <?> "letter"
805−
806−-- | Parse an alphabetical or numerical character.
807−-- | Matches any char that satisfies `Data.Char.Unicode.isAlphaNum`.
808−alphaNum :: forall m . Monad m => ParserT String m Char
809−alphaNum = satisfy isAlphaNum <?> "letter or digit"
test/Main.purs+28−486
@@ -1,14 +1,9 @@
11module Test.Main where
22
3−import Prelude hiding (between,when)
3+import Prelude
44
5−import Control.Alt ((<|>))
6−import Control.Lazy (fix)
7−import Data.Array (some)
85import Data.Either (Either(..))
9−import Data.List (List(..), fromFoldable, many)
10−import Data.Maybe (Maybe(..))
11−import Data.String.CodeUnits (fromCharArray, singleton)
6+import Data.List (fromFoldable)
127import Data.Traversable(for_)
138import Data.Tuple (Tuple(..))
149import Data.UInt (fromInt)
@@ -16,32 +11,13 @@ import Effect (Effect)
1611import Effect.Console (logShow)
1712import Control.Monad.Trans.Class (lift)
1813import Test.Assert (assert')
19−import Text.Parsing.Parser (Parser, ParserT, runParser, runParserT, parseErrorPosition, fail)
20−import Text.Parsing.Parser.Combinators (endBy1, sepBy1, optionMaybe, try, chainl, between, manyTill)
21−import Text.Parsing.Parser.Expr (Assoc(..), Operator(..), buildExprParser)
22−import Text.Parsing.Parser.Language (javaStyle, haskellStyle, haskellDef)
23−import Text.Parsing.Parser.Pos (Position(..), initialPos)
24−import Text.Parsing.Parser.String (eof, string, char, satisfy, anyChar)
25−import Text.Parsing.Parser.Token (TokenParser, match, when, token, makeTokenParser)
14+import Text.Parsing.Parser (ParserT, runParserT, parseErrorPosition, fail)
15+import Text.Parsing.Parser.Combinators (manyTill)
16+import Text.Parsing.Parser.Pos (Position(..))
2617import Data.ArrayBuffer.ArrayBuffer (empty) as AB
2718import Data.ArrayBuffer.DataView (setInt8, whole) as AB
2819import Text.Parsing.Parser.DataView as DV
2920
30−parens :: forall m a. Monad m => ParserT String m a -> ParserT String m a
31−parens = between (string "(") (string ")")
32−
33−nested :: forall m. Monad m => ParserT String m Int
34−nested = fix \p -> (do
35− _ <- string "a"
36− pure 0) <|> ((+) 1) <$> parens p
37−
38−parseTest :: forall s a. Show a => Eq a => s -> a -> Parser s a -> Effect Unit
39−parseTest input expected p = case runParser input p of
40− Right actual -> do
41− assert' ("expected: " <> show expected <> ", actual: " <> show actual) (expected == actual)
42− logShow actual
43− Left err -> assert' ("error: " <> show err) false
44−
4521parseTestT :: forall s a. Show a => Eq a => s -> a -> ParserT s Effect a -> Effect Unit
4622parseTestT input expected p = do
4723 result <- runParserT input p
@@ -51,16 +27,8 @@ parseTestT input expected p = do
5127 logShow actual
5228 Left err -> assert' (show err) false
5329
54−parseErrorTestPosition :: forall s a. Show a => Parser s a -> s -> Position -> Effect Unit
55−parseErrorTestPosition p input expected = case runParser input p of
56− Right _ -> assert' "error: ParseError expected!" false
57− Left err -> do
58− let pos = parseErrorPosition err
59− assert' ("expected: " <> show expected <> ", pos: " <> show pos) (expected == pos)
60− logShow expected
61−
62−parseFailTestPositionT :: forall s a. s -> Position -> ParserT s Effect a -> Effect Unit
63−parseFailTestPositionT input failPos p = do
30+parseFailT :: forall s a. s -> Position -> ParserT s Effect a -> Effect Unit
31+parseFailT input failPos p = do
6432 result <- runParserT input p
6533 case result of
6634 Right _ -> assert' ("ParseError expected at " <> show failPos) false
@@ -70,501 +38,74 @@ parseFailTestPositionT input failPos p = do
7038 (pos == failPos)
7139 logShow $ show failPos
7240
73−opTest :: Parser String String
74−opTest = chainl (singleton <$> anyChar) (char '+' $> append) ""
75−
76−digit :: Parser String Int
77−digit = (string "0" >>= \_ -> pure 0)
78− <|> (string "1" >>= \_ -> pure 1)
79− <|> (string "2" >>= \_ -> pure 2)
80− <|> (string "3" >>= \_ -> pure 3)
81− <|> (string "4" >>= \_ -> pure 4)
82− <|> (string "5" >>= \_ -> pure 5)
83− <|> (string "6" >>= \_ -> pure 6)
84− <|> (string "7" >>= \_ -> pure 7)
85− <|> (string "8" >>= \_ -> pure 8)
86− <|> (string "9" >>= \_ -> pure 9)
87−
88−exprTest :: Parser String Int
89−exprTest = buildExprParser [ [ Infix (string "/" >>= \_ -> pure (/)) AssocRight ]
90− , [ Infix (string "*" >>= \_ -> pure (*)) AssocRight ]
91− , [ Infix (string "-" >>= \_ -> pure (-)) AssocRight ]
92− , [ Infix (string "+" >>= \_ -> pure (+)) AssocRight ]
93− ] digit
94−
95−
96−manySatisfyTest :: Parser String String
97−manySatisfyTest = do
98− r <- some $ satisfy (\s -> s /= '?')
99− _ <- char '?'
100− pure (fromCharArray r)
101−
102−data TestToken = A | B
103−
104−instance showTestTokens :: Show TestToken where
105− show A = "A"
106− show B = "B"
107−
108−instance testTokensEq :: Eq TestToken where
109− eq A A = true
110− eq B B = true
111− eq _ _ = false
112−
113−isA :: TestToken -> Boolean
114−isA A = true
115−isA _ = false
116−
117−testTokenParser :: TokenParser
118−testTokenParser = makeTokenParser haskellDef
119−
12041mkPos :: Int -> Position
12142mkPos n = mkPos' n 1
12243
12344mkPos' :: Int -> Int -> Position
12445mkPos' column line = Position { column: column, line: line }
12546
126−type TestM = Effect Unit
127−
128−tokenParserIdentifierTest :: TestM
129−tokenParserIdentifierTest = do
130− -- parse normal identifier
131− parseTest "hello" "hello" testTokenParser.identifier
132−
133− -- error on reserved words
134− parseErrorTestPosition testTokenParser.identifier "let" $ mkPos 4
135−
136− -- parse whitespace after identifier
137− parseTest "hello twice " "twice" (testTokenParser.identifier *> testTokenParser.identifier)
138−
139− -- can't start identifiers with numbers
140− parseErrorTestPosition testTokenParser.identifier "3hello" $ mkPos 1
141−
142− -- but numbers can be in the identifier
143− parseTest "h3ll0 " "h3ll0" testTokenParser.identifier
144−
145− -- comments count as whitespace
146− parseTest "h3ll0 -- this is a comment\nbye {- this is another comment -}" (Tuple "h3ll0" "bye")
147− (Tuple <$> testTokenParser.identifier <*> testTokenParser.identifier)
148−
149− -- multiline comments work well
150− parseTest "hello {- this \nis a comment -} bye" (Tuple "hello" "bye")
151− (Tuple <$> testTokenParser.identifier <*> testTokenParser.identifier)
152−
153− -- nested comments are okay
154− parseTest "hello {- this {- \nis a comment -} foo -} bye" (Tuple "hello" "bye")
155− (Tuple <$> testTokenParser.identifier <*> testTokenParser.identifier)
156−
157− -- fail on non-matching comments
158− parseErrorTestPosition testTokenParser.identifier "hello {-" $ mkPos 9
159−
160−
161−tokenParserReservedTest :: TestM
162−tokenParserReservedTest = do
163− -- parse reserved identifier
164− parseTest "forall" unit $ testTokenParser.reserved "forall"
165−
166− -- fail on nonmatching reserved identifier
167− parseErrorTestPosition (testTokenParser.reserved "forall") "forall3" $ mkPos 7
168−
169− -- fail on nonmatching reserved identifier
170− parseErrorTestPosition (testTokenParser.reserved "forall") "forall3" $ mkPos 7
171−
172−tokenParserOperatorTest :: TestM
173−tokenParserOperatorTest = do
174− -- parse operator
175− parseTest "<>" "<>" testTokenParser.operator
176−
177− -- fail on nonoperator
178− parseErrorTestPosition testTokenParser.operator "foo" $ mkPos 1
179−
180− -- fail on reserved operator
181− parseErrorTestPosition testTokenParser.operator "=" $ mkPos 2
182−
183−-- TODO
184−tokenParserReservedOpTest :: TestM
185−tokenParserReservedOpTest = pure unit
186−
187−tokenParserCharLiteralTest :: TestM
188−tokenParserCharLiteralTest = do
189− -- parse char literal
190− parseTest "'c'" 'c' testTokenParser.charLiteral
191−
192− -- fail on slash
193− parseErrorTestPosition testTokenParser.charLiteral "'\'" $ mkPos 2
194−
195− -- parse escape code
196− parseTest "'\\n'" '\n' testTokenParser.charLiteral
197−
198− -- parse oct number
199− parseTest "'\\o101'" 'A' testTokenParser.charLiteral
200−
201− -- parse hex number
202− parseTest "'\\x41'" 'A' testTokenParser.charLiteral
203−
204− -- fail on bad oct
205− parseErrorTestPosition testTokenParser.charLiteral "'\\o389'" $ mkPos 5
206−
207− -- parse ascii
208− parseTest "'\\^I'" '\t' testTokenParser.charLiteral
209−
210−tokenParserStringLiteralTest :: TestM
211−tokenParserStringLiteralTest = do
212− -- parse string char
213− parseTest "\"hello\"" "hello" testTokenParser.stringLiteral
214−
215− -- fail on non-operator
216− parseErrorTestPosition testTokenParser.stringLiteral "he\"llo" $ mkPos 1
217−
218− -- parse string gap
219− parseTest "\"he\\ \\llo\"" "hello" testTokenParser.stringLiteral
220−
221− -- parse string empty
222− parseTest "\"he\\&llo\"" "hello" testTokenParser.stringLiteral
223−
224− -- parse string escape
225− parseTest "\"he\\nllo\"" "he\nllo" testTokenParser.stringLiteral
226−
227−tokenParserNaturalTest :: TestM
228−tokenParserNaturalTest = do
229− -- parse natural
230− parseTest "1" 1 testTokenParser.natural
231−
232− -- parse hex natural
233− parseTest "0xFF" 255 testTokenParser.natural
234−
235− -- parse oct natural
236− parseTest "0o10 " 8 testTokenParser.natural
237−
238− -- fail on nonoct
239− parseErrorTestPosition testTokenParser.natural "0o8" $ mkPos 3
240−
241− -- fail on no digits
242− parseErrorTestPosition testTokenParser.natural "0o" $ mkPos 3
243−
244−tokenParserIntegerTest :: TestM
245−tokenParserIntegerTest = do
246− -- parse integer
247− parseTest "100" 100 testTokenParser.integer
248−
249− -- parse plus
250− parseTest "+200" 200 testTokenParser.integer
251−
252− -- parse minus
253− parseTest "- 100" (-100) testTokenParser.integer
254−
255−tokenParserFloatTest :: TestM
256−tokenParserFloatTest = do
257− -- parse float
258− parseTest "100.5" 100.5 testTokenParser.float
259−
260− -- parse float with exponent
261− parseTest "100e1" 1000.0 testTokenParser.float
262−
263− -- parse float with exponent
264− parseTest "100.5e1" 1005.0 testTokenParser.float
265−
266− -- fail on nonfloat
267− parseErrorTestPosition testTokenParser.float "100.e1" $ mkPos 5
268−
269−-- TODO
270−tokenParserNaturalOrFloatTest :: TestM
271−tokenParserNaturalOrFloatTest = do
272− pure unit
273−
274−tokenParserDecimalTest :: TestM
275−tokenParserDecimalTest = do
276− -- parse decimal
277− parseTest "0202" 202 testTokenParser.decimal
278−
279− -- fail on nondecimal
280− parseErrorTestPosition testTokenParser.decimal "foo" $ mkPos 1
281−
282−-- TODO
283−tokenParserHexadecimalTest :: TestM
284−tokenParserHexadecimalTest = do
285− pure unit
286−
287−-- TODO
288−tokenParserOctalTest :: TestM
289−tokenParserOctalTest = do
290− pure unit
291−
292−tokenParserSymbolTest :: TestM
293−tokenParserSymbolTest = do
294− -- parse symbol
295− parseTest "hello " "hello" $ testTokenParser.symbol "hello"
296−
297−-- TODO
298−tokenParserLexemeTest :: TestM
299−tokenParserLexemeTest = do
300− pure unit
301−
302−-- TODO
303−tokenParserWhiteSpaceTest :: TestM
304−tokenParserWhiteSpaceTest = do
305− pure unit
306−
307−tokenParserParensTest :: TestM
308−tokenParserParensTest = do
309− -- parse parens
310− parseTest "(hello)" "hello" $ testTokenParser.parens $ string "hello"
311−
312− -- fail on non-closed parens
313− parseErrorTestPosition (testTokenParser.parens $ string "hello") "(hello" $ mkPos 7
314−
315−tokenParserBracesTest :: TestM
316−tokenParserBracesTest = do
317− -- parse braces
318− parseTest "{hello}" "hello" $ testTokenParser.braces $ string "hello"
319−
320− -- fail on non-closed braces
321− parseErrorTestPosition (testTokenParser.braces $ string "hello") "{hello" $ mkPos 7
322−
323−tokenParserAnglesTest :: TestM
324−tokenParserAnglesTest = do
325− -- parse angles
326− parseTest "<hello>" "hello" $ testTokenParser.angles $ string "hello"
327−
328− -- fail on non-closed angles
329− parseErrorTestPosition (testTokenParser.angles $ string "hello") "<hello" $ mkPos 7
330−
331−tokenParserBracketsTest :: TestM
332−tokenParserBracketsTest = do
333− -- parse brackets
334− parseTest "[hello]" "hello" $ testTokenParser.brackets $ string "hello"
335−
336− -- fail on non-closed brackets
337− parseErrorTestPosition (testTokenParser.brackets $ string "hello") "[hello" $ mkPos 7
338−
339−tokenParserSemiTest :: TestM
340−tokenParserSemiTest = do
341− -- parse semicolon
342− parseTest ";" ";" testTokenParser.semi
343−
344− -- fail on non-semicolon
345− parseErrorTestPosition testTokenParser.semi "a" $ mkPos 1
346−
347−tokenParserCommaTest :: TestM
348−tokenParserCommaTest = do
349− -- parse comma
350− parseTest "," "," testTokenParser.comma
351−
352− -- fail on non-comma
353− parseErrorTestPosition testTokenParser.comma "a" $ mkPos 1
354−
355−tokenParserColonTest :: TestM
356−tokenParserColonTest = do
357− -- parse colon
358− parseTest ":" ":" testTokenParser.colon
359−
360− -- fail on non-colon
361− parseErrorTestPosition testTokenParser.colon "a" $ mkPos 1
362−
363−tokenParserDotTest :: TestM
364−tokenParserDotTest = do
365− -- parse dot
366− parseTest "." "." testTokenParser.dot
367−
368− -- fail on non-dot
369− parseErrorTestPosition testTokenParser.dot "a" $ mkPos 1
370−
371−tokenParserSemiSepTest :: TestM
372−tokenParserSemiSepTest = do
373− -- parse semi sep
374− parseTest "foo; foo" (fromFoldable ["foo", "foo"]) $ testTokenParser.semiSep $ string "foo"
375−
376− -- parse semi sep with newline
377− parseTest "foo; \nfoo" (fromFoldable ["foo", "foo"]) $ testTokenParser.semiSep $ string "foo"
378−
379− -- parse no semi sep
380− parseTest "" (fromFoldable []) $ testTokenParser.semiSep $ string "foo"
381− -- parseErrorTestPosition testTokenParser.operator "foo" $ mkPos 1
382−
383−tokenParserSemiSep1Test :: TestM
384−tokenParserSemiSep1Test = do
385− -- parse semi sep1
386− parseTest "foo; foo" (fromFoldable ["foo", "foo"]) $ testTokenParser.semiSep1 $ string "foo"
387−
388− -- parse semi sep1 with newline
389− parseTest "foo; \nfoo" (fromFoldable ["foo", "foo"]) $ testTokenParser.semiSep1 $ string "foo"
390−
391− -- no parse on empty string
392− parseErrorTestPosition (testTokenParser.semiSep1 $ string "foo") "" $ mkPos 1
393−
394−tokenParserCommaSepTest :: TestM
395−tokenParserCommaSepTest = do
396− -- parse comma sep
397− parseTest "foo, foo" (fromFoldable ["foo", "foo"]) $ testTokenParser.commaSep $ string "foo"
398−
399− -- parse comma sep with newline
400− parseTest "foo, \nfoo" (fromFoldable ["foo", "foo"]) $ testTokenParser.commaSep $ string "foo"
401−
402− -- parse no comma sep
403− parseTest "" (fromFoldable []) $ testTokenParser.commaSep $ string "foo"
404−
405−tokenParserCommaSep1Test :: TestM
406−tokenParserCommaSep1Test = do
407− -- parse comma sep1
408− parseTest "foo, foo" (fromFoldable ["foo", "foo"]) $ testTokenParser.commaSep1 $ string "foo"
409−
410− -- parse comma sep1 with newline
411− parseTest "foo, \nfoo" (fromFoldable ["foo", "foo"]) $ testTokenParser.commaSep1 $ string "foo"
412−
413− -- no parse on empty string
414− parseErrorTestPosition (testTokenParser.commaSep1 $ string "foo") "" $ mkPos 1
415−
416−haskellStyleTest :: TestM
417−haskellStyleTest = do
418− let haskellTokParser = makeTokenParser haskellStyle
419−
420− -- make sure haskell-style comments work
421− parseTest "hello {- comment\n -} fo_" "fo_" $ haskellTokParser.identifier *> haskellTokParser.identifier
422−
423− -- make sure java-style comments do not work
424− parseErrorTestPosition
425− (haskellTokParser.identifier *> haskellTokParser.identifier)
426− "hello /* comment\n */ foo"
427− (mkPos 7)
428−
429−javaStyleTest :: TestM
430−javaStyleTest = do
431− let javaTokParser = makeTokenParser javaStyle
432− -- make sure java-style comments work
433− parseTest "hello /* comment\n */ fo_" "fo_" $ javaTokParser.identifier *> javaTokParser.identifier
434−
435− -- make sure java-style identifier work
436− parseTest "$hello /* comment\n */ _f$o_" "_f$o_" $ javaTokParser.identifier *> javaTokParser.identifier
437−
438− -- make sure haskell-style comments do not work
439− parseErrorTestPosition
440− (javaTokParser.identifier *> javaTokParser.identifier)
441− "hello {- comment\n -} foo"
442− (mkPos 7)
44347
44448main :: Effect Unit
44549main = do
44650
447− parseErrorTestPosition
448− (many $ char 'f' *> char '?')
449− "foo"
450− (Position { column: 2, line: 1 })
451−
452− parseErrorTestPosition
453− (satisfy (_ == '?'))
454− "foo"
455− (Position { column: 1, line: 1 })
456−
457− parseTest
458− "foo"
459− Nil
460− (many $ try $ char 'f' *> char '?')
461−
462− parseTest "(((a)))" 3 nested
463− parseTest "aaa" (Cons "a" (Cons "a" (Cons "a" Nil))) $ many (string "a")
464− parseTest "(ab)" (Just "b") $ parens do
465− _ <- string "a"
466− optionMaybe $ string "b"
467− parseTest "a,a,a" (Cons "a" (Cons "a" (Cons "a" Nil))) $ string "a" `sepBy1` string ","
468− parseTest "a,a,a," (Cons "a" (Cons "a" (Cons "a" Nil))) $ do
469− as <- string "a" `endBy1` string ","
470− eof
471− pure as
472− parseTest "a+b+c" "abc" opTest
473− parseTest "1*2+3/4-5" (-3) exprTest
474− parseTest "ab?" "ab" manySatisfyTest
475− parseTest "aaab" (fromFoldable ['a','a','a']) $ manyTill (char 'a') (char 'b')
476−
477− let tokpos = const initialPos
478− parseTest (fromFoldable [A, B]) A (token tokpos)
479− parseTest (fromFoldable [B, A]) B (token tokpos)
480−
481− parseTest (fromFoldable [A, B]) A (when tokpos isA)
482−
483− parseTest (fromFoldable [A]) A (match tokpos A)
484− parseTest (fromFoldable [B]) B (match tokpos B)
485− parseTest (fromFoldable [A, B]) A (match tokpos A)
486−
487− parseErrorTestPosition (string "abc") "bcd" (Position { column: 1, line: 1 })
488− parseErrorTestPosition (string "abc" *> eof) "abcdefg" (Position { column: 4, line: 1 })
489− parseErrorTestPosition (string "a\nb\nc\n" *> eof) "a\nb\nc\nd\n" (Position { column: 1, line: 4 })
490− parseErrorTestPosition (string "\ta" *> eof) "\tab" (Position { column: 10, line: 1 })
491−
492− tokenParserIdentifierTest
493− tokenParserReservedTest
494− tokenParserOperatorTest
495− tokenParserReservedOpTest
496−
497− tokenParserCharLiteralTest
498− tokenParserStringLiteralTest
499− tokenParserNaturalTest
500− tokenParserIntegerTest
501− tokenParserFloatTest
502− tokenParserNaturalOrFloatTest
503− tokenParserDecimalTest
504− tokenParserHexadecimalTest
505− tokenParserOctalTest
506−
507− tokenParserSymbolTest
508− tokenParserLexemeTest
509− tokenParserWhiteSpaceTest
510−
511− tokenParserParensTest
512− tokenParserBracesTest
513− tokenParserAnglesTest
514− tokenParserBracketsTest
515− tokenParserSemiTest
516− tokenParserCommaTest
517− tokenParserColonTest
518− tokenParserDotTest
519− tokenParserSemiSepTest
520− tokenParserSemiSep1Test
521− tokenParserCommaSepTest
522− tokenParserCommaSep1Test
523−
524− haskellStyleTest
525− javaStyleTest
526−
51+ -- Test input DataView = [5,6,7,8,9]
52752 ab <- AB.empty 5
52853 let dv = AB.whole ab
52954 for_ [0,1,2,3,4] $ \i -> AB.setInt8 dv i (i+5)
55+ -- anyInt8
53056 parseTestT dv 5 DV.anyInt8
57+ -- manyTill eof
53158 parseTestT dv (fromFoldable [5,6,7,8,9]) $ manyTill DV.anyInt8 DV.eof
59+ -- manyTill satisfy
53260 parseTestT dv (fromFoldable [5,6,7,8]) $ manyTill DV.anyInt8 (DV.satisfyInt8 (_ == 9))
61+ -- anyInt16be
53362 parseTestT dv 0x0506 DV.anyInt16be
63+ -- anyInt16le
53464 parseTestT dv 0x0605 DV.anyInt16le
65+ -- anyUint16be
53566 parseTestT dv (fromInt 0x0506) DV.anyUint16be
67+ -- anyUint16le
53668 parseTestT dv (fromInt 0x0605) DV.anyUint16le
537− parseFailTestPositionT dv (mkPos 5) $ DV.anyInt16le *> DV.anyInt16le *> DV.anyInt16le
69+ -- fail on anyInt16le past end of DataView
70+ parseFailT dv (mkPos 5) $ DV.anyInt16le *> DV.anyInt16le *> DV.anyInt16le
71+ -- anyInt32be and anyInt8
53872 parseTestT dv (Tuple 0x05060708 0x09) $ do
53973 l <- DV.anyInt32be
54074 r <- DV.anyInt8
54175 DV.eof
54276 pure $ Tuple l r
77+ -- anyInt32le and anyInt8
54378 parseTestT dv (Tuple 0x08070605 0x09) $ do
54479 l <- DV.anyInt32le
54580 r <- DV.anyInt8
54681 DV.eof
54782 pure $ Tuple l r
83+ -- anyUint32be and anyInt8
54884 parseTestT dv (Tuple (fromInt 0x05060708) 0x09) $ do
54985 l <- DV.anyUint32be
55086 r <- DV.anyInt8
55187 DV.eof
55288 pure $ Tuple l r
89+ -- anyUint32le and anyInt8
55390 parseTestT dv (Tuple (fromInt 0x08070605) 0x09) $ do
55491 l <- DV.anyUint32le
55592 r <- DV.anyInt8
55693 DV.eof
55794 pure $ Tuple l r
95+ -- takeN
55896 parseTestT dv 0x0908 do
55997 _ <- DV.takeN 3
56098 DV.anyInt16le <* DV.eof
99+ -- takeRest then a new parse then anyInt16le
561100 parseTestT dv 0x0908 do
562101 _ <- DV.takeN 3
563102 remain <- DV.takeRest
564103 lift (runParserT remain DV.anyInt16le) >>= case _ of
565104 Right actual -> pure actual
566105 Left err -> fail $ show err
567− parseFailTestPositionT dv (mkPos 1) $ DV.takeN 6
106+ -- fail on takeN past end of DataView
107+ parseFailT dv (mkPos 1) $ DV.takeN 6
108+ -- takeRest then new parse on takeRest then anyInt8
568109 parseTestT dv 0x07 do
569110 _ <- DV.takeN 1
570111 DV.takeRest >>= \dv2 ->
@@ -573,7 +114,8 @@ main = do
573114 Right dv3 -> lift (runParserT dv3 $ DV.anyInt8) >>= case _ of
574115 Left err -> fail $ show err
575116 Right x -> pure x
576− parseFailTestPositionT dv (mkPos 2) $ do
117+ -- takeN then a new parse then fail on anyInt16le past end of DataView
118+ parseFailT dv (mkPos 2) $ do
577119 dv2 <- DV.takeN 1
578120 lift (runParserT dv2 DV.anyInt16le) >>= case _ of
579121 Left err -> fail $ show err