lib: merge parsing of date-tags with that of tags
This commit is contained in:
		
							parent
							
								
									ec85271a0b
								
							
						
					
					
						commit
						fcc10f018d
					
				| @ -853,23 +853,38 @@ followingcommentandtagsp mdefdate = do | ||||
|   -- pdbg 0 $ "commentws:" ++ show commentLines | ||||
| 
 | ||||
|   -- Reparse the comment for any tags. | ||||
|   tags <- case traverse (runTextParserAt tagsp) commentLines of | ||||
|   tagsWithPositions <- case traverse (runTextParserAt tagswithvaluepositions) commentLines of | ||||
|     Right tss -> pure $ concat tss | ||||
|     Left e    -> throwError $ parseErrorPretty e | ||||
| 
 | ||||
|   -- Reparse the comment for any posting dates. | ||||
|   -- Extract date-tag style posting dates from the tags. | ||||
|   -- Use the transaction date for defaults, if provided. | ||||
|   epdates <- fmap sequence | ||||
|   journal <- fmap | ||||
|     (\j -> j{jparsedefaultyear=first3.toGregorian <$> mdefdate}) get | ||||
| 
 | ||||
|   let eTagDates = traverse (tagDate journal) | ||||
|                 $ filter (isDateLabel . fst . snd) tagsWithPositions | ||||
|                 where isDateLabel txt = txt == "date" || txt == "date2" | ||||
|   tagDates <- case eTagDates of | ||||
|     Right ds -> pure ds | ||||
|     Left e   -> throwError e | ||||
| 
 | ||||
|   -- Reparse the comment for any bracketed style posting dates. | ||||
|   -- Use the transaction date for defaults, if provided. | ||||
|   eBracketedDates <- fmap sequence | ||||
|            $ traverse (runErroringJournalParserAt (postingdatesp mdefdate)) | ||||
|                       commentLines | ||||
|   pdates <- case epdates of | ||||
|   bracketedDates <- case eBracketedDates of | ||||
|     Right dss -> pure $ concat dss | ||||
|     Left e    -> throwError e | ||||
|   -- pdbg 0 $ "pdates: "++show pdates | ||||
| 
 | ||||
|   let pdates = tagDates ++ bracketedDates | ||||
|   -- pdbg 0 $ "allDates: "++show pdates | ||||
|   let mdate  = headMay $ map snd $ filter ((=="date") .fst) pdates | ||||
|       mdate2 = headMay $ map snd $ filter ((=="date2").fst) pdates | ||||
| 
 | ||||
|   let strippedComment = T.unlines $ map (T.strip . snd) commentLines | ||||
|       tags = map snd tagsWithPositions | ||||
|   -- pdbg 0 $ "comment:"++show strippedComment | ||||
| 
 | ||||
|   pure (strippedComment, tags, mdate, mdate2) | ||||
| @ -877,9 +892,22 @@ followingcommentandtagsp mdefdate = do | ||||
|   where | ||||
|     runTextParserAt parser (pos, txt) = | ||||
|       runTextParser (setPosition pos *> parser) txt | ||||
| 
 | ||||
|     runErroringJournalParserAt parser (pos, txt) = | ||||
|       runErroringJournalParser (setPosition pos *> parser) txt | ||||
| 
 | ||||
|     parseWithStateAt' st parser (pos, txt) = | ||||
|       parseWithState' st (setPosition pos *> parser) txt | ||||
| 
 | ||||
|     tagDate | ||||
|       :: Journal | ||||
|       -> (SourcePos, Tag) | ||||
|       -> Either String (TagName, Day) | ||||
|     tagDate journal (pos, (name, value)) = | ||||
|       case parseWithStateAt' journal datep (pos, value) of | ||||
|         Left e -> Left $ parseErrorPretty e | ||||
|         Right day -> Right (name, day) | ||||
| 
 | ||||
| -- A transaction/posting comment must start with a semicolon. | ||||
| -- This parser discards the leading whitespace of the comment | ||||
| -- and returns the source position of the comment's first non-whitespace character. | ||||
| @ -929,7 +957,10 @@ commentTags s = | ||||
| 
 | ||||
| -- | Parse all tags found in a string. | ||||
| tagsp :: SimpleTextParser [Tag] | ||||
| tagsp = do | ||||
| tagsp = map snd <$> tagswithvaluepositions | ||||
| 
 | ||||
| tagswithvaluepositions :: SimpleTextParser [(SourcePos, Tag)] | ||||
| tagswithvaluepositions = do | ||||
|   -- pdbg 0 $ "tagsp" | ||||
| 
 | ||||
|   -- If we parse in a single pass, we cannot know whether some text | ||||
| @ -953,25 +984,22 @@ tagsp = do | ||||
|     tagValue = | ||||
|       T.strip . T.pack <$> anyChar `manyTill` (void (char ',') <|> eolof) | ||||
| 
 | ||||
