Skip to content

Introduce purs-tidy formatter #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:

- name: Set up a PureScript toolchain
uses: purescript-contrib/setup-purescript@main
with:
purs-tidy: "latest"

- name: Cache PureScript dependencies
uses: actions/cache@v2
Expand All @@ -32,3 +34,6 @@ jobs:

- name: Run tests
run: spago -x spago-dev.dhall test --no-install

- name: Check formatting
run: purs-tidy check src test bench
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
!.gitignore
!.github
!.editorconfig
!.tidyrc.json

output
generated-docs
Expand Down
10 changes: 10 additions & 0 deletions .tidyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"importSort": "source",
"importWrap": "source",
"indent": 2,
"operatorsFile": null,
"ribbon": 1,
"typeArrowPlacement": "first",
"unicode": "never",
"width": null
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ New features:
Bugfixes:

Other improvements:
- Added `purs-tidy` formatter (#126 by @thomashoneyman)

## [v7.0.1](https://github.com/purescript-contrib/purescript-parsing/releases/tag/v7.0.0) - 2021-11-17

Expand Down
42 changes: 24 additions & 18 deletions bench/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,19 @@ import Text.Parsing.StringParser.CodeUnits as StringParser.CodeUnits

string23 :: String
string23 = "23"

string23_2 :: String
string23_2 = fold $ replicate 2 string23

string23_10000 :: String
string23_10000 = fold $ replicate 10000 string23

stringSkidoo :: String
stringSkidoo = "skidoo"

stringSkidoo_2 :: String
stringSkidoo_2 = fold $ replicate 2 stringSkidoo

stringSkidoo_10000 :: String
stringSkidoo_10000 = fold $ replicate 10000 stringSkidoo

Expand All @@ -84,29 +88,31 @@ parse23Units :: StringParser.Parser (List Char)
parse23Units = manyRec StringParser.CodeUnits.anyDigit

pattern23 :: Regex
pattern23 = either (unsafePerformEffect <<< throw) identity $
regex "\\d" $ RegexFlags
{ dotAll: true
, global: true
, ignoreCase: false
, multiline: true
, sticky: false
, unicode: true
}
pattern23 = either (unsafePerformEffect <<< throw) identity
$ regex "\\d"
$ RegexFlags
{ dotAll: true
, global: true
, ignoreCase: false
, multiline: true
, sticky: false
, unicode: true
}

parseSkidoo :: Parser String (List String)
parseSkidoo = manyRec $ string "skidoo"

patternSkidoo :: Regex
patternSkidoo = either (unsafePerformEffect <<< throw) identity $
regex "skidoo" $ RegexFlags
{ dotAll: true
, global: true
, ignoreCase: false
, multiline: true
, sticky: false
, unicode: true
}
patternSkidoo = either (unsafePerformEffect <<< throw) identity
$ regex "skidoo"
$ RegexFlags
{ dotAll: true
, global: true
, ignoreCase: false
, multiline: true
, sticky: false
, unicode: true
}

main :: Effect Unit
main = do
Expand Down
24 changes: 14 additions & 10 deletions src/Text/Parsing/Parser.purs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import Prelude

import Control.Alt (class Alt)
import Control.Apply (lift2)
import Control.Lazy (defer, class Lazy)
import Control.Monad.Error.Class (class MonadThrow, throwError, catchError)
import Control.Monad.Except (class MonadError, ExceptT(..), runExceptT, mapExceptT)
import Control.Lazy (class Lazy, defer)
import Control.Monad.Error.Class (class MonadThrow, catchError, throwError)
import Control.Monad.Except (class MonadError, ExceptT(..), mapExceptT, runExceptT)
import Control.Monad.Rec.Class (class MonadRec)
import Control.Monad.State (class MonadState, StateT(..), evalStateT, gets, mapStateT, modify_, runStateT)
import Control.Monad.Trans.Class (class MonadTrans, lift)
import Control.MonadPlus (class Alternative, class MonadZero, class MonadPlus, class Plus)
import Control.MonadPlus (class Alternative, class MonadPlus, class MonadZero, class Plus)
import Data.Either (Either(..))
import Data.Identity (Identity)
import Data.Newtype (class Newtype, unwrap, over)
import Data.Newtype (class Newtype, over, unwrap)
import Data.Tuple (Tuple(..))
import Text.Parsing.Parser.Pos (Position, initialPos)

Expand Down Expand Up @@ -62,7 +62,8 @@ derive instance newtypeParserT :: Newtype (ParserT s m a) _

-- | Apply a parser, keeping only the parsed result.
runParserT :: forall m s a. Monad m => s -> ParserT s m a -> m (Either ParseError a)
runParserT s p = evalStateT (runExceptT (unwrap p)) initialState where
runParserT s p = evalStateT (runExceptT (unwrap p)) initialState
where
initialState = ParseState s initialPos false

-- | The `Parser` monad is a synonym for the parser monad transformer applied to the `Identity` monad.
Expand All @@ -76,10 +77,13 @@ hoistParserT :: forall s m n a. (m ~> n) -> ParserT s m a -> ParserT s n a
hoistParserT = mapParserT

-- | Change the underlying monad action and data type in a ParserT monad action.
mapParserT :: forall b n s a m.
( m (Tuple (Either ParseError a) (ParseState s))
-> n (Tuple (Either ParseError b) (ParseState s))
) -> ParserT s m a -> ParserT s n b
mapParserT
:: forall b n s a m
. ( m (Tuple (Either ParseError a) (ParseState s))
-> n (Tuple (Either ParseError b) (ParseState s))
)
-> ParserT s m a
-> ParserT s n b
mapParserT = over ParserT <<< mapExceptT <<< mapStateT

instance lazyParserT :: Lazy (ParserT s m a) where
Expand Down
36 changes: 22 additions & 14 deletions src/Text/Parsing/Parser/Combinators.purs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module Text.Parsing.Parser.Combinators where

import Prelude

import Control.Monad.Except (runExceptT, ExceptT(..))
import Control.Monad.Except (ExceptT(..), runExceptT)
import Control.Monad.State (StateT(..), runStateT)
import Control.Plus (empty, (<|>))
import Data.Either (Either(..))
Expand All @@ -35,7 +35,7 @@ import Data.List.NonEmpty as NEL
import Data.Maybe (Maybe(..))
import Data.Newtype (unwrap)
import Data.Tuple (Tuple(..))
import Text.Parsing.Parser (ParseState(..), ParserT(..), ParseError(..), fail)
import Text.Parsing.Parser (ParseError(..), ParseState(..), ParserT(..), fail)

-- | Provide an error message in the case of failure.
withErrorMessage :: forall m s a. Monad m => ParserT s m a -> String -> ParserT s m a
Expand Down Expand Up @@ -122,9 +122,11 @@ sepEndBy p sep = map NEL.toList (sepEndBy1 p sep) <|> pure Nil
sepEndBy1 :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
sepEndBy1 p sep = do
a <- p
(do _ <- sep
( do
_ <- sep
as <- sepEndBy p sep
pure (NEL.cons' a as)) <|> pure (NEL.singleton a)
pure (NEL.cons' a as)
) <|> pure (NEL.singleton a)

-- | Parse phrases delimited and terminated by a separator, requiring at least one match.
endBy1 :: forall m s a sep. Monad m => ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
Expand Down Expand Up @@ -155,9 +157,12 @@ chainl1 p f = do
chainl1' p f a

chainl1' :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
chainl1' p f a = (do f' <- f
a' <- p
chainl1' p f (f' a a')) <|> pure a
chainl1' p f a =
( do
f' <- f
a' <- p
chainl1' p f (f' a a')
) <|> pure a

-- | Parse phrases delimited by a right-associative operator, requiring at least one match.
chainr1 :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
Expand All @@ -166,9 +171,12 @@ chainr1 p f = do
chainr1' p f a

chainr1' :: forall m s a. Monad m => ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
chainr1' p f a = (do f' <- f
a' <- chainr1 p f
pure $ f' a a') <|> pure a
chainr1' p f a =
( do
f' <- f
a' <- chainr1 p f
pure $ f' a a'
) <|> pure a

-- | Parse one of a set of alternatives.
choice :: forall f m s a. Foldable f => Monad m => f (ParserT s m a) -> ParserT s m a
Expand All @@ -193,10 +201,10 @@ notFollowedBy p = try $ (try p *> fail "Negated parser succeeded") <|> pure unit
manyTill :: forall s a m e. Monad m => ParserT s m a -> ParserT s m e -> ParserT s m (List a)
manyTill p end = scan
where
scan = (end $> Nil)
<|> do x <- p
xs <- scan
pure (x : xs)
scan = (end $> Nil) <|> do
x <- p
xs <- scan
pure (x : xs)

-- | Parse several phrases until the specified terminator matches, requiring at least one match.
many1Till :: forall s a m e. Monad m => ParserT s m a -> ParserT s m e -> ParserT s m (NonEmptyList a)
Expand Down
61 changes: 33 additions & 28 deletions src/Text/Parsing/Parser/Expr.purs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,27 @@ module Text.Parsing.Parser.Expr
import Prelude hiding (between)

import Control.Alt ((<|>))
import Data.Foldable (foldr, foldl)
import Data.Foldable (foldl, foldr)
import Data.List (List(..), (:))
import Text.Parsing.Parser (ParserT)
import Text.Parsing.Parser.Combinators (choice, (<?>))

data Assoc = AssocNone | AssocLeft | AssocRight

data Operator m s a = Infix (ParserT s m (a -> a -> a)) Assoc
| Prefix (ParserT s m (a -> a))
| Postfix (ParserT s m (a -> a))
data Operator m s a
= Infix (ParserT s m (a -> a -> a)) Assoc
| Prefix (ParserT s m (a -> a))
| Postfix (ParserT s m (a -> a))

type OperatorTable m s a = Array (Array (Operator m s a))

type SplitAccum m s a = { rassoc :: List (ParserT s m (a -> a -> a))
, lassoc :: List (ParserT s m (a -> a -> a))
, nassoc :: List (ParserT s m (a -> a -> a))
, prefix :: List (ParserT s m (a -> a))
, postfix :: List (ParserT s m (a -> a)) }
type SplitAccum m s a =
{ rassoc :: List (ParserT s m (a -> a -> a))
, lassoc :: List (ParserT s m (a -> a -> a))
, nassoc :: List (ParserT s m (a -> a -> a))
, prefix :: List (ParserT s m (a -> a))
, postfix :: List (ParserT s m (a -> a))
}

-- | Build a parser from an `OperatorTable`.
-- |
Expand All @@ -50,28 +53,30 @@ makeParser term ops = do
<|> pure x
<?> "operator"
where
accum = foldr splitOp { rassoc: Nil
, lassoc: Nil
, nassoc: Nil
, prefix: Nil
, postfix: Nil
} ops

rassocOp = choice accum.rassoc
lassocOp = choice accum.lassoc
nassocOp = choice accum.nassoc
prefixOp = choice accum.prefix <?> ""
accum = foldr splitOp
{ rassoc: Nil
, lassoc: Nil
, nassoc: Nil
, prefix: Nil
, postfix: Nil
}
ops

rassocOp = choice accum.rassoc
lassocOp = choice accum.lassoc
nassocOp = choice accum.nassoc
prefixOp = choice accum.prefix <?> ""
postfixOp = choice accum.postfix <?> ""

postfixP = postfixOp <|> pure identity
prefixP = prefixOp <|> pure identity

splitOp :: forall m s a. Operator m s a -> SplitAccum m s a -> SplitAccum m s a
splitOp (Infix op AssocNone) accum = accum { nassoc = op : accum.nassoc }
splitOp (Infix op AssocLeft) accum = accum { lassoc = op : accum.lassoc }
splitOp (Infix op AssocRight) accum = accum { rassoc = op : accum.rassoc }
splitOp (Prefix op) accum = accum { prefix = op : accum.prefix }
splitOp (Postfix op) accum = accum { postfix = op : accum.postfix }
splitOp (Infix op AssocNone) accum = accum { nassoc = op : accum.nassoc }
splitOp (Infix op AssocLeft) accum = accum { lassoc = op : accum.lassoc }
splitOp (Infix op AssocRight) accum = accum { rassoc = op : accum.rassoc }
splitOp (Prefix op) accum = accum { prefix = op : accum.prefix }
splitOp (Postfix op) accum = accum { postfix = op : accum.postfix }

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
rassocP x rassocOp prefixP term postfixP = do
Expand Down Expand Up @@ -101,7 +106,7 @@ nassocP x nassocOp prefixP term postfixP = do

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
termP prefixP term postfixP = do
pre <- prefixP
x <- term
post <- postfixP
pre <- prefixP
x <- term
post <- postfixP
pure (post (pre x))
Loading