mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-07 21:15:19 +03:00
lib: add a copy of the ledger4 parser
This adds some or all of these as new dependencies for hledger-lib: parsers, parsec, attoparsec, trifecta
This commit is contained in:
parent
a64dea651e
commit
f5ee020b88
@ -53,6 +53,9 @@ flag oldtime
|
||||
default: False
|
||||
|
||||
library
|
||||
hs-source-dirs:
|
||||
other/ledger-parse
|
||||
, .
|
||||
ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans
|
||||
build-depends:
|
||||
base >=4.3 && <5
|
||||
@ -81,6 +84,9 @@ library
|
||||
, uglymemo
|
||||
, utf8-string >=0.3.5 && <1.1
|
||||
, HUnit
|
||||
, parsers >= 0.5
|
||||
, system-filepath
|
||||
, trifecta >= 0.91
|
||||
, parsec
|
||||
, semigroups
|
||||
if impl(ghc <7.6)
|
||||
@ -135,13 +141,16 @@ library
|
||||
Hledger.Utils.Tree
|
||||
Hledger.Utils.UTF8IOCompat
|
||||
other-modules:
|
||||
Ledger.Parser.Text
|
||||
Paths_hledger_lib
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite doctests
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs:
|
||||
tests
|
||||
other/ledger-parse
|
||||
, .
|
||||
, tests
|
||||
ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans
|
||||
main-is: doctests.hs
|
||||
build-depends:
|
||||
@ -171,18 +180,65 @@ test-suite doctests
|
||||
, uglymemo
|
||||
, utf8-string >=0.3.5 && <1.1
|
||||
, HUnit
|
||||
, parsers >= 0.5
|
||||
, system-filepath
|
||||
, trifecta >= 0.91
|
||||
, doctest >=0.8
|
||||
, Glob >=0.7
|
||||
if impl(ghc <7.6)
|
||||
build-depends:
|
||||
ghc-prim
|
||||
other-modules:
|
||||
Ledger.Parser.Text
|
||||
Hledger
|
||||
Hledger.Data
|
||||
Hledger.Data.Account
|
||||
Hledger.Data.AccountName
|
||||
Hledger.Data.Amount
|
||||
Hledger.Data.Commodity
|
||||
Hledger.Data.Dates
|
||||
Hledger.Data.Journal
|
||||
Hledger.Data.Ledger
|
||||
Hledger.Data.Period
|
||||
Hledger.Data.Posting
|
||||
Hledger.Data.RawOptions
|
||||
Hledger.Data.StringFormat
|
||||
Hledger.Data.Timeclock
|
||||
Hledger.Data.Transaction
|
||||
Hledger.Data.Types
|
||||
Hledger.Query
|
||||
Hledger.Read
|
||||
Hledger.Read.Common
|
||||
Hledger.Read.CsvReader
|
||||
Hledger.Read.JournalReader
|
||||
Hledger.Read.TimeclockReader
|
||||
Hledger.Read.TimedotReader
|
||||
Hledger.Reports
|
||||
Hledger.Reports.BalanceHistoryReport
|
||||
Hledger.Reports.BalanceReport
|
||||
Hledger.Reports.EntriesReport
|
||||
Hledger.Reports.MultiBalanceReports
|
||||
Hledger.Reports.PostingsReport
|
||||
Hledger.Reports.ReportOptions
|
||||
Hledger.Reports.TransactionsReports
|
||||
Hledger.Utils
|
||||
Hledger.Utils.Debug
|
||||
Hledger.Utils.Parse
|
||||
Hledger.Utils.Regex
|
||||
Hledger.Utils.String
|
||||
Hledger.Utils.Test
|
||||
Hledger.Utils.Text
|
||||
Hledger.Utils.Tree
|
||||
Hledger.Utils.UTF8IOCompat
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite hunittests
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: hunittests.hs
|
||||
hs-source-dirs:
|
||||
tests
|
||||
other/ledger-parse
|
||||
, .
|
||||
, tests
|
||||
ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans
|
||||
build-depends:
|
||||
base >=4.3 && <5
|
||||
@ -211,6 +267,9 @@ test-suite hunittests
|
||||
, uglymemo
|
||||
, utf8-string >=0.3.5 && <1.1
|
||||
, HUnit
|
||||
, parsers >= 0.5
|
||||
, system-filepath
|
||||
, trifecta >= 0.91
|
||||
, hledger-lib
|
||||
, test-framework
|
||||
, test-framework-hunit
|
||||
@ -224,4 +283,46 @@ test-suite hunittests
|
||||
else
|
||||
build-depends:
|
||||
time >=1.5
|
||||
other-modules:
|
||||
Ledger.Parser.Text
|
||||
Hledger
|
||||
Hledger.Data
|
||||
Hledger.Data.Account
|
||||
Hledger.Data.AccountName
|
||||
Hledger.Data.Amount
|
||||
Hledger.Data.Commodity
|
||||
Hledger.Data.Dates
|
||||
Hledger.Data.Journal
|
||||
Hledger.Data.Ledger
|
||||
Hledger.Data.Period
|
||||
Hledger.Data.Posting
|
||||
Hledger.Data.RawOptions
|
||||
Hledger.Data.StringFormat
|
||||
Hledger.Data.Timeclock
|
||||
Hledger.Data.Transaction
|
||||
Hledger.Data.Types
|
||||
Hledger.Query
|
||||
Hledger.Read
|
||||
Hledger.Read.Common
|
||||
Hledger.Read.CsvReader
|
||||
Hledger.Read.JournalReader
|
||||
Hledger.Read.TimeclockReader
|
||||
Hledger.Read.TimedotReader
|
||||
Hledger.Reports
|
||||
Hledger.Reports.BalanceHistoryReport
|
||||
Hledger.Reports.BalanceReport
|
||||
Hledger.Reports.EntriesReport
|
||||
Hledger.Reports.MultiBalanceReports
|
||||
Hledger.Reports.PostingsReport
|
||||
Hledger.Reports.ReportOptions
|
||||
Hledger.Reports.TransactionsReports
|
||||
Hledger.Utils
|
||||
Hledger.Utils.Debug
|
||||
Hledger.Utils.Parse
|
||||
Hledger.Utils.Regex
|
||||
Hledger.Utils.String
|
||||
Hledger.Utils.Test
|
||||
Hledger.Utils.Text
|
||||
Hledger.Utils.Tree
|
||||
Hledger.Utils.UTF8IOCompat
|
||||
default-language: Haskell2010
|
||||
|
19
hledger-lib/other/ledger-parse/LICENSE
Normal file
19
hledger-lib/other/ledger-parse/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
opyright (c) 2012 John Wiegley
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
219
hledger-lib/other/ledger-parse/Ledger/Parser/Text.hs
Normal file
219
hledger-lib/other/ledger-parse/Ledger/Parser/Text.hs
Normal file
@ -0,0 +1,219 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Ledger.Parser.Text
|
||||
( parseJournalFile
|
||||
, RawJournal(..)
|
||||
, RawEntity(..)
|
||||
, RawEntityInSitu(..)
|
||||
, RawPosting(..)
|
||||
, RawTransaction(..)
|
||||
, RawAutoTxn(..)
|
||||
, RawPeriodTxn(..)
|
||||
-- , main
|
||||
) where
|
||||
|
||||
import Control.Applicative
|
||||
import Data.ByteString as B hiding (pack, unpack, singleton,
|
||||
zipWith, concat)
|
||||
import Data.Maybe
|
||||
import qualified Data.Text.Encoding as E
|
||||
import Filesystem.Path.CurrentOS hiding (concat)
|
||||
import Prelude hiding (FilePath, readFile, until)
|
||||
import Text.Parser.Combinators
|
||||
import Text.Parser.LookAhead
|
||||
import Text.Parser.Token
|
||||
import Text.Trifecta
|
||||
import Text.Trifecta.Delta
|
||||
-- import Control.DeepSeq
|
||||
-- import Criterion
|
||||
-- import Criterion.Main
|
||||
|
||||
infixl 4 <$!>
|
||||
|
||||
(<$!>) :: TokenParsing m => (a -> b) -> m a -> m b
|
||||
f <$!> ma = ($!) <$> pure f <*> ma
|
||||
|
||||
data RawJournal = RawJournal [RawEntity]
|
||||
deriving (Show, Eq)
|
||||
|
||||
data RawEntity = Whitespace String
|
||||
| FileComment String
|
||||
| Directive { directiveChar :: Maybe Char
|
||||
, directiveName :: !String
|
||||
, directiveArg :: Maybe String }
|
||||
| RawTransactionEntity RawTransaction
|
||||
| RawAutoTxnEntity RawAutoTxn
|
||||
| RawPeriodTxnEntity RawPeriodTxn
|
||||
| EndOfFile
|
||||
deriving (Show, Eq)
|
||||
|
||||
data RawEntityInSitu = RawEntityInSitu { rawEntityIndex :: !Int
|
||||
, rawEntityStartPos :: !Rendering
|
||||
, rawEntity :: !RawEntity
|
||||
, rawEntityEndPos :: !Rendering }
|
||||
|
||||
instance Show RawEntityInSitu where
|
||||
show x = show (rawEntity x) ++ "\n"
|
||||
|
||||
data RawPosting = RawPosting { rawPostState :: Maybe Char
|
||||
, rawPostAccount :: !String
|
||||
, rawPostAmount :: Maybe String
|
||||
, rawPostNote :: Maybe String }
|
||||
| RawPostingNote !String
|
||||
deriving (Show, Eq)
|
||||
|
||||
data RawTransaction = RawTransaction { rawTxnDate :: !String
|
||||
, rawTxnDateAux :: Maybe String
|
||||
, rawTxnState :: Maybe Char
|
||||
, rawTxnCode :: Maybe String
|
||||
, rawTxnDesc :: !String
|
||||
, rawTxnNote :: Maybe String
|
||||
, rawTxnPosts :: ![RawPosting] }
|
||||
deriving (Show, Eq)
|
||||
|
||||
data RawAutoTxn = RawAutoTxn { rawATxnQuery :: !String
|
||||
, rawATxnPosts :: ![RawPosting] }
|
||||
deriving (Show, Eq)
|
||||
|
||||
data RawPeriodTxn = RawPeriodTxn { rawPTxnPeriod :: !String
|
||||
, rawPTxnPosts :: ![RawPosting] }
|
||||
deriving (Show, Eq)
|
||||
|
||||
txnDateParser :: TokenParsing m => m String
|
||||
txnDateParser = some (digit <|> oneOf "/-." <|> letter)
|
||||
<?> "transaction date"
|
||||
|
||||
longSep :: CharParsing m => m ()
|
||||
longSep = () <$ (try (char ' ' *> char ' ') <|> tab)
|
||||
|
||||
noteParser :: (LookAheadParsing m, CharParsing m) => m String
|
||||
noteParser = char ';' *> manyTill anyChar (try (lookAhead endOfLine))
|
||||
<?> "note"
|
||||
|
||||
longSepOrEOL :: (LookAheadParsing m, CharParsing m) => m ()
|
||||
longSepOrEOL = try (lookAhead (longSep <|> endOfLine))
|
||||
|
||||
longSepOrEOLIf :: (LookAheadParsing m, CharParsing m) => m p -> m ()
|
||||
longSepOrEOLIf p = try (lookAhead ((() <$ longSep <* p) <|> endOfLine))
|
||||
|
||||
until :: CharParsing m => m () -> m String
|
||||
until end = (:) <$> noneOf "\r\n" <*> manyTill anyChar end
|
||||
|
||||
tokenP :: TokenParsing m => m p -> m p
|
||||
tokenP p = p <* skipMany spaceChars
|
||||
|
||||
postingParser :: (LookAheadParsing m, TokenParsing m) => m RawPosting
|
||||
postingParser =
|
||||
(RawPosting <$!> (some spaceChars *>
|
||||
optional (tokenP (char '*' <|> char '!')))
|
||||
<*> tokenP (until longSepOrEOL)
|
||||
<*> optional (tokenP (until (longSepOrEOLIf (char ';'))))
|
||||
<*> (optional noteParser <* endOfLine)
|
||||
<?> "posting")
|
||||
<|>
|
||||
(RawPostingNote <$!> (concat <$!>
|
||||
some ((++) <$!> (some spaceChars *> noteParser)
|
||||
<*> ((:[]) <$> endOfLineChar)))
|
||||
<?> "posting note")
|
||||
|
||||
spaceChars :: CharParsing m => m ()
|
||||
spaceChars = () <$ oneOf " \t"
|
||||
|
||||
regularTxnParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
regularTxnParser = RawTransactionEntity <$!> go
|
||||
where go = RawTransaction
|
||||
<$!> txnDateParser
|
||||
<*> optional (char '=' *> txnDateParser)
|
||||
<*> (many spaceChars *>
|
||||
optional (tokenP (char '*' <|> char '!')))
|
||||
<*> optional
|
||||
(tokenP (parens (many (noneOf ")\r\n"))))
|
||||
<*> tokenP (until (longSepOrEOLIf (char ';')))
|
||||
<*> optional noteParser
|
||||
<*> (endOfLine *> some postingParser)
|
||||
<?> "regular transaction"
|
||||
|
||||
automatedTxnParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
automatedTxnParser = RawAutoTxnEntity <$!> go
|
||||
where go = RawAutoTxn
|
||||
<$!> (tokenP (char '=') *>
|
||||
manyTill anyChar (try (lookAhead endOfLine)))
|
||||
<*> (endOfLine *> some postingParser)
|
||||
<?> "automated transaction"
|
||||
|
||||
periodicTxnParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
periodicTxnParser = RawPeriodTxnEntity <$!> go
|
||||
where go = RawPeriodTxn
|
||||
<$!> (tokenP (char '~') *>
|
||||
manyTill anyChar (try (lookAhead endOfLine)))
|
||||
<*> (endOfLine *> some postingParser)
|
||||
<?> "periodic transaction"
|
||||
|
||||
transactionParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
transactionParser = regularTxnParser
|
||||
<|> automatedTxnParser
|
||||
<|> periodicTxnParser
|
||||
<?> "transaction"
|
||||
|
||||
directiveParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
directiveParser =
|
||||
Directive <$!> optional (oneOf "@!")
|
||||
<*> ((:) <$!> letter <*> tokenP (many alphaNum))
|
||||
<*> (optional
|
||||
((:) <$!> noneOf "\r\n"
|
||||
<*> manyTill anyChar (try (lookAhead endOfLine)))
|
||||
<* endOfLine)
|
||||
<?> "directive"
|
||||
|
||||
endOfLine :: CharParsing m => m ()
|
||||
endOfLine = () <$ endOfLineChar
|
||||
|
||||
endOfLineChar :: CharParsing m => m Char
|
||||
endOfLineChar = skipOptional (char '\r') *> char '\n'
|
||||
|
||||
commentParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
commentParser = FileComment
|
||||
<$!> (concat <$!>
|
||||
some ((++) <$!> noteParser
|
||||
<*> ((:[]) <$> endOfLineChar)))
|
||||
<?> "comment"
|
||||
|
||||
whitespaceParser :: TokenParsing m => m RawEntity
|
||||
whitespaceParser = Whitespace <$!> some space <?> "whitespace"
|
||||
|
||||
entityParser :: (LookAheadParsing m, TokenParsing m) => m RawEntity
|
||||
entityParser = directiveParser
|
||||
<|> commentParser
|
||||
<|> whitespaceParser
|
||||
<|> transactionParser
|
||||
<?> "journal"
|
||||
|
||||
rendCaret :: DeltaParsing m => m Rendering
|
||||
rendCaret = addCaret <$!> position <*> rend
|
||||
|
||||
journalParser :: (LookAheadParsing m, DeltaParsing m) => m [RawEntityInSitu]
|
||||
journalParser =
|
||||
many (RawEntityInSitu <$!> pure 0 <*> rendCaret <*> entityParser <*> rendCaret)
|
||||
|
||||
parseJournalFile :: FilePath -> ByteString -> Result [RawEntityInSitu]
|
||||
parseJournalFile file contents =
|
||||
let filepath = either id id $ toText file
|
||||
start = Directed (E.encodeUtf8 filepath) 0 0 0 0
|
||||
in zipWith (\e i -> e { rawEntityIndex = i})
|
||||
<$> parseByteString journalParser start contents
|
||||
<*> pure [1..]
|
||||
|
||||
-- testme :: IO (Result [RawEntityInSitu])
|
||||
-- testme =
|
||||
-- let file = "/Users/johnw/Documents/Finances/ledger.dat"
|
||||
-- in parseJournalFile (fromText (T.pack file)) <$> B.readFile file
|
||||
|
||||
-- instance NFData RawEntityInSitu
|
||||
-- instance NFData (Result a)
|
||||
|
||||
-- main = do let file = "/Users/johnw/Documents/Finances/ledger.dat"
|
||||
-- bs <- B.readFile file
|
||||
-- defaultMain [
|
||||
-- bench "main" $ nf (parseJournalFile (fromText (T.pack file))) bs ]
|
||||
|
||||
-- Text.hs ends here
|
4
hledger-lib/other/ledger-parse/README
Normal file
4
hledger-lib/other/ledger-parse/README
Normal file
@ -0,0 +1,4 @@
|
||||
This is the parser code from John W's
|
||||
https://github.com/ledger/ledger4/tree/master/ledger-parse ,
|
||||
revision 8fb414c + updates for latest parsers lib.
|
||||
Later, perhaps it will be a published lib and we can remove this copy.
|
@ -65,6 +65,10 @@ dependencies:
|
||||
- uglymemo
|
||||
- utf8-string >=0.3.5 && <1.1
|
||||
- HUnit
|
||||
# for ledger-parse:
|
||||
- parsers >= 0.5
|
||||
- system-filepath
|
||||
- trifecta >= 0.91
|
||||
ghc-options:
|
||||
- -Wall
|
||||
- -fno-warn-unused-do-bind
|
||||
@ -72,6 +76,9 @@ ghc-options:
|
||||
- -fno-warn-missing-signatures
|
||||
- -fno-warn-type-defaults
|
||||
- -fno-warn-orphans
|
||||
source-dirs:
|
||||
- other/ledger-parse
|
||||
- .
|
||||
library:
|
||||
exposed-modules:
|
||||
- Hledger
|
||||
|
Loading…
Reference in New Issue
Block a user