Skip to content

Commit d644b8d

Browse files
committed
consumeWith doesn't consume if position does not advance
This will effect parsers: * rest * string * takeN * regex * whiteSpace * skipSpaces
1 parent 44ef16b commit d644b8d

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ Notable changes to this project are documented in this file. The format is based
44

55
## [Unreleased]
66

7+
Bugfixes:
8+
9+
- consumeWith doesn't consume if position does not advance (#201 by @jamesdbrock)
10+
11+
This will effect parsers:
12+
13+
* rest
14+
* string
15+
* takeN
16+
* regex
17+
* whiteSpace
18+
* skipSpaces
19+
20+
721
## [v9.1.0](https://github.com/purescript-contrib/purescript-parsing/releases/tag/v9.1.0) - 2022-06-12
822

923
Breaking changes:

src/Parsing/String.purs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ regex pattern flags =
283283
-- |
284284
-- | * `value` is the value to return.
285285
-- | * `consumed` is the input `String` that was consumed. It is used to update the parser position.
286+
-- | If the `consumed` `String` is non-empty then the `consumed` flag will
287+
-- | be set to true. (Confusing terminology.)
286288
-- | * `remainder` is the new remaining input `String`.
287289
-- |
288290
-- | This function is used internally to construct primitive `String` parsers.
@@ -296,7 +298,7 @@ consumeWith f = ParserT
296298
Left err ->
297299
runFn2 throw state1 (ParseError err pos)
298300
Right { value, consumed, remainder } ->
299-
runFn2 done (ParseState remainder (updatePosString pos consumed remainder) true) value
301+
runFn2 done (ParseState remainder (updatePosString pos consumed remainder) (not (String.null consumed))) value
300302
)
301303

302304
-- | Combinator which finds the first position in the input `String` where the

src/Parsing/String/Basic.purs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,17 @@ satisfyCP :: forall m. (CodePoint -> Boolean) -> ParserT String m Char
148148
satisfyCP p = satisfy (p <<< codePointFromChar)
149149

150150
-- | Match zero or more whitespace characters satisfying
151-
-- | `Data.CodePoint.Unicode.isSpace`. Always succeeds.
151+
-- | `Data.CodePoint.Unicode.isSpace`.
152+
-- |
153+
-- | Always succeeds. Will consume only when matched whitespace string
154+
-- | is non-empty.
152155
whiteSpace :: forall m. ParserT String m String
153156
whiteSpace = fst <$> match skipSpaces
154157

155-
-- | Skip whitespace characters and throw them away. Always succeeds.
158+
-- | Skip whitespace characters satisfying `Data.CodePoint.Unicode.isSpace`
159+
-- | and throw them away.
160+
-- |
161+
-- | Always succeeds. Will only consume when some characters are skipped.
156162
skipSpaces :: forall m. ParserT String m Unit
157163
skipSpaces = consumeWith \input -> do
158164
let consumed = takeWhile isSpace input

test/Main.purs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ import Effect (Effect)
3333
import Effect.Console (log, logShow)
3434
import Effect.Unsafe (unsafePerformEffect)
3535
import Node.Process (lookupEnv)
36-
import Parsing (ParseError(..), Parser, ParserT, Position(..), consume, fail, initialPos, parseErrorMessage, parseErrorPosition, position, region, runParser)
36+
import Parsing (ParseError(..), ParseState(..), Parser, ParserT, Position(..), consume, fail, getParserT, initialPos, parseErrorMessage, parseErrorPosition, position, region, runParser)
3737
import Parsing.Combinators (advance, between, chainl, chainl1, chainr, chainr1, choice, empty, endBy, endBy1, lookAhead, many, many1, many1Till, many1Till_, manyIndex, manyTill, manyTill_, notFollowedBy, optionMaybe, sepBy, sepBy1, sepEndBy, sepEndBy1, skipMany, skipMany1, try, (<?>), (<??>), (<~?>))
3838
import Parsing.Combinators.Array as Combinators.Array
3939
import Parsing.Expr (Assoc(..), Operator(..), buildExprParser)
4040
import Parsing.Language (haskellDef, haskellStyle, javaStyle)
4141
import Parsing.String (anyChar, anyCodePoint, anyTill, char, eof, match, regex, rest, satisfy, string, takeN)
42-
import Parsing.String.Basic (intDecimal, letter, noneOfCodePoints, number, oneOfCodePoints, whiteSpace)
42+
import Parsing.String.Basic (intDecimal, letter, noneOfCodePoints, number, oneOfCodePoints, skipSpaces, whiteSpace)
4343
import Parsing.String.Replace (breakCap, replace, replaceT, splitCap, splitCapT)
4444
import Parsing.Token (TokenParser, makeTokenParser, token, when)
4545
import Parsing.Token as Token
@@ -685,6 +685,22 @@ main = do
685685
parseErrorTestPosition (string "a\nb\nc\n" *> eof) "a\nb\nc\nd\n" (Position { index: 6, column: 1, line: 4 })
686686
parseErrorTestPosition (string "\ta" *> eof) "\tab" (Position { index: 2, column: 10, line: 1 })
687687

688+
assertEqual' "skipSpaces consumes if position advancement issue #200"
689+
{ actual: runParser " " do
690+
skipSpaces
691+
ParseState _ _ c <- getParserT
692+
pure c
693+
, expected: Right true
694+
}
695+
696+
assertEqual' "skipSpaces doesn't consume if no position advancement issue #200"
697+
{ actual: runParser "x" do
698+
skipSpaces
699+
ParseState _ _ c <- getParserT
700+
pure c
701+
, expected: Right false
702+
}
703+
688704
log "\nTESTS number\n"
689705

690706
-- assert' "Number.fromString" $ Just infinity == Data.Number.fromString "Infinity"

0 commit comments

Comments
 (0)