lib: change some parsers to use takeWhileP

This commit is contained in:
Alex Chen 2018-05-21 19:52:34 -06:00 committed by Simon Michael
parent 558c11596f
commit 12e8d0e282
6 changed files with 52 additions and 38 deletions

View File

@ -12,6 +12,7 @@ are thousands separated by comma, significant decimal places and so on.
module Hledger.Data.Commodity module Hledger.Data.Commodity
where where
import Data.Char (isDigit)
import Data.List import Data.List
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
#if !(MIN_VERSION_base(4,11,0)) #if !(MIN_VERSION_base(4,11,0))
@ -28,7 +29,13 @@ import Hledger.Utils
-- characters that may not be used in a non-quoted commodity symbol -- characters that may not be used in a non-quoted commodity symbol
nonsimplecommoditychars = "0123456789-+.@*;\n \"{}=" :: [Char] nonsimplecommoditychars = "0123456789-+.@*;\n \"{}=" :: [Char]
quoteCommoditySymbolIfNeeded s | any (`elem` nonsimplecommoditychars) (T.unpack s) = "\"" <> s <> "\"" isNonsimpleCommodityChar :: Char -> Bool
isNonsimpleCommodityChar c = isDigit c || c `textElem` otherChars
where
otherChars = "-+.@*;\n \"{}=" :: T.Text
textElem = T.any . (==)
quoteCommoditySymbolIfNeeded s | T.any (isNonsimpleCommodityChar) s = "\"" <> s <> "\""
| otherwise = s | otherwise = s
commodity = "" commodity = ""

View File

