all repos

clerk @ 0ff087c

missing tooling for ledger/hledger

clerk/journal/ast/entries.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
ast: add constructor functions to help with building ast by hand, 1 month ago
1
package ast
2
3
import (
4
	"olexsmir.xyz/clerk/internal/decimal"
5
	"olexsmir.xyz/clerk/journal/token"
6
)
7
8
type BlankLine struct{ Span token.Span }
9
10
func (BlankLine) entryNode() {}
11
12
type Transaction struct {
13
	Date           Date
14
	SecondDate     *Date      // optional =2026-05-18 date
15
	Status         StatusType // optional */! status
16
	StatusSpan     token.Span
17
	Code           string // optional (123) code
18
	CodeSpan       token.Span
19
	Payee          string // optional payee
20
	PayeeSpan      token.Span
21
	Note           string // part after |
22
	NoteSpan       token.Span
23
	Comment        *Comment   // inline ; on header line
24
	HeaderComments []*Comment // indented ; lines before first posting
25
	Postings       []Posting
26
	Span           token.Span
27
}
28
29
func (Transaction) entryNode() {}
30
31
type Period struct {
32
	Raw  string // "monthly", "every 2 weeks"
33
	From *Date
34
	To   *Date
35
	Span token.Span
36
}
37
38
func (Period) entryNode() {}
39
40
type PeriodicTransaction struct {
41
	Period          Period // period-expr
42
	Status          StatusType
43
	StatusSpan      token.Span
44
	Code            string
45
	CodeSpan        token.Span
46
	Description     string
47
	DescriptionSpan token.Span
48
	Comment         *Comment // optional inline comment
49
	HeaderComments  []*Comment
50
	Postings        []Posting
51
	Span            token.Span
52
}
53
54
func (PeriodicTransaction) entryNode() {}
55
56
type AutomatedTransaction struct {
57
	Expr           string
58
	ExprSpan       token.Span
59
	Postings       []Posting
60
	Comment        *Comment   // inline ; on header line
61
	HeaderComments []*Comment // indented ; lines before first posting
62
	Span           token.Span
63
}
64
65
func (AutomatedTransaction) entryNode() {}
66
67
type PostingType int
68
69
const (
70
	PostingReal              PostingType = iota
71
	PostingVirtualBalanced               // '['
72
	PostingVirtualUnbalanced             // '('
73
)
74
75
func (p PostingType) String() string {
76
	switch p {
77
	case PostingReal:
78
		return "real"
79
	case PostingVirtualBalanced:
80
		return "balanced virtual"
81
	case PostingVirtualUnbalanced:
82
		return "unbalanced virtual"
83
	default:
84
		panic("unreachable")
85
	}
86
}
87
88
type Posting struct {
89
	Type       PostingType
90
	Status     StatusType
91
	StatusSpan token.Span
92
	Account    Account
93
	Amount     *Amount // nil == auto-balancing
94
	Cost       *Cost   // @ @@
95
	Balance    *BalanceAssertion
96
	Comment    *Comment
97
	Comments   []Comment // continuation comment lines
98
	Span       token.Span
99
}
100
101
type Amount struct {
102
	IsNegative    bool
103
	Quantity      decimal.Decimal
104
	QuantityFmt   QuantityFormat
105
	Commodity     string
106
	CommodityPos  CommodityPos // Before | After
107
	CommoditySpan token.Span   // span of the commodity within the amount
108
	HasSpace      bool         // "$10" vs "$ 10"
109
	IsExpr        bool         // e.g: *-1
110
	Expr          string       // expression text e.g. "amount * -1". set only if IsExpr is true
111
	Span          token.Span
112
}
113
114
// Quantity parses s as a decimal quantity. Helper for handcrafting ast.
115
func Quantity(s string) (decimal.Decimal, error) {
116
	return decimal.FromString(s)
117
}
118
119
// MustQuantity same as [Quantity] but panics in case of an error.
120
func MustQuantity(s string) decimal.Decimal {
121
	d, err := decimal.FromString(s)
122
	if err != nil {
123
		panic(err)
124
	}
125
	return d
126
}
127
128
type Cost struct {
129
	IsTotal bool // @ vs @@
130
	Amount  Amount
131
	Span    token.Span
132
}
133
134
type BalanceAssertion struct {
135
	IsStrict     bool // ==  vs =
136
	IsInclusive  bool // =* or === (inclusive of subaccounts)
137
	IsAssignment bool // := balance assignment (not a check)
138
	Amount       Amount
139
	Cost         *Cost // price after @/@@
140
	Span         token.Span
141
}
142
143
type CommodityPos int
144
145
func (c CommodityPos) String() string {
146
	if c == CommodityBefore {
147
		return "Before"
148
	}
149
	return "After"
150
}
151
152
const (
153
	CommodityBefore CommodityPos = iota
154
	CommodityAfter
155
)
156
157
type QuantityFormat struct {
158
	Decimal   byte // '.' or ','; 0 when the literal has no explicit decimal mark
159
	Thousands byte // ',' '.' ' ' or 0
160
	Precision int
161
}