aboutsummaryrefslogtreecommitdiff
path: root/src/journal_lib/parse/parsers/p_ledger.py
blob: 6b5d573ba3f7656b095c82aaeb0457ee5e68b2f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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 : COMMODITY AMOUNT"""
        p[0] = {"currency": p[1], "amount": p[2]}

    def p_amount_suffixed(self, p):
        """amount : AMOUNT COMMODITY"""
        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")