|     atSpaceChar :: SimpleTextParser [Tag] | ||||
|     atSpaceChar = skipSome spaceChar *> tagsp | ||||
|     atSpaceChar :: SimpleTextParser [(SourcePos, Tag)] | ||||
|     atSpaceChar = skipSome spaceChar *> tagswithvaluepositions | ||||
| 
 | ||||
|     atColon :: Text -> SimpleTextParser [Tag] | ||||
|     atColon :: Text -> SimpleTextParser [(SourcePos, Tag)] | ||||
|     atColon tagName = do | ||||
|       char ':' | ||||
|       if T.null tagName | ||||
|         then tagsp | ||||
|         else (:) <$> fmap (tagName,) tagValue <*> tagsp | ||||
|         then tagswithvaluepositions | ||||
|         else do | ||||
|           pos <- getPosition | ||||
|           (:) <$> fmap (\val -> (pos, (tagName, val))) tagValue | ||||
|               <*> tagswithvaluepositions | ||||
| 
 | ||||
|     atEof :: SimpleTextParser [Tag] | ||||
|     atEof :: SimpleTextParser [(SourcePos, Tag)] | ||||
|     atEof = eof *> pure [] | ||||
| 
 | ||||
| tagvaluep :: TextParser m Text | ||||
| tagvaluep = do | ||||
|   -- ptrace "tagvalue" | ||||
|   v <- anyChar `manyTill` (void (try (char ',')) <|> eolof) | ||||
|   return $ T.pack $ strip $ reverse $ dropWhile (==',') $ reverse $ strip v | ||||
| 
 | ||||
| --- ** posting dates | ||||
| 
 | ||||
| -- | Parse all posting dates found in a string. Posting dates can be | ||||
| @ -982,52 +1010,12 @@ tagvaluep = do | ||||
| postingdatesp :: Monad m => Maybe Day -> ErroringJournalParser m [(TagName,Day)] | ||||
| postingdatesp mdefdate = do | ||||
|   -- pdbg 0 $ "postingdatesp" | ||||
|   let p = ((:[]) <$> datetagp mdefdate) <|> bracketeddatetagsp mdefdate | ||||
|   let p = bracketeddatetagsp mdefdate | ||||
|       nonp = | ||||
|          many (notFollowedBy p >> anyChar) | ||||
|          -- anyChar `manyTill` (lookAhead (try (p >> return ()) <|> eof)) | ||||
|   concat <$> many (try (nonp >> p)) | ||||
| 
 | ||||
| --- ** date tags | ||||
| 
 | ||||
| -- | Date tags are tags with name "date" or "date2". Their value is | ||||
| -- parsed as a date, using the provided default date if any for | ||||
| -- inferring a missing year if needed. Any error in date parsing is | ||||
| -- reported and terminates parsing. | ||||
| -- | ||||
| -- >>> rejp (datetagp Nothing) "date: 2000/1/2 " | ||||
| -- Right ("date",2000-01-02) | ||||
| -- | ||||
| -- >>> rejp (datetagp (Just $ fromGregorian 2001 2 3)) "date2:3/4" | ||||
| -- Right ("date2",2001-03-04) | ||||
| -- | ||||
| -- >>> rejp (datetagp Nothing) "date:  3/4" | ||||
| -- Left ...1:9...partial date 3/4 found, but the current year is unknown... | ||||
| -- | ||||
| datetagp :: Monad m => Maybe Day -> ErroringJournalParser m (TagName,Day) | ||||
| datetagp mdefdate = do | ||||
|   -- pdbg 0 "datetagp" | ||||
|   string "date" | ||||
|   n <- fromMaybe "" <$> optional (mptext "2") | ||||
|   char ':' | ||||
|   startpos <- getPosition | ||||
|   v <- lift tagvaluep | ||||
|   -- re-parse value as a date. | ||||
|   j <- get | ||||
|   let ep :: Either (ParseError Char MPErr) Day | ||||
|       ep = parseWithState' | ||||
|              j{jparsedefaultyear=first3.toGregorian <$> mdefdate} | ||||
|              -- The value extends to a comma, newline, or end of file. | ||||
|              -- It seems like ignoring any extra stuff following a date | ||||
|              -- gives better errors here. | ||||
|              (do | ||||
|                  setPosition startpos | ||||
|                  datep) -- <* eof) | ||||
|              v | ||||
|   case ep | ||||
|     of Left e  -> throwError $ parseErrorPretty e | ||||
|        Right d -> return ("date"<>n, d) | ||||
| 
 | ||||
| --- ** bracketed dates | ||||
| 
 | ||||
| -- tagorbracketeddatetagsp :: Monad m => Maybe Day -> TextParser u m [Tag] | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user