Skip to content
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

Fix reversed branches in parsnip's scan #10

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 9 additions & 2 deletions parsnip/parsnip.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.2
name: parsnip
version: 0
version: 0.0.0.1
synopsis: A fast, minimal parser
description:
A fast, minimal parser.
Expand Down Expand Up @@ -47,7 +47,7 @@ common base
c-sources: cbits/parsnip.c
build-depends:
attoparsec,
base >= 4.15 && < 5,
base >= 4.14.1.0 && < 5,
bytestring,
containers,
data-default,
Expand All @@ -67,3 +67,10 @@ library
Text.Parsnip.Internal.Parser
Text.Parsnip.Internal.Private
Text.Parsnip.Internal.Simple

test-suite spec
import: base
type: exitcode-stdio-1.0
hs-source-dirs: test
build-depends: parsnip >= 0.0.0.1, hspec, tasty, tasty-hspec
main-is: Spec.hs
12 changes: 6 additions & 6 deletions parsnip/src/Text/Parsnip/Char8.hs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ anyChar = Parser \p s -> case readCharOffAddr# p 0# s of
{-# inline anyChar #-}

digit :: Parser s Char
digit = satisfy A.isDigit
digit = satisfy A.isDigit
{-# inline digit #-}

space :: Parser s Char
Expand All @@ -107,14 +107,14 @@ scan :: (Char -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan f = go where
go p s = case readCharOffAddr# p 0# s of
(# t, c #) -> if isTrue# (chr# 0# `neChar#` c) && f (C# c)
then (# t, p #)
else scan f (plusAddr# p 1#) t
then scan f (plusAddr# p 1#) t
else (# t, p #)
{-# inline scan #-}

skipWhile :: (Char -> Bool) -> Parser s ()
skipWhile f = Parser \p s -> case scan f p s of
(# t, q #) -> OK () q t
{-# inline [1] skipWhile #-}
{-# inline [1] skipWhile #-}

{-# RULES
"skipWhile (x/=)" forall x.
Expand Down Expand Up @@ -151,7 +151,7 @@ skipWhileSome p = satisfy p *> skipWhile p

while :: KnownBase s => (Char -> Bool) -> Parser s ByteString
while f = snipping (skipWhile f)
{-# inline while #-}
{-# inline while #-}

till :: KnownBase s => (Char -> Bool) -> Parser s ByteString
till p = snipping (skipTill p)
Expand All @@ -169,7 +169,7 @@ tillSome :: KnownBase s => (Char -> Bool) -> Parser s ByteString
tillSome p = snipping (skipTillSome p)
{-# inline tillSome #-}

-- Peek at the previous character. Always succeeds.
-- Peek at the previous character. Always succeeds.
previousChar :: forall s. KnownBase s => Parser s (Maybe Char)
previousChar = case reflectBase @s of
!(Base _ _ l _) -> Parser \p s ->
Expand Down
1 change: 0 additions & 1 deletion parsnip/src/Text/Parsnip/Internal/Private.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import GHC.Prim
import GHC.Ptr
import GHC.Types
import System.IO.Unsafe
import Unsafe.Coerce

io :: IO a -> State# s -> (# State# s, a #)
io = unsafeCoerce#
Expand Down
4 changes: 2 additions & 2 deletions parsnip/src/Text/Parsnip/Word8.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ scan :: (Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan f = go where
go p s = case readWord8OffAddr# p 0# s of
(# t, c #) -> if isTrue# (0## `neWord#` c) && f (W8# c)
then (# t, p #)
else scan f (plusAddr# p 1#) t
then scan f (plusAddr# p 1#) t
else (# t, p #)
{-# inline scan #-}

skipWhile :: (Word8 -> Bool) -> Parser s ()
Expand Down
54 changes: 54 additions & 0 deletions parsnip/test/Spec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Main
( main
) where

import Test.Hspec as Hspec
import Test.Tasty
import Test.Tasty.Hspec

import Text.Parsnip
import qualified Text.Parsnip.Word8 as PW

import Data.Function (on)
import Data.ByteString.Internal (c2w)


spec :: IO TestTree
spec = testSpec "spec" $ do

describe "parsnip" $ do
it "while" $ parse (while ('A' ==)) "AAB" `shouldBe` Right "AA"
it "while edge" $ parse (while ('B' ==)) "AAB" `shouldBe` Right ""
it "while NUL" $ parse (while ('A' ==)) "A\0AB" `shouldBe` Right "A"
-- These are failing. Is this a bug? Or just a necessity due to the design?
-- it "while" $ parse (while (== 'A')) "AAB" `shouldBe` Right "AA"
-- it "while edge" $ parse (while (== 'B')) "AAB" `shouldBe` Right ""
-- it "while NUL" $ parse (while (== 'A')) "A\0AB" `shouldBe` Right "A"
it "till" $ parse (till (== 'B')) "AAB" `shouldBe` Right "AA"
it "till edge" $ parse (till (== 'A')) "AAB" `shouldBe` Right ""
it "till NUL" $ parse (till (== 'B')) "A\0AB" `shouldBe` Right "A"

describe "parsnip Word8" $ do
it "while" $ parse (PW.while (c2w 'A' ==)) "AAB" `shouldBe` Right "AA"
it "while edge" $ parse (PW.while (c2w 'B' ==)) "AAB" `shouldBe` Right ""
it "while NUL" $ parse (PW.while (c2w 'A' ==)) "A\0AB" `shouldBe` Right "A"
-- These are failing. Is this a bug? Or just a necessity due to the design?
-- it "while" $ parse (PW.while (== c2w 'A')) "AAB" `shouldBe` Right "AA"
-- it "while edge" $ parse (PW.while (== c2w 'B')) "AAB" `shouldBe` Right ""
-- it "while NUL" $ parse (PW.while (== c2w 'A')) "A\0AB" `shouldBe` Right "A"
it "till" $ parse (PW.till (== c2w 'B')) "AAB" `shouldBe` Right "AA"
it "till edge" $ parse (PW.till (== c2w 'A')) "AAB" `shouldBe` Right ""
it "till NUL" $ parse (PW.till (== c2w 'B')) "A\0AB" `shouldBe` Right "A"


instance Eq Location where
(==) = (==) `on` show

main :: IO ()
main = do
tests <- spec
defaultMain tests