aboutsummaryrefslogtreecommitdiff
path: root/src/journal_lib/parse/parsers/p_ledger.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/journal_lib/parse/parsers/p_ledger.py')
-rw-r--r--src/journal_lib/parse/parsers/p_ledger.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/journal_lib/parse/parsers/p_ledger.py b/src/journal_lib/parse/parsers/p_ledger.py
new file mode 100644
index 0000000..ad01a79
--- /dev/null
+++ b/src/journal_lib/parse/parsers/p_ledger.py
@@ -0,0 +1,134 @@
+from datetime import datetime
+
+from journal_lib.parse.parsewrapper import ParseWrapper
+from journal_lib.parse.lexers.l_ledger import JournalLexer
+from journal_lib.dataclasses import Journal, JournalEntry, JournalEntryTransaction, JournalAccountDef, JournalCommodityDef
+
+class JournalParser(ParseWrapper):
+ tokens = JournalLexer.tokens
+
+ def p_journal(self, p):
+ '''journal : elements '''
+ p[0] = Journal.from_elements(p[1])
+
+ if self.debug:
+ for x in p[1]:
+ print(repr(x))
+
+ def p_elements(self, p):
+ '''elements : elements element
+ | element'''
+ if len(p) == 3:
+ p[0] = p[1] + [p[2]]
+ else:
+ p[0] = [p[1]]
+
+ def p_element_entry(self, p):
+ '''element : DATE effective_date status TEXT transactions'''
+ p[0] = JournalEntry(
+ date = p[1],
+ effective_date = p[2],
+ cleared = p[3]['cleared'],
+ pending = p[3]['pending'],
+ title = p[4],
+ transactions = p[5]['transactions'],
+ comments = p[5]['comments']
+ )
+
+ def p_element_account(self, p):
+ '''element : KW_ACCOUNT TEXT COMMENT
+ | KW_ACCOUNT TEXT'''
+ p[0] = JournalAccountDef(account=p[2], comment=p[3] if len(p) > 3 else None)
+
+ def p_element_commodity(self, p):
+ '''element : KW_COMMODITY TEXT commodity_attributes '''
+ p[0] = JournalCommodityDef(commodity=p[2], **p[3])
+
+ def p_commodity_attributes(self, p):
+ '''commodity_attributes : COMMODITY_FORMAT TEXT commodity_attributes
+ | COMMODITY_NOTE TEXT commodity_attributes
+ | COMMODITY_NOMARKET commodity_attributes
+ | COMMODITY_DEFAULT commodity_attributes
+ | empty
+ '''
+ p[0] = {}
+ if p[1] == "format":
+ p[0]["format"] = p[2]
+ elif p[1] == "note":
+ p[0]["note"] = p[2]
+ elif p[1] == "nomarket":
+ p[0]["nomarket"] = True
+ elif p[1] == "default":
+ p[0]["default"] = True
+ if len(p) > 3 and p[3]:
+ p[0].update(p[3])
+
+ def p_effective_date(self, p):
+ '''effective_date : ENTRY_EFFECTIVE_DATE_SEPARATOR DATE
+ | empty
+ '''
+ p[0] = p[2] if p[1] else None
+
+ def p_status(self, p):
+ '''status : ENTRY_STATUS
+ | empty
+ '''
+ p[0] = {'cleared': p[1] == "*", 'pending': p[1] == "!"} if p[1] else {'cleared': False, 'pending': False}
+
+ def p_empty(self, p):
+ '''empty :'''
+ pass
+
+ def p_transactions(self, p):
+ '''transactions : transactions transaction'''
+ p[0] = {"comments": p[1]['comments'],
+ "transactions": p[1]['transactions'] + [p[2]]}
+
+ def p_comments(self, p):
+ '''transactions : transactions COMMENT'''
+ p[0] = {"comments": p[1]['comments'] + [p[2]],
+ "transactions": p[1]['transactions']}
+
+ def p_transactions_single(self, p):
+ '''transactions : transaction '''
+ p[0] = {"comments": [], "transactions": [p[1]]}
+
+ def p_transactions_comment_single(self, p):
+ '''transactions : COMMENT '''
+ p[0] = {"comments": [p[1]], "transactions": []}
+
+ def p_amount_prefixed(self, p):
+ '''amount : CURRENCY AMOUNT'''
+ p[0] = {'currency': p[1], 'amount': p[2]}
+
+ def p_amount_suffixed(self, p):
+ '''amount : AMOUNT CURRENCY'''
+ p[0] = {'currency': p[2], 'amount': p[1]}
+
+ def p_transaction_with_amount(self, p):
+ '''transaction : TEXT amount INLINE_COMMENT
+ | TEXT amount'''
+
+ p[0] = JournalEntryTransaction(
+ account = p[1],
+ currency = p[2]['currency'],
+ amount = p[2]['amount'],
+ comment = p[3] if len(p) > 3 else None
+ )
+
+ def p_transaction_without_amount(self, p):
+ '''transaction : TEXT INLINE_COMMENT
+ | TEXT'''
+ p[0] = JournalEntryTransaction(
+ account = p[1],
+ currency = None,
+ amount = None,
+ comment = p[2] if len(p) > 2 else None
+ )
+
+ def p_error(self, p):
+ if p:
+ self._hl_token(p)
+ else:
+ print("Syntax error at EOF")
+