made interface of ‘Text.Megaparsec.Pos’ smarter

Now it's impossible to create ‘SourcePos’ with non-positive line number
or column number. Unfortunately we cannot use ‘Numeric.Natural’ because
we need to support older versions of ‘base’.
This commit is contained in:
mrkkrp 2015-10-21 17:33:29 +06:00
parent bedad01d98
commit 8356a05919
3 changed files with 47 additions and 31 deletions

View File

@ -1,3 +1,10 @@
## Megaparsec 4.2.0
* Made `newPos` constructor and other functions in `Text.Megaparsec.Pos`
smarter. Now it's impossible to create `SourcePos` with non-positive line
number or column number. Unfortunately we cannot use `Numeric.Natural`
because we need to support older versions of `base`.
## Megaparsec 4.1.1
* Fixed bug in implementation of `sepEndBy` and `sepEndBy1` and removed

View File

@ -28,9 +28,7 @@ module Text.Megaparsec.Pos
, defaultTabWidth )
where
import Data.Data (Data)
import Data.List (foldl')
import Data.Typeable (Typeable)
-- | The abstract data type @SourcePos@ represents source positions. It
-- contains the name of the source (i.e. file name), a line number and a
@ -44,7 +42,7 @@ data SourcePos = SourcePos
, sourceLine :: !Int
-- | Extract the column number from a source position.
, sourceColumn :: !Int }
deriving (Eq, Ord, Data, Typeable)
deriving (Eq, Ord)
instance Show SourcePos where
show (SourcePos n l c)
@ -54,9 +52,12 @@ instance Show SourcePos where
-- | Create a new 'SourcePos' with the given source name, line number and
-- column number.
--
-- In call @newPos name line column@, if @line@ is not a positive
-- number, 1 will be used. The same holds for @column@ value.
newPos :: String -> Int -> Int -> SourcePos
newPos = SourcePos
newPos n l c = SourcePos n (max 1 l) (max 1 c)
-- | Create a new 'SourcePos' with the given source name, and line number
-- and column number set to 1, the upper left.
@ -64,30 +65,34 @@ newPos = SourcePos
initialPos :: String -> SourcePos
initialPos name = newPos name 1 1
-- | Increment the line number of a source position.
-- | Increment the line number of a source position. If resulting line
-- number is not positive, line number will be equal to 1.
incSourceLine :: SourcePos -> Int -> SourcePos
incSourceLine (SourcePos n l c) d = SourcePos n (l + d) c
incSourceLine (SourcePos n l c) d = SourcePos n (max 1 $ l + d) c
-- | Increments the column number of a source position.
-- | Increments the column number of a source position. If resulting column
-- number is not positive, column number will be equal to 1.
incSourceColumn :: SourcePos -> Int -> SourcePos
incSourceColumn (SourcePos n l c) d = SourcePos n l (c + d)
incSourceColumn (SourcePos n l c) d = SourcePos n l (max 1 $ c + d)
-- | Set the name of the source.
setSourceName :: SourcePos -> String -> SourcePos
setSourceName (SourcePos _ l c) n = SourcePos n l c
-- | Set the line number of a source position.
-- | Set the line number of a source position. If the line number is not
-- positive, 1 will be used.
setSourceLine :: SourcePos -> Int -> SourcePos
setSourceLine (SourcePos n _ c) l = SourcePos n l c
setSourceLine (SourcePos n _ c) l = SourcePos n (max 1 l) c
-- | Set the column number of a source position.
-- | Set the column number of a source position. If the line number is not
-- positive, 1 will be used.
setSourceColumn :: SourcePos -> Int -> SourcePos
setSourceColumn (SourcePos n l _) = SourcePos n l
setSourceColumn (SourcePos n l _) c = SourcePos n l (max 1 c)
-- | Update a source position given a character. The first argument
-- specifies tab width. If the character is a newline (\'\\n\') the line

View File

@ -47,6 +47,7 @@ import Control.Applicative ((<$>), (<*>), pure)
tests :: Test
tests = testGroup "Textual source positions"
[ testProperty "components" prop_components
, testProperty "positive coordinates" prop_positive
, testProperty "show file name in source positions" prop_showFileName
, testProperty "show line in source positions" prop_showLine
, testProperty "show column in source positions" prop_showColumn
@ -59,7 +60,7 @@ tests = testGroup "Textual source positions"
, testProperty "position updating" prop_updating ]
instance Arbitrary SourcePos where
arbitrary = newPos <$> fileName <*> choose (1, 1000) <*> choose (0, 100)
arbitrary = newPos <$> fileName <*> choose (-10, 1000) <*> choose (-10, 100)
fileName :: Gen String
fileName = do
@ -74,6 +75,9 @@ prop_components :: SourcePos -> Bool
prop_components pos = pos == copy
where copy = newPos (sourceName pos) (sourceLine pos) (sourceColumn pos)
prop_positive :: SourcePos -> Bool
prop_positive pos = sourceLine pos > 0 && sourceColumn pos > 0
prop_showFileName :: SourcePos -> Bool
prop_showFileName pos = sourceName pos `isInfixOf` show pos
@ -90,21 +94,21 @@ prop_initialPos n =
sourceColumn ipos == 1
where ipos = initialPos n
prop_incSourceLine :: SourcePos -> NonNegative Int -> Bool
prop_incSourceLine :: SourcePos -> Int -> Bool
prop_incSourceLine pos l =
d sourceName id pos incp &&
d sourceLine (+ l') pos incp &&
d sourceColumn id pos incp
where l' = getNonNegative l
incp = incSourceLine pos l'
d sourceName id pos incp &&
d sourceLine f pos incp &&
d sourceColumn id pos incp
where f = max 1 . (+ l)
incp = incSourceLine pos l
prop_incSourceColumn :: SourcePos -> NonNegative Int -> Bool
prop_incSourceColumn :: SourcePos -> Int -> Bool
prop_incSourceColumn pos c =
d sourceName id pos incp &&
d sourceLine id pos incp &&
d sourceColumn (+ c') pos incp
where c' = getNonNegative c
incp = incSourceColumn pos c'
d sourceName id pos incp &&
d sourceLine id pos incp &&
d sourceColumn f pos incp
where f = max 1 . (+ c)
incp = incSourceColumn pos c
prop_setSourceName :: SourcePos -> String -> Bool
prop_setSourceName pos n =
@ -113,21 +117,21 @@ prop_setSourceName pos n =
d sourceColumn id pos setp
where setp = setSourceName pos n
prop_setSourceLine :: SourcePos -> Positive Int -> Bool
prop_setSourceLine :: SourcePos -> Int -> Bool
prop_setSourceLine pos l =
d sourceName id pos setp &&
d sourceLine (const l') pos setp &&
d sourceColumn id pos setp
where l' = getPositive l
setp = setSourceLine pos l'
where l' = max 1 l
setp = setSourceLine pos l
prop_setSourceColumn :: SourcePos -> NonNegative Int -> Bool
prop_setSourceColumn :: SourcePos -> Int -> Bool
prop_setSourceColumn pos c =
d sourceName id pos setp &&
d sourceLine id pos setp &&
d sourceColumn (const c') pos setp
where c' = getNonNegative c
setp = setSourceColumn pos c'
where c' = max 1 c
setp = setSourceColumn pos c
prop_updating :: Int -> SourcePos -> String -> Bool
prop_updating w pos "" = updatePosString w pos "" == pos