@ -50,6 +50,7 @@ module Hledger.Data.Dates (
failIfInvalidDay, failIfInvalidDay,
datesepchar, datesepchar,
datesepchars, datesepchars,
isDateSepChar,
spanStart, spanStart,
spanEnd, spanEnd,
spansSpan, spansSpan,
@ -738,8 +739,12 @@ smartdateonly = do
datesepchars :: [Char] datesepchars :: [Char]
datesepchars = "/-." datesepchars = "/-."
datesepchar :: TextParser m Char datesepchar :: TextParser m Char
datesepchar = oneOf datesepchars datesepchar = satisfy isDateSepChar
isDateSepChar :: Char -> Bool
isDateSepChar c = c == '/' || c == '-' || c == '.'
validYear, validMonth, validDay :: String -> Bool validYear, validMonth, validDay :: String -> Bool
validYear s = length s >= 4 && isJust (readMay s :: Maybe Year) validYear s = length s >= 4 && isJust (readMay s :: Maybe Year)

View File

@ -345,11 +345,14 @@ statusp =
] ]
<?> "cleared status" <?> "cleared status"
codep :: TextParser m String codep :: TextParser m Text
codep = try (do { skipSome spacenonewline; char '(' <?> "codep"; anyChar `manyTill` char ')' } ) <|> return "" codep = try codep' <|> pure "" where
codep' = do
skipSome spacenonewline
between (char '(' <?> "codep") (char ')') $ takeWhileP Nothing (/= ')')
descriptionp :: JournalParser m String descriptionp :: JournalParser m Text
descriptionp = many (noneOf (";\n" :: [Char])) descriptionp = takeWhileP Nothing $ \c -> c /= ';' && c /= '\n'
--- ** dates --- ** dates
@ -467,7 +470,7 @@ accountnamep = do
otherParts <- many $ try $ singleSpace *> part otherParts <- many $ try $ singleSpace *> part
let account = T.unwords $ firstPart : otherParts let account = T.unwords $ firstPart : otherParts
when (accountNameFromComponents (accountNameComponents account) /= account) when (accountNameFromComponents (accountNameComponents account) /= account)
(fail $ "account name seems ill-formed: " ++ T.unpack account) (fail $ "account name seems ill-formed: " ++ T.unpack account)
pure account pure account
where where
part = takeWhile1P Nothing (not . isSpace) part = takeWhile1P Nothing (not . isSpace)
@ -602,14 +605,12 @@ commoditysymbolp :: TextParser m CommoditySymbol
commoditysymbolp = (quotedcommoditysymbolp <|> simplecommoditysymbolp) <?> "commodity symbol" commoditysymbolp = (quotedcommoditysymbolp <|> simplecommoditysymbolp) <?> "commodity symbol"
quotedcommoditysymbolp :: TextParser m CommoditySymbol quotedcommoditysymbolp :: TextParser m CommoditySymbol
quotedcommoditysymbolp = do quotedcommoditysymbolp =
char '"' between (char '"') (char '"') $
s <- some $ noneOf (";\n\"" :: [Char]) takeWhile1P Nothing $ \c -> c /= ';' && c /= '\n' && c /= '\"'
char '"'
return $ T.pack s
simplecommoditysymbolp :: TextParser m CommoditySymbol simplecommoditysymbolp :: TextParser m CommoditySymbol
simplecommoditysymbolp = T.pack <$> some (noneOf nonsimplecommoditychars) simplecommoditysymbolp = takeWhile1P Nothing (not . isNonsimpleCommodityChar)
priceamountp :: Monad m => JournalParser m Price priceamountp :: Monad m => JournalParser m Price
priceamountp = priceamountp =
@ -816,7 +817,7 @@ multilinecommentp = startComment *> anyLine `skipManyTill` endComment
endComment = eof <|> (string "end comment" >> emptyLine) endComment = eof <|> (string "end comment" >> emptyLine)
emptyLine = void $ skipMany spacenonewline *> newline emptyLine = void $ skipMany spacenonewline *> newline
anyLine = anyChar `manyTill` newline anyLine = takeWhileP Nothing (\c -> c /= '\n') *> newline
emptyorcommentlinep :: TextParser m () emptyorcommentlinep :: TextParser m ()
emptyorcommentlinep = do emptyorcommentlinep = do
@ -933,7 +934,7 @@ commentStartingWithp f = do
satisfy f satisfy f
skipMany spacenonewline skipMany spacenonewline
startPos <- getPosition startPos <- getPosition
content <- T.pack <$> anyChar `manyTill` eolof content <- takeWhileP Nothing (\c -> c /= '\n')
optional newline optional newline
return (startPos, content) return (startPos, content)
@ -977,15 +978,15 @@ tagswithvaluepositions = do
where where
break :: SimpleTextParser () isBreak :: Char -> Bool
break = void spaceChar <|> void (char ':') <|> eof isBreak c = isSpace c || c == ':'
tillNextBreak :: SimpleTextParser Text tillNextBreak :: SimpleTextParser Text
tillNextBreak = T.pack <$> anyChar `manyTill` lookAhead break tillNextBreak = takeWhileP Nothing (not . isBreak)
tagValue :: SimpleTextParser Text tagValue :: SimpleTextParser Text
tagValue = tagValue = T.strip <$> takeWhileP Nothing (not . commaOrNewline)
T.strip . T.pack <$> anyChar `manyTill` (void (char ',') <|> eolof) where commaOrNewline c = c == ',' || c == '\n'
atSpaceChar :: SimpleTextParser [(SourcePos, Tag)] atSpaceChar :: SimpleTextParser [(SourcePos, Tag)]
atSpaceChar = skipSome spaceChar *> tagswithvaluepositions atSpaceChar = skipSome spaceChar *> tagswithvaluepositions
@ -1014,11 +1015,10 @@ tagswithvaluepositions = do
bracketedpostingdatesp :: Maybe Day -> SimpleTextParser [(TagName,Day)] bracketedpostingdatesp :: Maybe Day -> SimpleTextParser [(TagName,Day)]
bracketedpostingdatesp mdefdate = do bracketedpostingdatesp mdefdate = do
-- pdbg 0 $ "bracketedpostingdatesp" -- pdbg 0 $ "bracketedpostingdatesp"
skipMany $ noneOf ['['] skipMany $ notChar '['
fmap concat fmap concat
$ sepEndBy (bracketeddatetagsp mdefdate <|> char '[' *> pure []) $ sepEndBy (bracketeddatetagsp mdefdate <|> char '[' *> pure [])
(skipMany $ noneOf ['[']) (skipMany $ notChar '[')
-- using noneOf ['['] in place of notChar '[' for backwards compatibility
--- ** bracketed dates --- ** bracketed dates
@ -1054,8 +1054,8 @@ bracketeddatetagsp mdefdate = do
try $ do try $ do
s <- lookAhead s <- lookAhead
$ between (char '[') (char ']') $ between (char '[') (char ']')
$ some $ digitChar <|> datesepchar <|> char '=' $ takeWhile1P Nothing isBracketedDateChar
unless (any isDigit s && any (`elem` datesepchars) s) $ unless (T.any isDigit s && T.any isDateSepChar s) $
fail "not a bracketed date" fail "not a bracketed date"
-- Looks sufficiently like a bracketed date to commit to parsing a date -- Looks sufficiently like a bracketed date to commit to parsing a date
@ -1064,8 +1064,10 @@ bracketeddatetagsp mdefdate = do
md1 <- optional $ datep' myear1 md1 <- optional $ datep' myear1
let myear2 = fmap readYear md1 <|> myear1 let myear2 = fmap readYear md1 <|> myear1
md2 <- optional $ char '=' *> (datep' myear2) md2 <- optional $ char '=' *> datep' myear2
pure $ catMaybes [("date",) <$> md1, ("date2",) <$> md2] pure $ catMaybes [("date",) <$> md1, ("date2",) <$> md2]
where readYear = first3 . toGregorian where
readYear = first3 . toGregorian
isBracketedDateChar c = isDigit c || isDateSepChar c || c == '='

View File

@ -464,7 +464,7 @@ periodictransactionp :: MonadIO m => ErroringJournalParser m PeriodicTransaction
periodictransactionp = do periodictransactionp = do
char '~' <?> "periodic transaction" char '~' <?> "periodic transaction"
lift (skipMany spacenonewline) lift (skipMany spacenonewline)
periodexpr <- T.pack . strip <$> descriptionp periodexpr <- T.strip <$> descriptionp
_ <- lift followingcommentp _ <- lift followingcommentp
postings <- postingsp Nothing postings <- postingsp Nothing
return $ PeriodicTransaction periodexpr postings return $ PeriodicTransaction periodexpr postings
@ -478,12 +478,12 @@ transactionp = do
edate <- optional (secondarydatep date) <?> "secondary date" edate <- optional (secondarydatep date) <?> "secondary date"
lookAhead (lift spacenonewline <|> newline) <?> "whitespace or newline" lookAhead (lift spacenonewline <|> newline) <?> "whitespace or newline"
status <- lift statusp <?> "cleared status" status <- lift statusp <?> "cleared status"
code <- T.pack <$> lift codep <?> "transaction code" code <- lift codep <?> "transaction code"
description <- T.pack . strip <$> descriptionp description <- T.strip <$> descriptionp
comment <- lift followingcommentp comment <- lift followingcommentp
let tags = commentTags comment let tags = commentTags comment
postings <- postingsp (Just date) postings <- postingsp (Just date)
pos' <- getPosition pos' <- getPosition
let sourcepos = journalSourcePos pos pos' let sourcepos = journalSourcePos pos pos'
return $ txnTieKnot $ Transaction 0 sourcepos date edate status code description comment tags postings "" return $ txnTieKnot $ Transaction 0 sourcepos date edate status code description comment tags postings ""

View File

@ -52,12 +52,12 @@ parsewithString p = runParser p ""
parseWithState :: Monad m => st -> StateT st (ParsecT Void Text m) a -> Text -> m (Either (ParseError Char Void) a) parseWithState :: Monad m => st -> StateT st (ParsecT Void Text m) a -> Text -> m (Either (ParseError Char Void) a)
parseWithState ctx p s = runParserT (evalStateT p ctx) "" s parseWithState ctx p s = runParserT (evalStateT p ctx) "" s
parseWithState' :: ( parseWithState'
Stream s :: (Stream s)
#if !MIN_VERSION_megaparsec(6,0,0) => st
,ErrorComponent e -> StateT st (ParsecT e s Identity) a
#endif -> s
) => st -> StateT st (ParsecT e s Identity) a -> s -> (Either (ParseError (Token s) e) a) -> (Either (ParseError (Token s) e) a)
parseWithState' ctx p s = runParser (evalStateT p ctx) "" s parseWithState' ctx p s = runParser (evalStateT p ctx) "" s
fromparse :: (Show t, Show e) => Either (ParseError t e) a -> a fromparse :: (Show t, Show e) => Either (ParseError t e) a -> a

View File

@ -200,7 +200,7 @@ dateAndCodeWizard EntryState{..} = do
c <- optional codep c <- optional codep
skipMany spacenonewline skipMany spacenonewline
eof eof
return (d, T.pack $ fromMaybe "" c) return (d, fromMaybe "" c)
-- defday = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) defdate -- defday = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) defdate
-- datestr = showDate $ fixSmartDate defday smtdate -- datestr = showDate $ fixSmartDate defday smtdate