lib: superficial changes to parsers
This commit is contained in:
		
							parent
							
								
									121ba92ade
								
							
						
					
					
						commit
						84c7e2c403
					
				| @ -339,6 +339,7 @@ parserErrorAt :: Monad m => SourcePos -> String -> ErroringJournalParser m a | ||||
| parserErrorAt pos s = throwError $ sourcePosPretty pos ++ ":\n" ++ s | ||||
| 
 | ||||
| --- * parsers | ||||
| 
 | ||||
| --- ** transaction bits | ||||
| 
 | ||||
| statusp :: TextParser m Status | ||||
| @ -348,16 +349,15 @@ statusp = | ||||
|     , skipMany spacenonewline >> char '!' >> return Pending | ||||
|     , return Unmarked | ||||
|     ] | ||||
|     <?> "cleared status" | ||||
| 
 | ||||
| codep :: TextParser m Text | ||||
| codep = try codep' <|> pure "" where | ||||
|   codep' = do | ||||
|     skipSome spacenonewline | ||||
|     between (char '(' <?> "codep") (char ')') $ takeWhileP Nothing (/= ')') | ||||
| codep = option "" $ try $ do | ||||
|   skipSome spacenonewline | ||||
|   between (char '(') (char ')') $ takeWhileP Nothing (/= ')') | ||||
| 
 | ||||
| descriptionp :: JournalParser m Text | ||||
| descriptionp = takeWhileP Nothing $ \c -> c /= ';' && c /= '\n' | ||||
| descriptionp = takeWhileP Nothing (not . semicolonOrNewline) | ||||
|   where semicolonOrNewline c = c == ';' || c == '\n' | ||||
| 
 | ||||
| --- ** dates | ||||
| 
 | ||||
| @ -367,8 +367,8 @@ descriptionp = takeWhileP Nothing $ \c -> c /= ';' && c /= '\n' | ||||
| -- Leading zeroes may be omitted. | ||||
| datep :: JournalParser m Day | ||||
| datep = do | ||||
|   myear <- getYear | ||||
|   lift $ datep' myear | ||||
|   mYear <- getYear | ||||
|   lift $ datep' mYear | ||||
| 
 | ||||
| datep' :: Maybe Year -> TextParser m Day | ||||
| datep' mYear = do | ||||
| @ -380,7 +380,7 @@ datep' mYear = do | ||||
| 
 | ||||
|   where | ||||
| 
 | ||||
|   fullDate :: Integer -> Char -> Integer -> TextParser m Day | ||||
|   fullDate :: Integer -> Char -> Int -> TextParser m Day | ||||
|   fullDate year sep1 month = do | ||||
|     sep2 <- satisfy isDateSepChar <?> "date separator" | ||||
|     day <- decimal <?> "day" | ||||
| @ -389,17 +389,18 @@ datep' mYear = do | ||||
|     when (sep1 /= sep2) $ fail $ | ||||
|       "invalid date (mixing date separators is not allowed): " ++ dateStr | ||||
| 
 | ||||
|     case fromGregorianValid year (fromIntegral month) day of | ||||
|     case fromGregorianValid year month day of | ||||
|       Nothing -> fail $ "well-formed but invalid date: " ++ dateStr | ||||
|       Just date -> pure date | ||||
| 
 | ||||
|   partialDate :: Maybe Year -> Integer -> Char -> Integer -> TextParser m Day | ||||
|   partialDate :: Maybe Year -> Integer -> Char -> Int -> TextParser m Day | ||||
|   partialDate mYear month sep day = case mYear of | ||||
|     Just year -> | ||||
|       case fromGregorianValid year (fromIntegral month) (fromIntegral day) of | ||||
|       case fromGregorianValid year (fromIntegral month) day of | ||||
|         Nothing -> fail $ "well-formed but invalid date: " ++ dateStr | ||||
|         Just date -> pure date | ||||
|       where dateStr = show year ++ [sep] ++ show month ++ [sep] ++ show day | ||||
| 
 | ||||
