all repos

clerk @ e76a121

missing tooling for ledger/hledger

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

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
lsp: date completion, 1 month ago
1
package ast
2
3
import (
4
	"fmt"
5
	"strings"
6
7
	"olexsmir.xyz/clerk/journal/token"
8
)
9
10
type Journal struct {
11
	Entries []Entry
12
	Errors  []*ParseError
13
}
14
15
type Entry interface {
16
	entryNode()
17
}
18
19
type ParseError struct {
20
	Span    token.Span
21
	Message string
22
}
23
24
type FileError struct {
25
	Path    string
26
	Span    token.Span
27
	Message string
28
}
29
30
type Date struct {
31
	Year, Month, Day int
32
	Sep              byte // '-' '/' '.'
33
	Span             token.Span
34
}
35
36
// Compare returns -1 if d is before other, 0 if equal, 1 if after.
37
func (d Date) Compare(other Date) int {
38
	if d.Year != other.Year {
39
		if d.Year < other.Year {
40
			return -1
41
		}
42
		return 1
43
	}
44
	if d.Month != other.Month {
45
		if d.Month < other.Month {
46
			return -1
47
		}
48
		return 1
49
	}
50
	if d.Day != other.Day {
51
		if d.Day < other.Day {
52
			return -1
53
		}
54
		return 1
55
	}
56
	return 0
57
}
58
59
// String renders d as written: with its own separator, and without the year
60
// when the date carried none. Returns "" for an unset or invalid date.
61
func (d Date) String() string {
62
	if (d.Year == 0 && d.Month == 0 && d.Day == 0) ||
63
		(d.Month < 1 || d.Month > 12 || d.Day < 1 || d.Day > 31) {
64
		return ""
65
	}
66
	sep := d.Sep
67
	if sep == 0 {
68
		sep = '-'
69
	}
70
	if d.Year == 0 {
71
		return fmt.Sprintf("%d%c%d", d.Month, sep, d.Day)
72
	}
73
	return fmt.Sprintf("%04d%c%02d%c%02d", d.Year, sep, d.Month, sep, d.Day)
74
}
75
76
type Time struct {
77
	Hour, Minute, Second int
78
	Span                 token.Span
79
}
80
81
type DateTime struct {
82
	Date Date
83
	Time *Time
84
	Span token.Span
85
}
86
87
type Tag struct {
88
	Key, Value string
89
	Span       token.Span
90
}
91
92
type Comment struct {
93
	Marker byte // ';' '#' '%' '*'
94
	Tags   []Tag
95
	Text   string
96
	Span   token.Span
97
}
98
99
func (Comment) entryNode() {}
100
101
type StatusType int
102
103
func (s StatusType) String() string {
104
	switch s {
105
	case StatusCleared:
106
		return "*"
107
	case StatusPending:
108
		return "!"
109
	case StatusNone:
110
		return ""
111
	default:
112
		panic("unreachable")
113
	}
114
}
115
116
const (
117
	StatusNone    StatusType = iota // not set
118
	StatusCleared                   // * cleared
119
	StatusPending                   // ! pending
120
)
121
122
type Status struct {
123
	Value StatusType
124
	Span  token.Span
125
}
126
127
type Code struct {
128
	Value string
129
	Span  token.Span
130
}
131
132
type Note struct {
133
	Value string
134
	Span  token.Span
135
}
136
137
type Description struct {
138
	Value string
139
	Span  token.Span
140
}
141
142
type Expr struct {
143
	Value string
144
	Span  token.Span
145
}
146
147
type Payee struct {
148
	Name string
149
	Span token.Span
150
}
151
152
type SubAccount struct {
153
	Name string
154
	Span token.Span
155
}
156
157
type Account struct {
158
	Name []SubAccount // ['expenses' 'food']
159
	Span token.Span
160
}
161
162
func (a Account) String() string {
163
	if len(a.Name) == 0 {
164
		return ""
165
	}
166
	var name strings.Builder
167
	name.Grow(len(a.Name))
168
	name.WriteString(a.Name[0].Name)
169
	for _, s := range a.Name[1:] {
170
		name.WriteByte(':')
171
		name.WriteString(s.Name)
172
	}
173
	return name.String()
174
}