From 8356a05919178f08ed4db1e022a2161c708f63ef Mon Sep 17 00:00:00 2001 From: mrkkrp Date: Wed, 21 Oct 2015 17:33:29 +0600 Subject: [PATCH] =?UTF-8?q?made=20interface=20of=20=E2=80=98Text.Megaparse?= =?UTF-8?q?c.Pos=E2=80=99=20smarter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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’. --- CHANGELOG.md | 7 +++++++ Text/Megaparsec/Pos.hs | 29 +++++++++++++++++------------ tests/Pos.hs | 42 +++++++++++++++++++++++------------------- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5ddf7c..b4443b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Text/Megaparsec/Pos.hs b/Text/Megaparsec/Pos.hs index 2b10f53..39da185 100644 --- a/Text/Megaparsec/Pos.hs +++ b/Text/Megaparsec/Pos.hs @@ -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 diff --git a/tests/Pos.hs b/tests/Pos.hs index 1ae5aa3..7f706ec 100644 --- a/tests/Pos.hs +++ b/tests/Pos.hs @@ -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