|     Nothing -> fail $ | ||||
|       "partial date "++dateStr++" found, but the current year is unknown" | ||||
|       where dateStr = show month ++ [sep] ++ show day | ||||
| @ -438,28 +439,9 @@ datetimep = do | ||||
|   -- return $ localTimeToUTC tz' $ LocalTime day $ TimeOfDay h' m' (fromIntegral s') | ||||
|   return $ LocalTime day $ TimeOfDay h' m' (fromIntegral s') | ||||
| 
 | ||||
| secondarydatep :: Day -> JournalParser m Day | ||||
| secondarydatep primarydate = do | ||||
|   char '=' | ||||
|   -- kludgy way to use primary date for default year | ||||
|   let withDefaultYear d p = do | ||||
|         y <- getYear | ||||
|         let (y',_,_) = toGregorian d in setYear y' | ||||
|         r <- p | ||||
|         when (isJust y) $ setYear $ fromJust y -- XXX | ||||
|         -- mapM setYear <$> y | ||||
|         return r | ||||
|   withDefaultYear primarydate datep | ||||
| 
 | ||||
| -- | | ||||
| -- >> parsewith twoorthreepartdatestringp "2016/01/2" | ||||
| -- Right "2016/01/2" | ||||
| -- twoorthreepartdatestringp = do | ||||
| --   n1 <- some digitChar | ||||
| --   c <- datesepchar | ||||
| --   n2 <- some digitChar | ||||
| --   mn3 <- optional $ char c >> some digitChar | ||||
| --   return $ n1 ++ c:n2 ++ maybe "" (c:) mn3 | ||||
| secondarydatep :: Day -> TextParser m Day | ||||
| secondarydatep primaryDate = char '=' *> datep' (Just primaryYear) | ||||
|   where primaryYear = first3 $ toGregorian primaryDate | ||||
| 
 | ||||
| --- ** account names | ||||
| 
 | ||||
| @ -485,8 +467,12 @@ accountnamep = do | ||||
|   firstPart <- part | ||||
|   otherParts <- many $ try $ singleSpace *> part | ||||
|   let account = T.unwords $ firstPart : otherParts | ||||
|   when (accountNameFromComponents (accountNameComponents account) /= account) | ||||
|        (fail $ "account name seems ill-formed: " ++ T.unpack account) | ||||
| 
 | ||||
|   let roundTripAccount = | ||||
|         accountNameFromComponents $ accountNameComponents account | ||||
|   when (account /= roundTripAccount) $ fail $ | ||||
|     "account name seems ill-formed: " ++ T.unpack account | ||||
| 
 | ||||
|   pure account | ||||
|   where | ||||
|     part = takeWhile1P Nothing (not . isSpace) | ||||
| @ -499,10 +485,9 @@ accountnamep = do | ||||
| -- "missing" marker amount. | ||||
| spaceandamountormissingp :: Monad m => JournalParser m MixedAmount | ||||
| spaceandamountormissingp = | ||||
|   try (do | ||||
|         lift $ skipSome spacenonewline | ||||
|         (Mixed . (:[])) `fmap` amountp <|> return missingmixedamt | ||||
|       ) <|> return missingmixedamt | ||||
|   option missingmixedamt $ try $ do | ||||
|     lift $ skipSome spacenonewline | ||||
|     Mixed . (:[]) <$> amountp | ||||
| 
 | ||||
| #ifdef TESTS | ||||
| assertParseEqual' :: (Show a, Eq a) => (Either ParseError a) -> a -> Assertion | ||||
| @ -556,10 +541,7 @@ signp = do | ||||
|                         _        -> "" | ||||
| 
 | ||||
| multiplierp :: TextParser m Bool | ||||
| multiplierp = do | ||||
|   multiplier <- optional $ oneOf ("*" :: [Char]) | ||||
|   return $ case multiplier of Just '*' -> True | ||||
|                               _        -> False | ||||
| multiplierp = option False $ char '*' *> pure True | ||||
| 
 | ||||
| -- | This is like skipMany but it returns True if at least one element | ||||
| -- was skipped. This is helpful if you’re just using many to check if | ||||
| @ -622,38 +604,35 @@ commoditysymbolp = (quotedcommoditysymbolp <|> simplecommoditysymbolp) <?> "comm | ||||
| 
 | ||||
| quotedcommoditysymbolp :: TextParser m CommoditySymbol | ||||
| quotedcommoditysymbolp = | ||||
|   between (char '"') (char '"') $ | ||||
|     takeWhile1P Nothing $ \c -> c /= ';' && c /= '\n' && c /= '\"' | ||||
|   between (char '"') (char '"') $ takeWhile1P Nothing f | ||||
|   where f c = c /= ';' && c /= '\n' && c /= '\"' | ||||
| 
 | ||||
| simplecommoditysymbolp :: TextParser m CommoditySymbol | ||||
| simplecommoditysymbolp = takeWhile1P Nothing (not . isNonsimpleCommodityChar) | ||||
| 
 | ||||
| priceamountp :: Monad m => JournalParser m Price | ||||
| priceamountp = | ||||
|     try (do | ||||
|           lift (skipMany spacenonewline) | ||||
|           char '@' | ||||
|           try (do | ||||
|                 char '@' | ||||
|                 lift (skipMany spacenonewline) | ||||
|                 a <- amountp -- XXX can parse more prices ad infinitum, shouldn't | ||||
|                 return $ TotalPrice a) | ||||
|            <|> (do | ||||
|             lift (skipMany spacenonewline) | ||||
|             a <- amountp -- XXX can parse more prices ad infinitum, shouldn't | ||||
|             return $ UnitPrice a)) | ||||
|          <|> return NoPrice | ||||
| priceamountp = option NoPrice $ try $ do | ||||
|   lift (skipMany spacenonewline) | ||||
|   char '@' | ||||
| 
 | ||||
|   m <- optional $ char '@' | ||||
|   let priceConstructor = case m of | ||||
|         Just _  -> TotalPrice | ||||
|         Nothing -> UnitPrice | ||||
| 
 | ||||
|   lift (skipMany spacenonewline) | ||||
|   priceAmount <- amountp -- XXX can parse more prices ad infinitum, shouldn't | ||||
| 
 | ||||
|   pure $ priceConstructor priceAmount | ||||
| 
 | ||||
| partialbalanceassertionp :: Monad m => JournalParser m BalanceAssertion | ||||
| partialbalanceassertionp = | ||||
|     try (do | ||||
|           lift (skipMany spacenonewline) | ||||
|           sourcepos <- genericSourcePos <$> lift getPosition | ||||
|           char '=' | ||||
|           lift (skipMany spacenonewline) | ||||
|           a <- amountp -- XXX should restrict to a simple amount | ||||
|           return $ Just (a, sourcepos)) | ||||
|          <|> return Nothing | ||||
| partialbalanceassertionp = optional $ try $ do | ||||
|   lift (skipMany spacenonewline) | ||||
|   sourcepos <- genericSourcePos <$> lift getPosition | ||||
|   char '=' | ||||
|   lift (skipMany spacenonewline) | ||||
|   a <- amountp -- XXX should restrict to a simple amount | ||||
|   return (a, sourcepos) | ||||
| 
 | ||||
| -- balanceassertion :: Monad m => TextParser m (Maybe MixedAmount) | ||||
| -- balanceassertion = | ||||
| @ -667,18 +646,16 @@ partialbalanceassertionp = | ||||
| 
 | ||||
| -- http://ledger-cli.org/3.0/doc/ledger3.html#Fixing-Lot-Prices | ||||
| fixedlotpricep :: Monad m => JournalParser m (Maybe Amount) | ||||
| fixedlotpricep = | ||||
|     try (do | ||||
|           lift (skipMany spacenonewline) | ||||
|           char '{' | ||||
|           lift (skipMany spacenonewline) | ||||
|           char '=' | ||||
|           lift (skipMany spacenonewline) | ||||
|           a <- amountp -- XXX should restrict to a simple amount | ||||
|           lift (skipMany spacenonewline) | ||||
|           char '}' | ||||
|           return $ Just a) | ||||
|          <|> return Nothing | ||||
| fixedlotpricep = optional $ try $ do | ||||
|   lift (skipMany spacenonewline) | ||||
|   char '{' | ||||
|   lift (skipMany spacenonewline) | ||||
|   char '=' | ||||
|   lift (skipMany spacenonewline) | ||||
|   a <- amountp -- XXX should restrict to a simple amount | ||||
|   lift (skipMany spacenonewline) | ||||
|   char '}' | ||||
|   return a | ||||
| 
 | ||||
| -- | Parse a string representation of a number for its value and display | ||||
| -- attributes. | ||||
| @ -733,53 +710,58 @@ fromRawNumber | ||||
| fromRawNumber suggestedStyle negated raw = case raw of | ||||
| 
 | ||||
|   LeadingDecimalPt decPt digitGrp -> | ||||
|     let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                   (digitGroupNumber digitGrp) | ||||
|     let quantity = sign $ | ||||
|           Decimal (fromIntegral precision) (digitGroupNumber digitGrp) | ||||
|         precision = digitGroupLength digitGrp | ||||
|     in  (quantity, precision, Just decPt, Nothing) | ||||
| 
 | ||||
|   TrailingDecimalPt digitGrp decPt -> | ||||
|     let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                   (digitGroupNumber digitGrp) | ||||
|     let quantity = sign $ | ||||
|           Decimal (fromIntegral precision) (digitGroupNumber digitGrp) | ||||
|         precision = 0 | ||||
|     in  (quantity, precision, Just decPt, Nothing) | ||||
| 
 | ||||
|   NoSeparators digitGrp -> | ||||
|     let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                   (digitGroupNumber digitGrp) | ||||
|     let quantity = sign $ | ||||
|           Decimal (fromIntegral precision) (digitGroupNumber digitGrp) | ||||
|         precision = 0 | ||||
|     in  (quantity, precision, Nothing, Nothing) | ||||
| 
 | ||||
|   AmbiguousNumber digitGrp1 sep digitGrp2 -> | ||||
|   AmbiguousNumber digitGrp1 sep digitGrp2 | ||||
|     -- If present, use the suggested style to disambiguate; | ||||
|     -- otherwise, assume that the separator is a decimal point where possible. | ||||
|     if isDecimalPointChar sep && maybe True (sep `isValidDecimalBy`) suggestedStyle | ||||
|     |    isDecimalPointChar sep | ||||
|       && maybe True (sep `isValidDecimalBy`) suggestedStyle -> | ||||
| 
 | ||||
|     then -- Assuming that the separator is a decimal point | ||||
|       let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                     (digitGroupNumber $ digitGrp1 <> digitGrp2) | ||||
|       -- Assuming that the separator is a decimal point | ||||
|       let quantity = sign $ | ||||
|             Decimal (fromIntegral precision) | ||||
|                     (digitGroupNumber $ digitGrp1 <> digitGrp2) | ||||
|           precision = digitGroupLength digitGrp2 | ||||
|       in  (quantity, precision, Just sep, Nothing) | ||||
| 
 | ||||
|     else -- Assuming that the separator is digit separator | ||||
|       let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                     (digitGroupNumber $ digitGrp1 <> digitGrp2) | ||||
|     | otherwise -> | ||||
|       -- Assuming that the separator is digit separator | ||||
|       let quantity = sign $ | ||||
|             Decimal (fromIntegral precision) | ||||
|                     (digitGroupNumber $ digitGrp1 <> digitGrp2) | ||||
|           precision = 0 | ||||
|           digitGroupStyle = Just $ | ||||
|             DigitGroups sep (groupSizes $ [digitGrp1, digitGrp2]) | ||||
|       in  (quantity, precision, Nothing, digitGroupStyle) | ||||
| 
 | ||||
|   DigitSeparators digitSep digitGrps -> | ||||
|     let quantity = sign $ Decimal (fromIntegral precision) | ||||
|                                   (digitGroupNumber $ mconcat digitGrps) | ||||
|     let quantity = sign $ | ||||
|           Decimal (fromIntegral precision) | ||||
|                   (digitGroupNumber $ mconcat digitGrps) | ||||
|         precision = 0 | ||||
|         digitGroupStyle = Just $ DigitGroups digitSep (groupSizes digitGrps) | ||||
|     in  (quantity, precision, Nothing, digitGroupStyle) | ||||
| 
 | ||||
|   BothSeparators digitSep digitGrps decPt decimalGrp -> | ||||
|     let quantity = | ||||
|           sign $ Decimal (fromIntegral precision) | ||||
|                          (digitGroupNumber $ mconcat digitGrps <> decimalGrp) | ||||
|     let quantity = sign $ | ||||
|           Decimal (fromIntegral precision) | ||||
|                   (digitGroupNumber $ mconcat digitGrps <> decimalGrp) | ||||
|         precision = digitGroupLength decimalGrp | ||||
|         digitGroupStyle = Just $ DigitGroups digitSep (groupSizes digitGrps) | ||||
|     in  (quantity, precision, Just decPt, digitGroupStyle) | ||||
| @ -860,7 +842,6 @@ rawnumberp = label "rawnumberp" $ do | ||||
|     | null grps = AmbiguousNumber grp1 sep grp2 | ||||
|     | otherwise = DigitSeparators sep (grp1:grp2:grps) | ||||
| 
 | ||||
| 
 | ||||
|   trailingDecimalPt :: DigitGrp -> TextParser m RawNumber | ||||
|   trailingDecimalPt grp1 = do | ||||
|     decimalPt <- satisfy isDecimalPointChar | ||||
| @ -937,10 +918,10 @@ data RawNumber | ||||
| multilinecommentp :: TextParser m () | ||||
| multilinecommentp = startComment *> anyLine `skipManyTill` endComment | ||||
|   where | ||||
|     startComment = string "comment" >> emptyLine | ||||
|     endComment = eof <|> (string "end comment" >> emptyLine) | ||||
|     startComment = string "comment" >> skipLine | ||||
|     endComment = eof <|> string "end comment" *> skipLine | ||||
| 
 | ||||
|     emptyLine = void $ skipMany spacenonewline *> newline | ||||
|     skipLine = void $ skipMany spacenonewline *> newline | ||||
|     anyLine = takeWhileP Nothing (\c -> c /= '\n') *> newline | ||||
| 
 | ||||
| emptyorcommentlinep :: TextParser m () | ||||
| @ -1140,9 +1121,8 @@ bracketedpostingdatesp :: Maybe Day -> SimpleTextParser [(TagName,Day)] | ||||
| bracketedpostingdatesp mdefdate = do | ||||
|   -- pdbg 0 $ "bracketedpostingdatesp" | ||||
|   skipMany $ notChar '[' | ||||
|   fmap concat | ||||
|     $ sepEndBy (bracketeddatetagsp mdefdate <|> char '[' *> pure []) | ||||
|                (skipMany $ notChar '[') | ||||
|   concat <$> sepEndBy (bracketeddatetagsp mdefdate <|> char '[' *> pure []) | ||||
|                       (skipMany $ notChar '[') | ||||
| 
 | ||||
| --- ** bracketed dates | ||||
| 
 | ||||
|  | ||||
| @ -475,7 +475,7 @@ transactionp = do | ||||
|   -- ptrace "transactionp" | ||||
|   pos <- getPosition | ||||
|   date <- datep <?> "transaction" | ||||
|   edate <- optional (secondarydatep date) <?> "secondary date" | ||||
|   edate <- optional (lift $ secondarydatep date) <?> "secondary date" | ||||
|   lookAhead (lift spacenonewline <|> newline) <?> "whitespace or newline" | ||||
|   status <- lift statusp <?> "cleared status" | ||||
|   code <- lift codep <?> "transaction code" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user