all repos

clerk @ ecc31e904b0d92db6b7aedb8f90794a36ab956d2

missing tooling for ledger/hledger
57 files changed, 503 insertions(+), 172 deletions(-)
parser: separate account names by :
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-06-22 18:00:13 +0300
Authored at: 2026-06-11 10:32:20 +0300
Change ID: pwnuqswmzznnptmoknzuormlqxqqwxmp
Parent: 15cdd16
jump to
M journal/ast/ast.go
M journal/ast/directives.go
M journal/ast/dump.go
M journal/journal_test.go
M journal/lexer/lexer.go
M journal/lexer/lexer_test.go
M journal/lexer/testdata/account_directive.golden
A journal/lexer/testdata/account_with_colon.golden
M journal/lexer/testdata/automated_transaction.golden
M journal/lexer/testdata/cleared_transaction.golden
M journal/lexer/testdata/simple_transaction.golden
M journal/lexer/testdata/special_chars_in_description.golden
M journal/lexer/testdata/transaction,_accounts_with_uppercase_latters.golden
M journal/lexer/testdata/transaction_with_code.golden
M journal/lexer/testdata/transaction_with_unicode_commodity_symbols.golden
M journal/lexer/testdata/transaction_with_virtual_accounts.golden
M journal/parser/parser.go
M journal/parser/testdata/account_directive.golden
M journal/parser/testdata/account_directive_with_comment.golden
M journal/parser/testdata/account_with_spaces.golden
M journal/parser/testdata/account_with_subdirectives.golden
M journal/parser/testdata/automated_transaction.golden
M journal/parser/testdata/bad_between_good.golden
M journal/parser/testdata/bad_posting_at_end.golden
M journal/parser/testdata/bad_then_next_transaction.golden
M journal/parser/testdata/comment_between_bad_postings.golden
M journal/parser/testdata/digit_group_marks.golden
M journal/parser/testdata/directive_prefixes.golden
M journal/parser/testdata/illegal_between_transactions.golden
M journal/parser/testdata/illegal_in_posting.golden
M journal/parser/testdata/multiple_bad_postings.golden
M journal/parser/testdata/nested_apply_tag_directives.golden
M journal/parser/testdata/period_transaction_expressions.golden
M journal/parser/testdata/quoted_payee_names.golden
M journal/parser/testdata/recovery_after_bad_posting.golden
M journal/parser/testdata/special_chars_in_description.golden
M journal/parser/testdata/three_bad_postings.golden
M journal/parser/testdata/transaction_in_ukrainian.golden
M journal/parser/testdata/transaction_with_balance_assertion.golden
M journal/parser/testdata/transaction_with_code.golden
M journal/parser/testdata/transaction_with_cost_and_assertion.golden
M journal/parser/testdata/transaction_with_costs.golden
M journal/parser/testdata/transaction_with_digit_payees.golden
M journal/parser/testdata/transaction_with_header_comment.golden
M journal/parser/testdata/transaction_with_inline_comment.golden
M journal/parser/testdata/transaction_with_posting.golden
M journal/parser/testdata/transaction_with_posting_amounts.golden
M journal/parser/testdata/transaction_with_spaced_account_name.golden
M journal/parser/testdata/transaction_with_strange_commodity_symbols.golden
M journal/parser/testdata/transaction_with_tabs.golden
M journal/parser/testdata/transaction_with_trailing_indent.golden
M journal/parser/testdata/transaction_with_unicode_commodity_symbols.golden
M journal/parser/testdata/transaction_with_virtual_accounts.golden
M journal/parser/testdata/virtual_postings_with_statuses.golden
M journal/printer/directives.go
M journal/printer/transaction_postings.go
M journal/tags/tag.go
M journal/ast/ast.go
···
        1
        1
         package ast

      
        2
        2
         

      
        3
        
        -import "olexsmir.xyz/clerk/journal/token"

      
        
        3
        +import (

      
        
        4
        +	"strings"

      
        
        5
        +

      
        
        6
        +	"olexsmir.xyz/clerk/journal/token"

      
        
        7
        +)

      
        4
        8
         

      
        5
        9
         type Journal struct {

      
        6
        10
         	Entries []Entry

      ···
        69
        73
         )

      
        70
        74
         

      
        71
        75
         type Status struct {

      
        72
        
        -	// Value byte // '!' '*'

      
        73
        76
         	Value StatusType

      
        74
        77
         	Span  token.Span

      
        75
        78
         }

      
        76
        79
         

      
        77
        80
         type Payee struct {

      
        
        81
        +	Name string

      
        
        82
        +	Span token.Span

      
        
        83
        +}

      
        
        84
        +

      
        
        85
        +type SubAccount struct {

      
        78
        86
         	Name string

      
        79
        87
         	Span token.Span

      
        80
        88
         }

      
        81
        89
         

      
        82
        90
         type Account struct {

      
        83
        
        -	Name string // 'expenses:food'

      
        
        91
        +	Name []SubAccount // ['expenses' 'food']

      
        84
        92
         	Span token.Span

      
        85
        93
         }

      
        
        94
        +

      
        
        95
        +func (a Account) String() string {

      
        
        96
        +	if len(a.Name) == 0 {

      
        
        97
        +		return ""

      
        
        98
        +	}

      
        
        99
        +	var name strings.Builder

      
        
        100
        +	name.Grow(len(a.Name))

      
        
        101
        +	name.WriteString(a.Name[0].Name)

      
        
        102
        +	for _, s := range a.Name[1:] {

      
        
        103
        +		name.WriteByte(':')

      
        
        104
        +		name.WriteString(s.Name)

      
        
        105
        +	}

      
        
        106
        +	return name.String()

      
        
        107
        +}

      
M journal/ast/directives.go
···
        44
        44
         func (IncludeDirective) entryNode() {}

      
        45
        45
         

      
        46
        46
         type AliasDirective struct {

      
        47
        
        -	From, To string

      
        
        47
        +	From, To Account

      
        48
        48
         	Comment  *Comment // optional inline comment

      
        49
        49
         	Span     token.Span

      
        50
        50
         }

      
M journal/ast/dump.go
···
        296
        296
         

      
        297
        297
         func dumpAccount(b *strings.Builder, a Account, depth int) {

      
        298
        298
         	indent(b, depth)

      
        299
        
        -	fmt.Fprintf(b, "Account %q %s\n", a.Name, a.Span)

      
        
        299
        +	fmt.Fprintf(b, "Account %s\n", a.Span)

      
        
        300
        +	for _, sub := range a.Name {

      
        
        301
        +		indent(b, depth+1)

      
        
        302
        +		fmt.Fprintf(b, "SubAccount: %q %s\n", sub.Name, sub.Span)

      
        
        303
        +	}

      
        300
        304
         }

      
        301
        305
         

      
        302
        306
         func dumpAccountDirective(b *strings.Builder, a *AccountDirective, depth int) {

      
M journal/journal_test.go
···
        20
        20
         	"actual-business.journal":                   {desc: "hledger: simple business transactions with commodities"},

      
        21
        21
         	"actual-goal-budget.journal":                {desc: "hledger: goal budget using periodic transactions"},

      
        22
        22
         	"actual-i18n-en.journal":                    {desc: "hledger: internationalization with account types in English"},

      
        23
        
        -	"actual-ledger-baseline-opt-lots-basis.dat": {desc: "ledger: G/S prefixes"},

      
        
        23
        +	"actual-ledger-baseline-opt-lots-basis.dat": {err: true, desc: "ledger: G/S prefixes"}, // no lot support yet

      
        24
        24
         	"actual-ledger-input-divzero.dat":           {desc: "ledger: fuzz corpus, designed to cause divide-by-zero"},

      
        25
        25
         	"actual-ledger-input-parsing.dat":           {desc: "ledger: fuzz corpus, tests EOF without newline"},

      
        26
        26
         	"actual-ledger-input-sample.dat":            {desc: "ledger: fuzz corpus, default commodity directive"},

      
        27
        27
         	"actual-ledger-input-standard.dat":          {desc: "ledger: fuzz corpus, standard ledger format"},

      
        28
        28
         	"actual-ledger-input-transfer.dat":          {desc: "ledger: fuzz corpus, byte quantity (non-monetary)"},

      
        29
        
        -	"actual-ledger-input-wow.dat":               {desc: "ledger-cli: fuzz corpus, World of Warcraft currency (1G=100s)"},

      
        
        29
        +	"actual-ledger-input-wow.dat":               {err: true, desc: "ledger-cli: fuzz corpus, World of Warcraft currency (1G=100s)"}, // no lot support ye

      
        30
        30
         	"actual-multicurrency.journal":              {desc: "hledger: multi-currency transactions with HRK/EUR"},

      
        31
        31
         	"actual-personal.journal":                   {desc: "hledger: simple personal finance example"},

      
        32
        32
         	"actual-quickstart.journal":                 {desc: "hledger: quickstart guide with commodity directive"},

      
M journal/lexer/lexer.go
···
        51
        51
         	col    int  // current column (1-based)

      
        52
        52
         	line   int  // current line (1-based)

      
        53
        53
         

      
        54
        
        -	transactionPastStatus  bool

      
        55
        
        -	postingExpectAccount   bool

      
        
        54
        +	transactionPastStatus bool

      
        
        55
        +	postingExpectAccount  bool

      
        56
        56
         	readingNoteAfterPipe  bool

      
        57
        57
         }

      
        58
        58
         

      ···
        321
        321
         		return l.lexSingle(token.LBRACKET)

      
        322
        322
         	case l.ch == ']':

      
        323
        323
         		return l.lexSingle(token.RBRACKET)

      
        
        324
        +	case l.ch == ':':

      
        
        325
        +		return l.lexSingle(token.COLON)

      
        324
        326
         	case l.postingExpectAccount && l.ch != '*' && l.ch != '!' && l.ch != '(' && l.ch != '[':

      
        325
        
        -		l.postingExpectAccount = false

      
        326
        
        -		return l.lexAccountText()

      
        
        327
        +		return l.lexAccountNamePosting()

      
        327
        328
         	case l.ch == '*': // after account name

      
        328
        329
         		return l.lexSingle(token.STAR)

      
        329
        330
         	case l.isDigit(), l.ch == '.':

      ···
        334
        335
         		return l.lexSingle(token.PLUS)

      
        335
        336
         	case l.isCommodityStart():

      
        336
        337
         		return l.lexCommodityMark()

      
        
        338
        +	case l.ch == '"' || l.ch == '\'':

      
        
        339
        +		return l.lexString()

      
        337
        340
         	case l.ch >= 'a' && l.ch <= 'z':

      
        338
        341
         		return l.lexCommodityMark()

      
        339
        342
         	default:

      
        340
        
        -		return l.lexAccountText()

      
        
        343
        +		return l.lexAccountNamePosting()

      
        341
        344
         	}

      
        342
        345
         }

      
        343
        346
         

      ···
        359
        362
         		return l.lexSingle(token.MINUS)

      
        360
        363
         	case '"', '\'':

      
        361
        364
         		return l.lexString()

      
        
        365
        +	case ':':

      
        
        366
        +		return l.lexSingle(token.COLON)

      
        362
        367
         	default:

      
        363
        368
         		if l.isCommodityStart() {

      
        364
        369
         			return l.lexCommodityMark()

      ···
        372
        377
         		if l.isDigit() {

      
        373
        378
         			return l.lexNumber()

      
        374
        379
         		}

      
        375
        
        -		return l.lexText()

      
        
        380
        +		return l.lexAccountNameDirective()

      
        376
        381
         	}

      
        377
        
        -	// case l.ch == '/': // regex in 'alias'

      
        378
        
        -	// 	return l.lexSingle(token.SLASH)

      
        379
        382
         }

      
        380
        383
         

      
        381
        384
         func (l *Lexer) lexSingle(kind token.Type) token.Token {

      ···
        452
        455
         	return token.Token{Type: token.TEXT, Literal: lit, Span: l.span(s)}

      
        453
        456
         }

      
        454
        457
         

      
        455
        
        -func (l *Lexer) lexAccountText() token.Token {

      
        
        458
        +// lexAccountNameDirective reads accout name in directive context.

      
        
        459
        +// stops at any whitespace, supports multi-word names("Taxi Fare").

      
        
        460
        +func (l *Lexer) lexAccountNameDirective() token.Token {

      
        456
        461
         	s := l.save()

      
        457
        
        -	for l.ch != '\n' && l.ch != ';' && l.ch != 0 && l.ch != ')' && l.ch != ']' {

      
        458
        
        -		// two spaces = end of account name

      
        
        462
        +	for l.ch != '\n' && l.ch != ';' && l.ch != 0 && l.ch != ')' && l.ch != ']' && l.ch != ':' && l.ch != ' ' && l.ch != '\t' {

      
        
        463
        +		l.advance()

      
        
        464
        +	}

      
        
        465
        +	lit := string(l.input[s.offset:l.pos])

      
        
        466
        +	return token.Token{Type: token.TEXT, Literal: lit, Span: l.span(s)}

      
        
        467
        +}

      
        
        468
        +

      
        
        469
        +// lexAccountNamePosting reads an account name in posting context.

      
        
        470
        +// stops at two consecutive spaces.

      
        
        471
        +func (l *Lexer) lexAccountNamePosting() token.Token {

      
        
        472
        +	s := l.save()

      
        
        473
        +	for l.ch != '\n' && l.ch != ';' && l.ch != 0 && l.ch != ')' && l.ch != ']' && l.ch != ':' {

      
        459
        474
         		if l.isTwoSpaces() {

      
        460
        475
         			break

      
        461
        476
         		}

      
        462
        477
         		l.advance()

      
        
        478
        +	}

      
        
        479
        +	if l.ch != ':' {

      
        
        480
        +		l.postingExpectAccount = false

      
        463
        481
         	}

      
        464
        482
         	lit := string(l.input[s.offset:l.pos])

      
        465
        483
         	return token.Token{Type: token.TEXT, Literal: lit, Span: l.span(s)}

      
M journal/lexer/lexer_test.go
···
        39
        39
         `},

      
        40
        40
         		{"transaction with virtual accounts", `2024/01/01 * groceries

      
        41
        41
         	(virtual:account)  1 PESO

      
        42
        
        -	[something:else]   5 PESO

      
        
        42
        +	[some thing:else]   5 PESO

      
        43
        43
         `},

      
        44
        44
         		{"transaction with unicode commodity symbols", `2024/01/01 groceries

      
        45
        45
             expenses:food  €10.00

      
M journal/lexer/testdata/account_directive.golden
···
        1
        1
         ACCOUNT      "account"            1:1-1:8

      
        2
        2
         WHITESPACE   " "                  1:8-1:9

      
        3
        
        -TEXT         "expenses:food"      1:9-1:22

      
        
        3
        +TEXT         "expenses"           1:9-1:17

      
        
        4
        +COLON        ":"                  1:17-1:18

      
        
        5
        +TEXT         "food"               1:18-1:22

      
        4
        6
         NEWLINE      "\n"                 1:22-1:23

      
        5
        7
         EOF          ""                   1:23-1:23

      
A journal/lexer/testdata/account_with_colon.golden
···
        
        1
        +ACCOUNT      "account"            1:1-1:8

      
        
        2
        +WHITESPACE   " "                  1:8-1:9

      
        
        3
        +TEXT         "income"              1:9-1:15

      
        
        4
        +COLON        ":"                  1:15-1:16

      
        
        5
        +TEXT         "salary"              1:16-1:22

      
        
        6
        +NEWLINE      "\n"                 1:22-1:23

      
        
        7
        +EOF          ""                   1:23-1:23

      
M journal/lexer/testdata/automated_transaction.golden
···
        4
        4
         NEWLINE      "\n"                 2:0-2:1

      
        5
        5
         INDENT       "    "               2:1-2:5

      
        6
        6
         LPAREN       "("                  2:5-2:6

      
        7
        
        -TEXT         "liabilities:tax"    2:6-2:21

      
        
        7
        +TEXT         "liabilities"        2:6-2:17

      
        
        8
        +COLON        ":"                  2:17-2:18

      
        
        9
        +TEXT         "tax"                2:18-2:21

      
        8
        10
         RPAREN       ")"                  2:21-2:22

      
        9
        11
         WHITESPACE   "  "                 2:22-2:24

      
        10
        12
         STAR         "*"                  2:24-2:25

      ···
        16
        18
         TEXT         "expenses:gifts"     4:3-5:0

      
        17
        19
         NEWLINE      "\n"                 5:0-5:1

      
        18
        20
         INDENT       "    "               5:1-5:5

      
        19
        
        -TEXT         "budget:gifts"       5:5-5:17

      
        
        21
        +TEXT         "budget"             5:5-5:11

      
        
        22
        +COLON        ":"                  5:11-5:12

      
        
        23
        +TEXT         "gifts"              5:12-5:17

      
        20
        24
         WHITESPACE   "  "                 5:17-5:19

      
        21
        25
         PARENEXPR    "(amount * -1)"      5:19-6:0

      
        22
        26
         NEWLINE      "\n"                 6:0-6:1

      
M journal/lexer/testdata/cleared_transaction.golden
···
        5
        5
         TEXT         "groceries"          1:14-2:0

      
        6
        6
         NEWLINE      "\n"                 2:0-2:1

      
        7
        7
         INDENT       "    "               2:1-2:5

      
        8
        
        -TEXT         "expenses:food"      2:5-2:18

      
        
        8
        +TEXT         "expenses"           2:5-2:13

      
        
        9
        +COLON        ":"                  2:13-2:14

      
        
        10
        +TEXT         "food"               2:14-2:18

      
        9
        11
         WHITESPACE   "  "                 2:18-2:20

      
        10
        12
         COMMODITYMARK "$"                  2:20-2:21

      
        11
        13
         DECIMAL      "10.00"              2:21-3:0

      
        12
        14
         NEWLINE      "\n"                 3:0-3:1

      
        13
        15
         INDENT       "    "               3:1-3:5

      
        14
        
        -TEXT         "assets:checking"    3:5-4:0

      
        
        16
        +TEXT         "assets"             3:5-3:11

      
        
        17
        +COLON        ":"                  3:11-3:12

      
        
        18
        +TEXT         "checking"           3:12-4:0

      
        15
        19
         NEWLINE      "\n"                 4:0-4:1

      
        16
        20
         EOF          ""                   4:1-4:1

      
M journal/lexer/testdata/simple_transaction.golden
···
        3
        3
         TEXT         "groceries"          1:12-2:0

      
        4
        4
         NEWLINE      "\n"                 2:0-2:1

      
        5
        5
         INDENT       "    "               2:1-2:5

      
        6
        
        -TEXT         "expenses:food"      2:5-2:18

      
        
        6
        +TEXT         "expenses"           2:5-2:13

      
        
        7
        +COLON        ":"                  2:13-2:14

      
        
        8
        +TEXT         "food"               2:14-2:18

      
        7
        9
         WHITESPACE   "  "                 2:18-2:20

      
        8
        10
         COMMODITYMARK "$"                  2:20-2:21

      
        9
        11
         DECIMAL      "10.00"              2:21-3:0

      
        10
        12
         NEWLINE      "\n"                 3:0-3:1

      
        11
        13
         INDENT       "    "               3:1-3:5

      
        12
        
        -TEXT         "assets:checking"    3:5-4:0

      
        
        14
        +TEXT         "assets"             3:5-3:11

      
        
        15
        +COLON        ":"                  3:11-3:12

      
        
        16
        +TEXT         "checking"           3:12-4:0

      
        13
        17
         NEWLINE      "\n"                 4:0-4:1

      
        14
        18
         EOF          ""                   4:1-4:1

      
M journal/lexer/testdata/special_chars_in_description.golden
···
        159
        159
         TEXT         "something *important*" 15:27-16:0

      
        160
        160
         NEWLINE      "\n"                 16:0-16:1

      
        161
        161
         INDENT       "    "               16:1-16:5

      
        162
        
        -TEXT         "expenses:food"      16:5-16:18

      
        
        162
        +TEXT         "expenses"           16:5-16:13

      
        
        163
        +COLON        ":"                  16:13-16:14

      
        
        164
        +TEXT         "food"               16:14-16:18

      
        163
        165
         WHITESPACE   "  "                 16:18-16:20

      
        164
        166
         DECIMAL      "40.00"              16:20-17:0

      
        165
        167
         NEWLINE      "\n"                 17:0-17:1

      
        166
        168
         INDENT       "    "               17:1-17:5

      
        167
        
        -TEXT         "assets:cash"        17:5-18:0

      
        
        169
        +TEXT         "assets"             17:5-17:11

      
        
        170
        +COLON        ":"                  17:11-17:12

      
        
        171
        +TEXT         "cash"               17:12-18:0

      
        168
        172
         NEWLINE      "\n"                 18:0-18:1

      
        169
        173
         EOF          ""                   18:1-18:1

      
M journal/lexer/testdata/transaction,_accounts_with_uppercase_latters.golden
···
        6
        6
         TEXT         "Store"              2:17-3:0

      
        7
        7
         NEWLINE      "\n"                 3:0-3:1

      
        8
        8
         INDENT       "    "               3:1-3:5

      
        9
        
        -TEXT         "Expenses:Books"     3:5-3:19

      
        
        9
        +TEXT         "Expenses"           3:5-3:13

      
        
        10
        +COLON        ":"                  3:13-3:14

      
        
        11
        +TEXT         "Books"              3:14-3:19

      
        10
        12
         WHITESPACE   "                       " 3:19-3:42

      
        11
        13
         COMMODITYMARK "$"                  3:42-3:43

      
        12
        14
         DECIMAL      "20.00"              3:43-4:0

      
        13
        15
         NEWLINE      "\n"                 4:0-4:1

      
        14
        16
         INDENT       "    "               4:1-4:5

      
        15
        
        -TEXT         "Liabilities:MasterCard" 4:5-5:0

      
        
        17
        +TEXT         "Liabilities"        4:5-4:16

      
        
        18
        +COLON        ":"                  4:16-4:17

      
        
        19
        +TEXT         "MasterCard"         4:17-5:0

      
        16
        20
         NEWLINE      "\n"                 5:0-5:1

      
        17
        21
         EOF          ""                   5:1-5:1

      
M journal/lexer/testdata/transaction_with_code.golden
···
        5
        5
         TEXT         "groceries"          1:18-2:0

      
        6
        6
         NEWLINE      "\n"                 2:0-2:1

      
        7
        7
         INDENT       "    "               2:1-2:5

      
        8
        
        -TEXT         "expenses:food"      2:5-2:18

      
        
        8
        +TEXT         "expenses"           2:5-2:13

      
        
        9
        +COLON        ":"                  2:13-2:14

      
        
        10
        +TEXT         "food"               2:14-2:18

      
        9
        11
         WHITESPACE   "  "                 2:18-2:20

      
        10
        12
         COMMODITYMARK "$"                  2:20-2:21

      
        11
        13
         DECIMAL      "10.00"              2:21-3:0

      
        12
        14
         NEWLINE      "\n"                 3:0-3:1

      
        13
        15
         INDENT       "    "               3:1-3:5

      
        14
        
        -TEXT         "assets:checking"    3:5-4:0

      
        
        16
        +TEXT         "assets"             3:5-3:11

      
        
        17
        +COLON        ":"                  3:11-3:12

      
        
        18
        +TEXT         "checking"           3:12-4:0

      
        15
        19
         NEWLINE      "\n"                 4:0-5:0

      
        16
        20
         NEWLINE      "\n"                 5:0-5:1

      
        17
        21
         DATE         "2024/01/02"         5:1-5:11

      
M journal/lexer/testdata/transaction_with_unicode_commodity_symbols.golden
···
        3
        3
         TEXT         "groceries"          1:12-2:0

      
        4
        4
         NEWLINE      "\n"                 2:0-2:1

      
        5
        5
         INDENT       "    "               2:1-2:5

      
        6
        
        -TEXT         "expenses:food"      2:5-2:18

      
        
        6
        +TEXT         "expenses"           2:5-2:13

      
        
        7
        +COLON        ":"                  2:13-2:14

      
        
        8
        +TEXT         "food"               2:14-2:18

      
        7
        9
         WHITESPACE   "  "                 2:18-2:20

      
        8
        10
         COMMODITYMARK "€"                  2:20-2:21

      
        9
        11
         DECIMAL      "10.00"              2:21-3:0

      
        10
        12
         NEWLINE      "\n"                 3:0-3:1

      
        11
        13
         INDENT       "    "               3:1-3:5

      
        12
        
        -TEXT         "expenses:food"      3:5-3:18

      
        
        14
        +TEXT         "expenses"           3:5-3:13

      
        
        15
        +COLON        ":"                  3:13-3:14

      
        
        16
        +TEXT         "food"               3:14-3:18

      
        13
        17
         WHITESPACE   "  "                 3:18-3:20

      
        14
        18
         COMMODITYMARK "£"                  3:20-3:21

      
        15
        19
         DECIMAL      "5.00"               3:21-4:0

      
        16
        20
         NEWLINE      "\n"                 4:0-4:1

      
        17
        21
         INDENT       "    "               4:1-4:5

      
        18
        
        -TEXT         "expenses:food"      4:5-4:18

      
        
        22
        +TEXT         "expenses"           4:5-4:13

      
        
        23
        +COLON        ":"                  4:13-4:14

      
        
        24
        +TEXT         "food"               4:14-4:18

      
        19
        25
         WHITESPACE   "  "                 4:18-4:20

      
        20
        26
         COMMODITYMARK "₹"                  4:20-4:21

      
        21
        27
         DECIMAL      "700.00"             4:21-5:0

      
        22
        28
         NEWLINE      "\n"                 5:0-5:1

      
        23
        29
         INDENT       "    "               5:1-5:5

      
        24
        
        -TEXT         "expenses:food"      5:5-5:18

      
        
        30
        +TEXT         "expenses"           5:5-5:13

      
        
        31
        +COLON        ":"                  5:13-5:14

      
        
        32
        +TEXT         "food"               5:14-5:18

      
        25
        33
         WHITESPACE   "  "                 5:18-5:20

      
        26
        34
         DECIMAL      "40.00"              5:20-5:25

      
        27
        35
         WHITESPACE   " "                  5:25-5:26

      
        28
        36
         COMMODITYMARK "гривні"             5:26-6:0

      
        29
        37
         NEWLINE      "\n"                 6:0-6:1

      
        30
        38
         INDENT       "    "               6:1-6:5

      
        31
        
        -TEXT         "assets:cash"        6:5-7:0

      
        
        39
        +TEXT         "assets"             6:5-6:11

      
        
        40
        +COLON        ":"                  6:11-6:12

      
        
        41
        +TEXT         "cash"               6:12-7:0

      
        32
        42
         NEWLINE      "\n"                 7:0-7:1

      
        33
        43
         EOF          ""                   7:1-7:1

      
M journal/lexer/testdata/transaction_with_virtual_accounts.golden
···
        6
        6
         NEWLINE      "\n"                 2:0-2:1

      
        7
        7
         INDENT       "\t"                 2:1-2:2

      
        8
        8
         LPAREN       "("                  2:2-2:3

      
        9
        
        -TEXT         "virtual:account"    2:3-2:18

      
        
        9
        +TEXT         "virtual"            2:3-2:10

      
        
        10
        +COLON        ":"                  2:10-2:11

      
        
        11
        +TEXT         "account"            2:11-2:18

      
        10
        12
         RPAREN       ")"                  2:18-2:19

      
        11
        13
         WHITESPACE   "  "                 2:19-2:21

      
        12
        14
         INT          "1"                  2:21-2:22

      ···
        15
        17
         NEWLINE      "\n"                 3:0-3:1

      
        16
        18
         INDENT       "\t"                 3:1-3:2

      
        17
        19
         LBRACKET     "["                  3:2-3:3

      
        18
        
        -TEXT         "something:else"     3:3-3:17

      
        19
        
        -RBRACKET     "]"                  3:17-3:18

      
        20
        
        -WHITESPACE   "   "                3:18-3:21

      
        21
        
        -INT          "5"                  3:21-3:22

      
        22
        
        -WHITESPACE   " "                  3:22-3:23

      
        23
        
        -COMMODITYMARK "PESO"               3:23-4:0

      
        
        20
        +TEXT         "some thing"         3:3-3:13

      
        
        21
        +COLON        ":"                  3:13-3:14

      
        
        22
        +TEXT         "else"               3:14-3:18

      
        
        23
        +RBRACKET     "]"                  3:18-3:19

      
        
        24
        +WHITESPACE   "   "                3:19-3:22

      
        
        25
        +INT          "5"                  3:22-3:23

      
        
        26
        +WHITESPACE   " "                  3:23-3:24

      
        
        27
        +COMMODITYMARK "PESO"               3:24-4:0

      
        24
        28
         NEWLINE      "\n"                 4:0-4:1

      
        25
        29
         EOF          ""                   4:1-4:1

      
M journal/parser/parser.go
···
        455
        455
         	alias := &ast.AliasDirective{}

      
        456
        456
         	p.expect(token.ALIAS)

      
        457
        457
         	p.skipWhitespace()

      
        458
        
        -	alias.From = p.parseAccount().Name

      
        
        458
        +	alias.From = p.parseAccount()

      
        459
        459
         	p.skipWhitespace()

      
        460
        460
         	p.expect(token.EQ)

      
        461
        461
         	p.skipWhitespace()

      
        462
        
        -	alias.To = p.parseAccount().Name

      
        
        462
        +	alias.To = p.parseAccount()

      
        463
        463
         	p.skipWhitespace()

      
        464
        464
         	alias.Comment = p.parseOptInlineComment()

      
        465
        465
         	p.expectNewline()

      ···
        627
        627
         	tok, _ := p.expect(token.COMMODITYMARK)

      
        628
        628
         	mp.Commodity = tok.Literal

      
        629
        629
         	p.advance()

      
        630
        
        -	p.skipWhitespace()

      
        631
        630
         

      
        632
        631
         	mp.Amount = *p.parseAmount()

      
        633
        632
         

      ···
        931
        930
         	// optional amount - after two spaces

      
        932
        931
         	if p.got(token.WHITESPACE) {

      
        933
        932
         		p.skipWhitespace()

      
        
        933
        +		if p.got(token.STRING) { // e.g "Plans: Wildthorn Mail" 1 @ 125s

      
        
        934
        +			p.advance()

      
        
        935
        +			p.skipWhitespace()

      
        
        936
        +		}

      
        934
        937
         		if p.isAmountStart() || p.got(token.STAR) {

      
        935
        938
         			posting.Amount = p.parseAmountWithOptExpr()

      
        936
        939
         		}

      ···
        1002
        1005
         	return ba

      
        1003
        1006
         }

      
        1004
        1007
         

      
        1005
        
        -func (p *Parser) parseAccount() ast.Account {

      
        1006
        
        -	s := p.cur.Span

      
        1007
        
        -	var name strings.Builder

      
        1008
        
        -

      
        
        1008
        +func (p *Parser) readAccountSegment() (ast.SubAccount, bool) {

      
        1009
        1009
         	switch p.cur.Type {

      
        1010
        1010
         	case token.TEXT:

      
        1011
        
        -		_, _ = name.WriteString(p.cur.Literal)

      
        
        1011
        +		sub := ast.SubAccount{Name: p.cur.Literal, Span: p.cur.Span}

      
        1012
        1012
         		p.advance()

      
        1013
        
        -		if p.got(token.WHITESPACE) && p.willGet(token.TEXT) && p.peek.Literal[0] != '(' {

      
        1014
        
        -			_, _ = name.WriteString(" ")

      
        
        1013
        +

      
        
        1014
        +		// handle multi work segment, e.g: "credit card"

      
        
        1015
        +		if p.got(token.WHITESPACE) && p.willGet(token.TEXT) && len(p.peek.Literal) > 0 && p.peek.Literal[0] != '(' {

      
        
        1016
        +			sub.Name += " "

      
        1015
        1017
         			p.advance()

      
        1016
        
        -			_, _ = name.WriteString(p.cur.Literal)

      
        
        1018
        +			sub.Name += p.cur.Literal

      
        1017
        1019
         			p.advance()

      
        1018
        1020
         		}

      
        
        1021
        +		return sub, true

      
        
        1022
        +

      
        1019
        1023
         	case token.COMMODITYMARK:

      
        1020
        
        -		_, _ = name.WriteString(p.cur.Literal)

      
        
        1024
        +		sub := ast.SubAccount{Name: p.cur.Literal, Span: p.cur.Span}

      
        1021
        1025
         		p.advance()

      
        
        1026
        +		// merge "EUR" + "-HRK" to "EUR-HRK"

      
        1022
        1027
         		for p.got(token.TEXT) {

      
        1023
        
        -			_, _ = name.WriteString(p.cur.Literal)

      
        
        1028
        +			sub.Name += p.cur.Literal

      
        1024
        1029
         			p.advance()

      
        1025
        1030
         		}

      
        
        1031
        +		return sub, true

      
        
        1032
        +

      
        
        1033
        +	default:

      
        
        1034
        +		return ast.SubAccount{}, false

      
        1026
        1035
         	}

      
        1027
        
        -	return ast.Account{Name: name.String(), Span: p.span(s)}

      
        
        1036
        +}

      
        
        1037
        +

      
        
        1038
        +func (p *Parser) parseAccount() ast.Account {

      
        
        1039
        +	s := p.cur.Span

      
        
        1040
        +	acc := ast.Account{}

      
        
        1041
        +

      
        
        1042
        +	sub, ok := p.readAccountSegment()

      
        
        1043
        +	if !ok {

      
        
        1044
        +		p.errorf("expected account, got %s", p.cur.Type)

      
        
        1045
        +		return ast.Account{}

      
        
        1046
        +	}

      
        
        1047
        +	acc.Name = append(acc.Name, sub)

      
        
        1048
        +

      
        
        1049
        +	for p.got(token.COLON) {

      
        
        1050
        +		p.advance()

      
        
        1051
        +		sub, ok := p.readAccountSegment()

      
        
        1052
        +		if !ok {

      
        
        1053
        +			break

      
        
        1054
        +		}

      
        
        1055
        +		acc.Name = append(acc.Name, sub)

      
        
        1056
        +	}

      
        
        1057
        +

      
        
        1058
        +	acc.Span = p.span(s)

      
        
        1059
        +	return acc

      
        1028
        1060
         }

      
        1029
        1061
         

      
        1030
        1062
         func (p *Parser) parseDate() ast.Date {

      
M journal/parser/testdata/account_directive.golden
···
        1
        1
         Journal

      
        2
        2
           AccountDirective j:1:1-2:1

      
        3
        
        -    Account "expenses:food" j:1:9-2:0

      
        
        3
        +    Account j:1:9-2:0

      
        
        4
        +      SubAccount: "expenses" j:1:9-1:17

      
        
        5
        +      SubAccount: "food" j:1:18-2:0

      
M journal/parser/testdata/account_directive_with_comment.golden
···
        1
        1
         Journal

      
        2
        2
           AccountDirective j:1:1-2:1

      
        3
        
        -    Account "expenses:food" j:1:9-1:22

      
        
        3
        +    Account j:1:9-1:22

      
        
        4
        +      SubAccount: "expenses" j:1:9-1:17

      
        
        5
        +      SubAccount: "food" j:1:18-1:22

      
        4
        6
             Comment j:1:23-2:0

      
        5
        7
               Marker: ";"

      
        6
        8
               Text: "my account"

      
M journal/parser/testdata/account_with_spaces.golden
···
        3
        3
             Date: 2026-05-11

      
        4
        4
             Payee: "testies" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:account name" j:2:2-2:23

      
        
        6
        +      Account j:2:2-2:23

      
        
        7
        +        SubAccount: "expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "account name" j:2:11-2:23

      
        7
        9
               Amount j:2:25-2:25

      
        8
        10
                 Quantity: 20

      
        9
        11
                 Commodity: ""

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:bank" j:3:2-4:0

      
        
        17
        +      Account j:3:2-4:0

      
        
        18
        +        SubAccount: "assets" j:3:2-3:8

      
        
        19
        +        SubAccount: "bank" j:3:9-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/account_with_subdirectives.golden
···
        1
        1
         Journal

      
        2
        2
           AccountDirective j:1:1-4:1

      
        3
        
        -    Account "expenses:food" j:1:9-2:0

      
        
        3
        +    Account j:1:9-2:0

      
        
        4
        +      SubAccount: "expenses" j:1:9-1:17

      
        
        5
        +      SubAccount: "food" j:1:18-2:0

      
M journal/parser/testdata/automated_transaction.golden
···
        3
        3
             Expr: "^income"

      
        4
        4
             Posting j:2:1-4:0

      
        5
        5
               Type: unbalanced virtual

      
        6
        
        -      Account "liabilities:tax" j:2:6-2:21

      
        
        6
        +      Account j:2:6-2:21

      
        
        7
        +        SubAccount: "liabilities" j:2:6-2:17

      
        
        8
        +        SubAccount: "tax" j:2:18-2:21

      
        7
        9
               Amount j:2:25-2:25

      
        8
        10
                 Quantity: 0.33

      
        9
        11
                 Commodity: ""

      ···
        16
        18
           AutomatedTransaction j:4:1-4:3

      
        17
        19
             Expr: "expenses:gifts"

      
        18
        20
             Posting j:5:1-6:1

      
        19
        
        -      Account "budget:gifts" j:5:5-5:17

      
        
        21
        +      Account j:5:5-5:17

      
        
        22
        +        SubAccount: "budget" j:5:5-5:11

      
        
        23
        +        SubAccount: "gifts" j:5:12-5:17

      
        20
        24
               Amount j:5:20-5:20

      
        21
        25
                 Quantity: -1

      
        22
        26
                 Commodity: ""

      ···
        26
        30
                 Precision: 0

      
        27
        31
                 Decimal: "."

      
        28
        32
             Posting j:6:1-8:0

      
        29
        
        -      Account "assets:budget" j:6:5-6:18

      
        
        33
        +      Account j:6:5-6:18

      
        
        34
        +        SubAccount: "assets" j:6:5-6:11

      
        
        35
        +        SubAccount: "budget" j:6:12-6:18

      
        30
        36
               Amount j:6:21-6:21

      
        31
        37
                 Quantity: 1

      
        32
        38
                 Commodity: ""

      ···
        39
        45
           AutomatedTransaction j:8:1-8:3

      
        40
        46
             Expr: "income:salary"

      
        41
        47
             Posting j:9:1-10:1

      
        42
        
        -      Account "budget:savings" j:9:5-9:19

      
        
        48
        +      Account j:9:5-9:19

      
        
        49
        +        SubAccount: "budget" j:9:5-9:11

      
        
        50
        +        SubAccount: "savings" j:9:12-9:19

      
        43
        51
               Amount j:9:21-10:0

      
        44
        52
                 Quantity: 0

      
        45
        53
                 Commodity: ""

      
M journal/parser/testdata/bad_between_good.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:4:1-5:1

      
        15
        
        -      Account "assets:cash" j:4:5-4:16

      
        
        17
        +      Account j:4:5-4:16

      
        
        18
        +        SubAccount: "assets" j:4:5-4:11

      
        
        19
        +        SubAccount: "cash" j:4:12-4:16

      
        16
        20
               Amount j:4:18-4:18

      
        17
        21
                 Quantity: 5

      
        18
        22
                 Commodity: "$"

      
M journal/parser/testdata/bad_posting_at_end.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        16
        18
             Date: 2024/01/02

      
        17
        19
             Payee: "salary" j:5:12-6:0

      
        18
        20
             Posting j:6:1-7:1

      
        19
        
        -      Account "income:salary" j:6:5-6:18

      
        
        21
        +      Account j:6:5-6:18

      
        
        22
        +        SubAccount: "income" j:6:5-6:11

      
        
        23
        +        SubAccount: "salary" j:6:12-6:18

      
        20
        24
               Amount j:6:20-6:20

      
        21
        25
                 Quantity: 1000

      
        22
        26
                 Commodity: "$"

      ···
        25
        29
                 Precision: 0

      
        26
        30
                 Decimal: "."

      
        27
        31
             Posting j:7:1-8:1

      
        28
        
        -      Account "assets:checking" j:7:5-8:0

      
        
        32
        +      Account j:7:5-8:0

      
        
        33
        +        SubAccount: "assets" j:7:5-7:11

      
        
        34
        +        SubAccount: "checking" j:7:12-8:0

      
        29
        35
               Amount: <elided>

      
        30
        36
           Errors

      
        31
        37
             j:3:5-3:7: expected account name, got ATAT

      
M journal/parser/testdata/bad_then_next_transaction.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        16
        18
             Date: 2024/01/02

      
        17
        19
             Payee: "salary" j:5:12-6:0

      
        18
        20
             Posting j:6:1-7:1

      
        19
        
        -      Account "income:salary" j:6:5-6:18

      
        
        21
        +      Account j:6:5-6:18

      
        
        22
        +        SubAccount: "income" j:6:5-6:11

      
        
        23
        +        SubAccount: "salary" j:6:12-6:18

      
        20
        24
               Amount j:6:20-6:20

      
        21
        25
                 Quantity: 1000

      
        22
        26
                 Commodity: "$"

      ···
        25
        29
                 Precision: 0

      
        26
        30
                 Decimal: "."

      
        27
        31
             Posting j:7:1-8:1

      
        28
        
        -      Account "assets:checking" j:7:5-8:0

      
        
        32
        +      Account j:7:5-8:0

      
        
        33
        +        SubAccount: "assets" j:7:5-7:11

      
        
        34
        +        SubAccount: "checking" j:7:12-8:0

      
        29
        35
               Amount: <elided>

      
        30
        36
           Errors

      
        31
        37
             j:3:5-3:7: expected account name, got ATAT

      
M journal/parser/testdata/comment_between_bad_postings.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:6:1-7:1

      
        15
        
        -      Account "assets:checking" j:6:5-7:0

      
        
        17
        +      Account j:6:5-7:0

      
        
        18
        +        SubAccount: "assets" j:6:5-6:11

      
        
        19
        +        SubAccount: "checking" j:6:12-7:0

      
        16
        20
               Amount: <elided>

      
        17
        21
           Errors

      
        18
        22
             j:3:5-3:7: expected account name, got ATAT

      
M journal/parser/testdata/digit_group_marks.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:3-2:16

      
        
        6
        +      Account j:2:3-2:16

      
        
        7
        +        SubAccount: "expenses" j:2:3-2:11

      
        
        8
        +        SubAccount: "food" j:2:12-2:16

      
        7
        9
               Amount j:2:18-2:18

      
        8
        10
                 Quantity: 1000

      
        9
        11
                 Commodity: "UAH"

      ···
        13
        15
                 Decimal: "."

      
        14
        16
                 Thousands: " "

      
        15
        17
             Posting j:3:1-4:1

      
        16
        
        -      Account "expenses:supplies" j:3:3-3:20

      
        
        18
        +      Account j:3:3-3:20

      
        
        19
        +        SubAccount: "expenses" j:3:3-3:11

      
        
        20
        +        SubAccount: "supplies" j:3:12-3:20

      
        17
        21
               Amount j:3:22-3:22

      
        18
        22
                 Quantity: 1000

      
        19
        23
                 Commodity: "USD"

      ···
        23
        27
                 Decimal: "."

      
        24
        28
                 Thousands: "'"

      
        25
        29
             Posting j:4:1-5:1

      
        26
        
        -      Account "assets:checking" j:4:3-4:18

      
        
        30
        +      Account j:4:3-4:18

      
        
        31
        +        SubAccount: "assets" j:4:3-4:9

      
        
        32
        +        SubAccount: "checking" j:4:10-4:18

      
        27
        33
               Amount j:4:20-4:20

      
        28
        34
                 Quantity: -2000

      
        29
        35
                 Commodity: "USD"

      
M journal/parser/testdata/directive_prefixes.golden
···
        1
        1
         Journal

      
        2
        2
           AccountDirective j:1:2-2:1

      
        3
        
        -    Account "expenses:food" j:1:10-2:0

      
        
        3
        +    Account j:1:10-2:0

      
        
        4
        +      SubAccount: "expenses" j:1:10-1:18

      
        
        5
        +      SubAccount: "food" j:1:19-2:0

      
        4
        6
           CommodityDirective j:2:2-3:1

      
        5
        7
             Commodity: "USD"

      
M journal/parser/testdata/illegal_between_transactions.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:5-4:0

      
        
        17
        +      Account j:3:5-4:0

      
        
        18
        +        SubAccount: "assets" j:3:5-3:11

      
        
        19
        +        SubAccount: "checking" j:3:12-4:0

      
        16
        20
               Amount: <elided>

      
        17
        21
           Transaction j:5:1-8:1

      
        18
        22
             Date: 2024/01/02

      
        19
        23
             Payee: "salary" j:5:12-6:0

      
        20
        24
             Posting j:6:1-7:1

      
        21
        
        -      Account "income:salary" j:6:5-6:18

      
        
        25
        +      Account j:6:5-6:18

      
        
        26
        +        SubAccount: "income" j:6:5-6:11

      
        
        27
        +        SubAccount: "salary" j:6:12-6:18

      
        22
        28
               Amount j:6:20-6:20

      
        23
        29
                 Quantity: 1000

      
        24
        30
                 Commodity: "$"

      ···
        27
        33
                 Precision: 0

      
        28
        34
                 Decimal: "."

      
        29
        35
             Posting j:7:1-8:1

      
        30
        
        -      Account "assets:checking" j:7:5-8:0

      
        
        36
        +      Account j:7:5-8:0

      
        
        37
        +        SubAccount: "assets" j:7:5-7:11

      
        
        38
        +        SubAccount: "checking" j:7:12-8:0

      
        31
        39
               Amount: <elided>

      
        32
        40
           Errors

      
        33
        41
             j:4:1-4:2: unexpected token AT

      
M journal/parser/testdata/illegal_in_posting.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:3:1-4:1

      
        6
        
        -      Account "assets:checking" j:3:5-4:0

      
        
        6
        +      Account j:3:5-4:0

      
        
        7
        +        SubAccount: "assets" j:3:5-3:11

      
        
        8
        +        SubAccount: "checking" j:3:12-4:0

      
        7
        9
               Amount: <elided>

      
        8
        10
           Errors

      
        9
        11
             j:2:5-2:7: expected account name, got ATAT

      
M journal/parser/testdata/multiple_bad_postings.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:5:1-6:1

      
        15
        
        -      Account "assets:checking" j:5:5-6:0

      
        
        17
        +      Account j:5:5-6:0

      
        
        18
        +        SubAccount: "assets" j:5:5-5:11

      
        
        19
        +        SubAccount: "checking" j:5:12-6:0

      
        16
        20
               Amount: <elided>

      
        17
        21
           Errors

      
        18
        22
             j:3:5-3:7: expected account name, got ATAT

      
M journal/parser/testdata/nested_apply_tag_directives.golden
···
        7
        7
             Date: 2011/01/27

      
        8
        8
             Payee: "Book Store" j:3:12-4:0

      
        9
        9
             Posting j:4:1-5:1

      
        10
        
        -      Account "expenses:books" j:4:3-4:17

      
        
        10
        +      Account j:4:3-4:17

      
        
        11
        +        SubAccount: "expenses" j:4:3-4:11

      
        
        12
        +        SubAccount: "books" j:4:12-4:17

      
        11
        13
               Amount j:4:19-4:19

      
        12
        14
                 Quantity: 20

      
        13
        15
                 Commodity: "$"

      ···
        16
        18
                 Precision: 2

      
        17
        19
                 Decimal: "."

      
        18
        20
             Posting j:5:1-6:1

      
        19
        
        -      Account "liabilities:mastercard" j:5:3-6:0

      
        
        21
        +      Account j:5:3-6:0

      
        
        22
        +        SubAccount: "liabilities" j:5:3-5:14

      
        
        23
        +        SubAccount: "mastercard" j:5:15-6:0

      
        20
        24
               Amount: <elided>

      
        21
        25
           EndDirective j:6:1-7:1

      
        22
        26
             Expr: "apply tag"

      
M journal/parser/testdata/period_transaction_expressions.golden
···
        3
        3
           PeriodicTransaction j:2:1-2:3

      
        4
        4
             Period: "monthly"

      
        5
        5
             Posting j:3:1-4:1

      
        6
        
        -      Account "expenses:rent" j:3:5-3:18

      
        
        6
        +      Account j:3:5-3:18

      
        
        7
        +        SubAccount: "expenses" j:3:5-3:13

      
        
        8
        +        SubAccount: "rent" j:3:14-3:18

      
        7
        9
               Amount j:3:28-3:28

      
        8
        10
                 Quantity: 2000

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:4:1-6:0

      
        15
        
        -      Account "assets:bank:checking" j:4:5-5:0

      
        
        17
        +      Account j:4:5-5:0

      
        
        18
        +        SubAccount: "assets" j:4:5-4:11

      
        
        19
        +        SubAccount: "bank" j:4:12-4:16

      
        
        20
        +        SubAccount: "checking" j:4:17-5:0

      
        16
        21
               Amount: <elided>

      
        17
        22
           BlankLine j:6:0-6:1

      
        18
        23
           PeriodicTransaction j:6:1-6:3

      ···
        20
        25
             From: 2023-04-15

      
        21
        26
             To: 2023-06-16

      
        22
        27
             Posting j:7:1-8:1

      
        23
        
        -      Account "expenses:utilities" j:7:5-7:23

      
        
        28
        +      Account j:7:5-7:23

      
        
        29
        +        SubAccount: "expenses" j:7:5-7:13

      
        
        30
        +        SubAccount: "utilities" j:7:14-7:23

      
        24
        31
               Amount j:7:33-7:33

      
        25
        32
                 Quantity: 400

      
        26
        33
                 Commodity: "$"

      ···
        29
        36
                 Precision: 0

      
        30
        37
                 Decimal: "."

      
        31
        38
             Posting j:8:1-10:0

      
        32
        
        -      Account "assets:bank:checking" j:8:5-9:0

      
        
        39
        +      Account j:8:5-9:0

      
        
        40
        +        SubAccount: "assets" j:8:5-8:11

      
        
        41
        +        SubAccount: "bank" j:8:12-8:16

      
        
        42
        +        SubAccount: "checking" j:8:17-9:0

      
        33
        43
               Amount: <elided>

      
        34
        44
           BlankLine j:10:0-10:1

      
        35
        45
           PeriodicTransaction j:10:1-10:3

      
        36
        46
             Period: "every 2 months"

      
        37
        47
             Description: "in 2023, we will review"

      
        38
        48
             Posting j:11:1-12:1

      
        39
        
        -      Account "expenses:utilities" j:11:5-11:23

      
        
        49
        +      Account j:11:5-11:23

      
        
        50
        +        SubAccount: "expenses" j:11:5-11:13

      
        
        51
        +        SubAccount: "utilities" j:11:14-11:23

      
        40
        52
               Amount j:11:33-11:33

      
        41
        53
                 Quantity: 400

      
        42
        54
                 Commodity: "$"

      ···
        45
        57
                 Precision: 0

      
        46
        58
                 Decimal: "."

      
        47
        59
             Posting j:12:1-14:0

      
        48
        
        -      Account "assets:bank:checking" j:12:5-13:0

      
        
        60
        +      Account j:12:5-13:0

      
        
        61
        +        SubAccount: "assets" j:12:5-12:11

      
        
        62
        +        SubAccount: "bank" j:12:12-12:16

      
        
        63
        +        SubAccount: "checking" j:12:17-13:0

      
        49
        64
               Amount: <elided>

      
        50
        65
           BlankLine j:14:0-14:1

      
        51
        66
           PeriodicTransaction j:14:1-14:3

      
        52
        67
             Period: "monthly"

      
        53
        68
             Description: "Next year blah blah"

      
        54
        69
             Posting j:15:1-16:1

      
        55
        
        -      Account "expenses:food" j:15:5-15:18

      
        
        70
        +      Account j:15:5-15:18

      
        
        71
        +        SubAccount: "expenses" j:15:5-15:13

      
        
        72
        +        SubAccount: "food" j:15:14-15:18

      
        56
        73
               Amount j:15:20-15:20

      
        57
        74
                 Quantity: 100

      
        58
        75
                 Commodity: "$"

      ···
        61
        78
                 Precision: 0

      
        62
        79
                 Decimal: "."

      
        63
        80
             Posting j:16:1-18:0

      
        64
        
        -      Account "assets:checking" j:16:5-17:0

      
        
        81
        +      Account j:16:5-17:0

      
        
        82
        +        SubAccount: "assets" j:16:5-16:11

      
        
        83
        +        SubAccount: "checking" j:16:12-17:0

      
        65
        84
               Amount: <elided>

      
        66
        85
           BlankLine j:18:0-18:1

      
        67
        86
           PeriodicTransaction j:18:1-18:3

      ···
        70
        89
               Marker: ";"

      
        71
        90
               Text: "In 2019 we will change this"

      
        72
        91
             Posting j:19:1-20:1

      
        73
        
        -      Account "expenses:food" j:19:5-19:18

      
        
        92
        +      Account j:19:5-19:18

      
        
        93
        +        SubAccount: "expenses" j:19:5-19:13

      
        
        94
        +        SubAccount: "food" j:19:14-19:18

      
        74
        95
               Amount j:19:20-19:20

      
        75
        96
                 Quantity: 100

      
        76
        97
                 Commodity: "$"

      ···
        79
        100
                 Precision: 0

      
        80
        101
                 Decimal: "."

      
        81
        102
             Posting j:20:1-21:1

      
        82
        
        -      Account "assets:checking" j:20:5-21:0

      
        
        103
        +      Account j:20:5-21:0

      
        
        104
        +        SubAccount: "assets" j:20:5-20:11

      
        
        105
        +        SubAccount: "checking" j:20:12-21:0

      
        83
        106
               Amount: <elided>

      
M journal/parser/testdata/quoted_payee_names.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries store" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:3-2:16

      
        
        6
        +      Account j:2:3-2:16

      
        
        7
        +        SubAccount: "expenses" j:2:3-2:11

      
        
        8
        +        SubAccount: "food" j:2:12-2:16

      
        7
        9
               Amount j:2:18-2:18

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:3-4:0

      
        
        17
        +      Account j:3:3-4:0

      
        
        18
        +        SubAccount: "assets" j:3:3-3:9

      
        
        19
        +        SubAccount: "checking" j:3:10-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/recovery_after_bad_posting.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:3:1-5:0

      
        6
        
        -      Account "assets:checking" j:3:5-4:0

      
        
        6
        +      Account j:3:5-4:0

      
        
        7
        +        SubAccount: "assets" j:3:5-3:11

      
        
        8
        +        SubAccount: "checking" j:3:12-4:0

      
        7
        9
               Amount: <elided>

      
        8
        10
           BlankLine j:5:0-5:1

      
        9
        11
           Transaction j:5:1-8:1

      
        10
        12
             Date: 2024/01/02

      
        11
        13
             Payee: "salary" j:5:12-6:0

      
        12
        14
             Posting j:6:1-7:1

      
        13
        
        -      Account "income:salary" j:6:5-6:18

      
        
        15
        +      Account j:6:5-6:18

      
        
        16
        +        SubAccount: "income" j:6:5-6:11

      
        
        17
        +        SubAccount: "salary" j:6:12-6:18

      
        14
        18
               Amount j:6:20-6:20

      
        15
        19
                 Quantity: 1000

      
        16
        20
                 Commodity: "$"

      ···
        19
        23
                 Precision: 0

      
        20
        24
                 Decimal: "."

      
        21
        25
             Posting j:7:1-8:1

      
        22
        
        -      Account "assets:checking" j:7:5-8:0

      
        
        26
        +      Account j:7:5-8:0

      
        
        27
        +        SubAccount: "assets" j:7:5-7:11

      
        
        28
        +        SubAccount: "checking" j:7:12-8:0

      
        23
        29
               Amount: <elided>

      
        24
        30
           Errors

      
        25
        31
             j:2:5-2:7: expected account name, got ATAT

      
M journal/parser/testdata/special_chars_in_description.golden
···
        58
        58
             Payee: "payee !one" j:15:14-15:24

      
        59
        59
             Note: "something *important*"

      
        60
        60
             Posting j:16:1-17:1

      
        61
        
        -      Account "expenses:food" j:16:5-16:18

      
        
        61
        +      Account j:16:5-16:18

      
        
        62
        +        SubAccount: "expenses" j:16:5-16:13

      
        
        63
        +        SubAccount: "food" j:16:14-16:18

      
        62
        64
               Amount j:16:20-16:20

      
        63
        65
                 Quantity: 40

      
        64
        66
                 Commodity: ""

      ···
        67
        69
                 Precision: 2

      
        68
        70
                 Decimal: "."

      
        69
        71
             Posting j:17:1-18:1

      
        70
        
        -      Account "assets:cash" j:17:5-18:0

      
        
        72
        +      Account j:17:5-18:0

      
        
        73
        +        SubAccount: "assets" j:17:5-17:11

      
        
        74
        +        SubAccount: "cash" j:17:12-18:0

      
        71
        75
               Amount: <elided>

      
M journal/parser/testdata/three_bad_postings.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:6:1-7:1

      
        15
        
        -      Account "assets:checking" j:6:5-7:0

      
        
        17
        +      Account j:6:5-7:0

      
        
        18
        +        SubAccount: "assets" j:6:5-6:11

      
        
        19
        +        SubAccount: "checking" j:6:12-7:0

      
        16
        20
               Amount: <elided>

      
        17
        21
           Errors

      
        18
        22
             j:3:5-3:7: expected account name, got ATAT

      
M journal/parser/testdata/transaction_in_ukrainian.golden
···
        3
        3
             Date: 2024/03/02

      
        4
        4
             Payee: "Обід" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "витрати:їжа" j:2:3-2:14

      
        
        6
        +      Account j:2:3-2:14

      
        
        7
        +        SubAccount: "витрати" j:2:3-2:10

      
        
        8
        +        SubAccount: "їжа" j:2:11-2:14

      
        7
        9
               Amount j:2:16-2:16

      
        8
        10
                 Quantity: 350

      
        9
        11
                 Commodity: "UAH"

      ···
        12
        14
                 Precision: 0

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "активи:готівка" j:3:3-4:0

      
        
        17
        +      Account j:3:3-4:0

      
        
        18
        +        SubAccount: "активи" j:3:3-3:9

      
        
        19
        +        SubAccount: "готівка" j:3:10-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_balance_assertion.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:2-2:15

      
        
        6
        +      Account j:2:2-2:15

      
        
        7
        +        SubAccount: "expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "food" j:2:11-2:15

      
        7
        9
               Amount j:2:17-2:17

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        22
        24
                   Precision: 2

      
        23
        25
                   Decimal: "."

      
        24
        26
             Posting j:3:1-5:0

      
        25
        
        -      Account "assets:checking" j:3:2-4:0

      
        
        27
        +      Account j:3:2-4:0

      
        
        28
        +        SubAccount: "assets" j:3:2-3:8

      
        
        29
        +        SubAccount: "checking" j:3:9-4:0

      
        26
        30
               Amount: <elided>

      
        27
        31
           BlankLine j:5:0-5:1

      
        28
        32
           Transaction j:5:1-9:0

      
        29
        33
             Date: 2025/03/07

      
        30
        34
             Payee: "groceries2" j:5:12-6:0

      
        31
        35
             Posting j:6:1-7:1

      
        32
        
        -      Account "expenses:food" j:6:2-6:15

      
        
        36
        +      Account j:6:2-6:15

      
        
        37
        +        SubAccount: "expenses" j:6:2-6:10

      
        
        38
        +        SubAccount: "food" j:6:11-6:15

      
        33
        39
               Amount j:6:17-6:17

      
        34
        40
                 Quantity: 10

      
        35
        41
                 Commodity: "$"

      ···
        48
        54
                   Precision: 2

      
        49
        55
                   Decimal: "."

      
        50
        56
             Posting j:7:1-9:0

      
        51
        
        -      Account "assets:checking" j:7:2-7:17

      
        
        57
        +      Account j:7:2-7:17

      
        
        58
        +        SubAccount: "assets" j:7:2-7:8

      
        
        59
        +        SubAccount: "checking" j:7:9-7:17

      
        52
        60
               Amount: <elided>

      
        53
        61
               BalanceAssertion j:7:19-8:0

      
        54
        62
                 IsStrict: true

      ···
        65
        73
             Date: 2025/04/08

      
        66
        74
             Payee: "groceries3" j:9:12-10:0

      
        67
        75
             Posting j:10:1-11:1

      
        68
        
        -      Account "expenses:food" j:10:2-10:15

      
        
        76
        +      Account j:10:2-10:15

      
        
        77
        +        SubAccount: "expenses" j:10:2-10:10

      
        
        78
        +        SubAccount: "food" j:10:11-10:15

      
        69
        79
               Amount j:10:17-10:17

      
        70
        80
                 Quantity: 10

      
        71
        81
                 Commodity: "$"

      ···
        74
        84
                 Precision: 2

      
        75
        85
                 Decimal: "."

      
        76
        86
             Posting j:11:1-12:1

      
        77
        
        -      Account "assets:checking" j:11:2-11:17

      
        
        87
        +      Account j:11:2-11:17

      
        
        88
        +        SubAccount: "assets" j:11:2-11:8

      
        
        89
        +        SubAccount: "checking" j:11:9-11:17

      
        78
        90
               Amount: <elided>

      
        79
        91
               BalanceAssertion j:11:19-12:0

      
        80
        92
                 IsStrict: false

      
M journal/parser/testdata/transaction_with_code.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "(123) groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:5-4:0

      
        
        17
        +      Account j:3:5-4:0

      
        
        18
        +        SubAccount: "assets" j:3:5-3:11

      
        
        19
        +        SubAccount: "checking" j:3:12-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_cost_and_assertion.golden
···
        3
        3
             Date: 2026-05-11

      
        4
        4
             Payee: "testies" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:atm" j:2:2-2:14

      
        
        6
        +      Account j:2:2-2:14

      
        
        7
        +        SubAccount: "expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "atm" j:2:11-2:14

      
        7
        9
               Amount j:2:16-2:16

      
        8
        10
                 Quantity: 20

      
        9
        11
                 Commodity: "UAH"

      ···
        30
        32
                   Precision: 0

      
        31
        33
                   Decimal: "."

      
        32
        34
             Posting j:3:1-4:1

      
        33
        
        -      Account "assets:bank" j:3:2-4:0

      
        
        35
        +      Account j:3:2-4:0

      
        
        36
        +        SubAccount: "assets" j:3:2-3:8

      
        
        37
        +        SubAccount: "bank" j:3:9-4:0

      
        34
        38
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_costs.golden
···
        3
        3
             Date: 2026-05-11

      
        4
        4
             Payee: "testies" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:atm" j:2:2-2:14

      
        
        6
        +      Account j:2:2-2:14

      
        
        7
        +        SubAccount: "expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "atm" j:2:11-2:14

      
        7
        9
               Amount j:2:16-2:16

      
        8
        10
                 Quantity: 20

      
        9
        11
                 Commodity: "UAH"

      ···
        20
        22
                   Precision: 0

      
        21
        23
                   Decimal: "."

      
        22
        24
             Posting j:3:1-5:0

      
        23
        
        -      Account "assets:bank" j:3:2-4:0

      
        
        25
        +      Account j:3:2-4:0

      
        
        26
        +        SubAccount: "assets" j:3:2-3:8

      
        
        27
        +        SubAccount: "bank" j:3:9-4:0

      
        24
        28
               Amount: <elided>

      
        25
        29
           BlankLine j:5:0-5:1

      
        26
        30
           Transaction j:5:1-9:0

      
        27
        31
             Date: 2026-05-11

      
        28
        32
             Payee: "testies2" j:5:12-6:0

      
        29
        33
             Posting j:6:1-7:1

      
        30
        
        -      Account "expenses:atm" j:6:2-6:14

      
        
        34
        +      Account j:6:2-6:14

      
        
        35
        +        SubAccount: "expenses" j:6:2-6:10

      
        
        36
        +        SubAccount: "atm" j:6:11-6:14

      
        31
        37
               Amount j:6:16-6:16

      
        32
        38
                 Quantity: 20

      
        33
        39
                 Commodity: "UAH"

      ···
        44
        50
                   Precision: 0

      
        45
        51
                   Decimal: "."

      
        46
        52
             Posting j:7:1-9:0

      
        47
        
        -      Account "assets:bank" j:7:2-8:0

      
        
        53
        +      Account j:7:2-8:0

      
        
        54
        +        SubAccount: "assets" j:7:2-7:8

      
        
        55
        +        SubAccount: "bank" j:7:9-8:0

      
        48
        56
               Amount: <elided>

      
        49
        57
           BlankLine j:9:0-9:1

      
        50
        58
           Transaction j:9:1-13:0

      
        51
        59
             Date: 2026-05-12

      
        52
        60
             Payee: "testies3" j:9:12-10:0

      
        53
        61
             Posting j:10:1-11:1

      
        54
        
        -      Account "expenses:atm" j:10:2-10:14

      
        
        62
        +      Account j:10:2-10:14

      
        
        63
        +        SubAccount: "expenses" j:10:2-10:10

      
        
        64
        +        SubAccount: "atm" j:10:11-10:14

      
        55
        65
               Amount j:10:16-10:16

      
        56
        66
                 Quantity: 20

      
        57
        67
                 Commodity: "UAH"

      ···
        78
        88
                   Precision: 2

      
        79
        89
                   Decimal: "."

      
        80
        90
             Posting j:11:1-13:0

      
        81
        
        -      Account "assets:bank" j:11:2-12:0

      
        
        91
        +      Account j:11:2-12:0

      
        
        92
        +        SubAccount: "assets" j:11:2-11:8

      
        
        93
        +        SubAccount: "bank" j:11:9-12:0

      
        82
        94
               Amount: <elided>

      
        83
        95
           BlankLine j:13:0-13:1

      
        84
        96
           Transaction j:13:1-16:1

      
        85
        97
             Date: 2015-01-03

      
        86
        98
             Payee: "money exchange office" j:13:12-14:0

      
        87
        99
             Posting j:14:1-15:1

      
        88
        
        -      Account "assets:cash" j:14:5-14:16

      
        
        100
        +      Account j:14:5-14:16

      
        
        101
        +        SubAccount: "assets" j:14:5-14:11

      
        
        102
        +        SubAccount: "cash" j:14:12-14:16

      
        89
        103
               Amount j:14:18-14:18

      
        90
        104
                 Quantity: -20

      
        91
        105
                 Commodity: "EUR"

      ···
        102
        116
                   Precision: 2

      
        103
        117
                   Decimal: "."

      
        104
        118
             Posting j:15:1-16:1

      
        105
        
        -      Account "assets:cash" j:15:5-15:16

      
        
        119
        +      Account j:15:5-15:16

      
        
        120
        +        SubAccount: "assets" j:15:5-15:11

      
        
        121
        +        SubAccount: "cash" j:15:12-15:16

      
        106
        122
               Amount j:15:18-15:18

      
        107
        123
                 Quantity: 150.6

      
        108
        124
                 Commodity: "HRK"

      
M journal/parser/testdata/transaction_with_digit_payees.golden
···
        4
        4
             State: "*"

      
        5
        5
             Payee: "1a1a6305d06ce4b284dba0d267c23f69d70c20be" j:1:14-2:0

      
        6
        6
             Posting j:2:1-3:1

      
        7
        
        -      Account "af0628973ff35bd62ddb048fa41dd8d83c1c46fe" j:2:5-2:45

      
        
        7
        +      Account j:2:5-2:45

      
        
        8
        +        SubAccount: "af0628973ff35bd62ddb048fa41dd8d83c1c46fe" j:2:5-2:45

      
        8
        9
               Amount j:2:52-2:52

      
        9
        10
                 Quantity: 474.31

      
        10
        11
                 Commodity: "$"

      ···
        13
        14
                 Precision: 2

      
        14
        15
                 Decimal: "."

      
        15
        16
             Posting j:3:1-5:0

      
        16
        
        -      Account "fc6f6f10f627ad1a5af9d488c98405a1498d019d" j:3:5-4:0

      
        
        17
        +      Account j:3:5-4:0

      
        
        18
        +        SubAccount: "fc6f6f10f627ad1a5af9d488c98405a1498d019d" j:3:5-4:0

      
        17
        19
               Amount: <elided>

      
        18
        20
           BlankLine j:5:0-5:1

      
        19
        21
           Transaction j:5:1-8:1

      ···
        21
        23
             State: "*"

      
        22
        24
             Payee: "9861ce541c17b11f627e71c26bf350b33141f62b" j:5:14-6:0

      
        23
        25
             Posting j:6:1-7:1

      
        24
        
        -      Account "0ecbb1b15e2cf3e515cc0f8533e5bb0fb2326728" j:6:5-6:45

      
        
        26
        +      Account j:6:5-6:45

      
        
        27
        +        SubAccount: "0ecbb1b15e2cf3e515cc0f8533e5bb0fb2326728" j:6:5-6:45

      
        25
        28
               Amount j:6:53-6:53

      
        26
        29
                 Quantity: 14.91

      
        27
        30
                 Commodity: "$"

      ···
        30
        33
                 Precision: 2

      
        31
        34
                 Decimal: "."

      
        32
        35
             Posting j:7:1-8:1

      
        33
        
        -      Account "fc6f6f10f627ad1a5af9d488c98405a1498d019d" j:7:5-8:0

      
        
        36
        +      Account j:7:5-8:0

      
        
        37
        +        SubAccount: "fc6f6f10f627ad1a5af9d488c98405a1498d019d" j:7:5-8:0

      
        34
        38
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_header_comment.golden
···
        7
        7
                 Marker: ";"

      
        8
        8
                 Text: "header comment"

      
        9
        9
             Posting j:3:1-4:1

      
        10
        
        -      Account "expenses:food" j:3:2-3:15

      
        
        10
        +      Account j:3:2-3:15

      
        
        11
        +        SubAccount: "expenses" j:3:2-3:10

      
        
        12
        +        SubAccount: "food" j:3:11-3:15

      
        11
        13
               Amount j:3:17-3:17

      
        12
        14
                 Quantity: 10

      
        13
        15
                 Commodity: "$"

      ···
        16
        18
                 Precision: 2

      
        17
        19
                 Decimal: "."

      
        18
        20
             Posting j:4:1-5:1

      
        19
        
        -      Account "assets:checking" j:4:2-5:0

      
        
        21
        +      Account j:4:2-5:0

      
        
        22
        +        SubAccount: "assets" j:4:2-4:8

      
        
        23
        +        SubAccount: "checking" j:4:9-5:0

      
        20
        24
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_inline_comment.golden
···
        3
        3
             Date: 2024/01/01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "Expenses:Good" j:2:2-2:15

      
        
        6
        +      Account j:2:2-2:15

      
        
        7
        +        SubAccount: "Expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "Good" j:2:11-2:15

      
        7
        9
               Amount j:2:17-2:17

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        15
        17
                 Marker: ";"

      
        16
        18
                 Text: "food"

      
        17
        19
             Posting j:3:1-4:1

      
        18
        
        -      Account "Assets:Checking" j:3:2-4:0

      
        
        20
        +      Account j:3:2-4:0

      
        
        21
        +        SubAccount: "Assets" j:3:2-3:8

      
        
        22
        +        SubAccount: "Checking" j:3:9-4:0

      
        19
        23
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_posting.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:5-4:0

      
        
        17
        +      Account j:3:5-4:0

      
        
        18
        +        SubAccount: "assets" j:3:5-3:11

      
        
        19
        +        SubAccount: "checking" j:3:12-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_posting_amounts.golden
···
        3
        3
             Date: 2024.01.01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "UAH"

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:5-3:20

      
        
        17
        +      Account j:3:5-3:20

      
        
        18
        +        SubAccount: "assets" j:3:5-3:11

      
        
        19
        +        SubAccount: "checking" j:3:12-3:20

      
        16
        20
               Amount j:3:22-3:22

      
        17
        21
                 Quantity: -10

      
        18
        22
                 Commodity: "UAH"

      
M journal/parser/testdata/transaction_with_spaced_account_name.golden
···
        3
        3
             Date: 2022-01-01

      
        4
        4
             Payee: "opening balances" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "assets" j:2:5-2:11

      
        
        6
        +      Account j:2:5-2:11

      
        
        7
        +        SubAccount: "assets" j:2:5-2:11

      
        7
        8
               Amount j:2:31-2:31

      
        8
        9
                 Quantity: 21

      
        9
        10
                 Commodity: ""

      ···
        22
        23
                   Precision: 0

      
        23
        24
                   Decimal: "."

      
        24
        25
             Posting j:3:1-4:1

      
        25
        
        -      Account "equity:opening/closing balances" j:3:5-4:0

      
        
        26
        +      Account j:3:5-4:0

      
        
        27
        +        SubAccount: "equity" j:3:5-3:11

      
        
        28
        +        SubAccount: "opening/closing balances" j:3:12-4:0

      
        26
        29
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_strange_commodity_symbols.golden
···
        5
        5
           Transaction j:2:1-6:0

      
        6
        6
             Date: 2026-05-20

      
        7
        7
             Posting j:3:1-4:1

      
        8
        
        -      Account "asdf" j:3:3-3:7

      
        
        8
        +      Account j:3:3-3:7

      
        
        9
        +        SubAccount: "asdf" j:3:3-3:7

      
        9
        10
               Amount j:3:9-3:9

      
        10
        11
                 Quantity: 123

      
        11
        12
                 Commodity: "$€£"

      ···
        14
        15
                 Precision: 0

      
        15
        16
                 Decimal: "."

      
        16
        17
             Posting j:4:1-6:0

      
        17
        
        -      Account "asdf2" j:4:3-5:0

      
        
        18
        +      Account j:4:3-5:0

      
        
        19
        +        SubAccount: "asdf2" j:4:3-5:0

      
        18
        20
               Amount: <elided>

      
        19
        21
           BlankLine j:6:0-6:1

      
        20
        22
           Transaction j:6:1-9:1

      
        21
        23
             Date: 2026-05-20

      
        22
        24
             Posting j:7:1-8:1

      
        23
        
        -      Account "asdf" j:7:3-7:7

      
        
        25
        +      Account j:7:3-7:7

      
        
        26
        +        SubAccount: "asdf" j:7:3-7:7

      
        24
        27
               Amount j:7:9-7:9

      
        25
        28
                 Quantity: 123

      
        26
        29
                 Commodity: "bytes"

      ···
        29
        32
                 Precision: 0

      
        30
        33
                 Decimal: "."

      
        31
        34
             Posting j:8:1-9:1

      
        32
        
        -      Account "asdf2" j:8:3-9:0

      
        
        35
        +      Account j:8:3-9:0

      
        
        36
        +        SubAccount: "asdf2" j:8:3-9:0

      
        33
        37
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_tabs.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:2-2:15

      
        
        6
        +      Account j:2:2-2:15

      
        
        7
        +        SubAccount: "expenses" j:2:2-2:10

      
        
        8
        +        SubAccount: "food" j:2:11-2:15

      
        7
        9
               Amount j:2:17-2:17

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "$"

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "assets:checking" j:3:2-4:0

      
        
        17
        +      Account j:3:2-4:0

      
        
        18
        +        SubAccount: "assets" j:3:2-3:8

      
        
        19
        +        SubAccount: "checking" j:3:9-4:0

      
        16
        20
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_trailing_indent.golden
···
        5
        5
             State: "*"

      
        6
        6
             Payee: "pay taxes" j:2:12-3:0

      
        7
        7
             Posting j:3:1-4:1

      
        8
        
        -      Account "expenses:personal:tax" j:3:5-3:26

      
        
        8
        +      Account j:3:5-3:26

      
        
        9
        +        SubAccount: "expenses" j:3:5-3:13

      
        
        10
        +        SubAccount: "personal" j:3:14-3:22

      
        
        11
        +        SubAccount: "tax" j:3:23-3:26

      
        9
        12
               Amount j:3:40-3:40

      
        10
        13
                 Quantity: 1250

      
        11
        14
                 Commodity: "$"

      ···
        14
        17
                 Precision: 0

      
        15
        18
                 Decimal: "."

      
        16
        19
             Posting j:4:1-6:0

      
        17
        
        -      Account "assets:bank:checking" j:4:5-4:25

      
        
        20
        +      Account j:4:5-4:25

      
        
        21
        +        SubAccount: "assets" j:4:5-4:11

      
        
        22
        +        SubAccount: "bank" j:4:12-4:16

      
        
        23
        +        SubAccount: "checking" j:4:17-4:25

      
        18
        24
               Amount j:4:40-4:40

      
        19
        25
                 Quantity: -1250

      
        20
        26
                 Commodity: "$"

      
M journal/parser/testdata/transaction_with_unicode_commodity_symbols.golden
···
        3
        3
             Date: 2024-01-01

      
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        
        -      Account "expenses:food" j:2:5-2:18

      
        
        6
        +      Account j:2:5-2:18

      
        
        7
        +        SubAccount: "expenses" j:2:5-2:13

      
        
        8
        +        SubAccount: "food" j:2:14-2:18

      
        7
        9
               Amount j:2:20-2:20

      
        8
        10
                 Quantity: 10

      
        9
        11
                 Commodity: "€"

      ···
        12
        14
                 Precision: 2

      
        13
        15
                 Decimal: "."

      
        14
        16
             Posting j:3:1-4:1

      
        15
        
        -      Account "expenses:food" j:3:5-3:18

      
        
        17
        +      Account j:3:5-3:18

      
        
        18
        +        SubAccount: "expenses" j:3:5-3:13

      
        
        19
        +        SubAccount: "food" j:3:14-3:18

      
        16
        20
               Amount j:3:20-3:20

      
        17
        21
                 Quantity: 5

      
        18
        22
                 Commodity: "£"

      ···
        21
        25
                 Precision: 2

      
        22
        26
                 Decimal: "."

      
        23
        27
             Posting j:4:1-5:1

      
        24
        
        -      Account "expenses:food" j:4:5-4:18

      
        
        28
        +      Account j:4:5-4:18

      
        
        29
        +        SubAccount: "expenses" j:4:5-4:13

      
        
        30
        +        SubAccount: "food" j:4:14-4:18

      
        25
        31
               Amount j:4:20-4:20

      
        26
        32
                 Quantity: 700

      
        27
        33
                 Commodity: "₹"

      ···
        30
        36
                 Precision: 2

      
        31
        37
                 Decimal: "."

      
        32
        38
             Posting j:5:1-6:1

      
        33
        
        -      Account "assets:checking" j:5:5-6:0

      
        
        39
        +      Account j:5:5-6:0

      
        
        40
        +        SubAccount: "assets" j:5:5-5:11

      
        
        41
        +        SubAccount: "checking" j:5:12-6:0

      
        34
        42
               Amount: <elided>

      
M journal/parser/testdata/transaction_with_virtual_accounts.golden
···
        4
        4
             Payee: "groceries" j:1:12-2:0

      
        5
        5
             Posting j:2:1-3:1

      
        6
        6
               Type: unbalanced virtual

      
        7
        
        -      Account "virtual:account" j:2:3-2:18

      
        
        7
        +      Account j:2:3-2:18

      
        
        8
        +        SubAccount: "virtual" j:2:3-2:10

      
        
        9
        +        SubAccount: "account" j:2:11-2:18

      
        8
        10
               Amount j:2:21-2:21

      
        9
        11
                 Quantity: 1

      
        10
        12
                 Commodity: "PESO"

      ···
        14
        16
                 Decimal: "."

      
        15
        17
             Posting j:3:1-4:1

      
        16
        18
               Type: balanced virtual

      
        17
        
        -      Account "something:else" j:3:3-3:17

      
        
        19
        +      Account j:3:3-3:17

      
        
        20
        +        SubAccount: "something" j:3:3-3:12

      
        
        21
        +        SubAccount: "else" j:3:13-3:17

      
        18
        22
               Amount j:3:21-3:21

      
        19
        23
                 Quantity: 5

      
        20
        24
                 Commodity: "PESO"

      ···
        23
        27
                 Precision: 0

      
        24
        28
                 Decimal: "."

      
        25
        29
             Posting j:4:1-5:1

      
        26
        
        -      Account "something:else" j:4:2-5:0

      
        
        30
        +      Account j:4:2-5:0

      
        
        31
        +        SubAccount: "something" j:4:2-4:11

      
        
        32
        +        SubAccount: "else" j:4:12-5:0

      
        27
        33
               Amount: <elided>

      
M journal/parser/testdata/virtual_postings_with_statuses.golden
···
        5
        5
             Posting j:2:1-3:1

      
        6
        6
               Type: unbalanced virtual

      
        7
        7
               Status: "!"

      
        8
        
        -      Account "assets:cash" j:2:6-2:17

      
        
        8
        +      Account j:2:6-2:17

      
        
        9
        +        SubAccount: "assets" j:2:6-2:12

      
        
        10
        +        SubAccount: "cash" j:2:13-2:17

      
        9
        11
               Amount j:2:20-2:20

      
        10
        12
                 Quantity: 10

      
        11
        13
                 Commodity: "$"

      ···
        15
        17
                 Decimal: "."

      
        16
        18
             Posting j:3:1-5:0

      
        17
        19
               Type: unbalanced virtual

      
        18
        
        -      Account "income:gift" j:3:4-3:15

      
        
        20
        +      Account j:3:4-3:15

      
        
        21
        +        SubAccount: "income" j:3:4-3:10

      
        
        22
        +        SubAccount: "gift" j:3:11-3:15

      
        19
        23
               Amount j:3:18-3:18

      
        20
        24
                 Quantity: -10

      
        21
        25
                 Commodity: "$"

      ···
        30
        34
             Posting j:6:1-7:1

      
        31
        35
               Type: unbalanced virtual

      
        32
        36
               Status: "!"

      
        33
        
        -      Account "assets:cash" j:6:8-6:19

      
        
        37
        +      Account j:6:8-6:19

      
        
        38
        +        SubAccount: "assets" j:6:8-6:14

      
        
        39
        +        SubAccount: "cash" j:6:15-6:19

      
        34
        40
               Amount j:6:22-6:22

      
        35
        41
                 Quantity: 10

      
        36
        42
                 Commodity: "$"

      ···
        40
        46
                 Decimal: "."

      
        41
        47
             Posting j:7:1-9:0

      
        42
        48
               Type: unbalanced virtual

      
        43
        
        -      Account "income:gift" j:7:6-7:17

      
        
        49
        +      Account j:7:6-7:17

      
        
        50
        +        SubAccount: "income" j:7:6-7:12

      
        
        51
        +        SubAccount: "gift" j:7:13-7:17

      
        44
        52
               Amount j:7:20-7:20

      
        45
        53
                 Quantity: -10

      
        46
        54
                 Commodity: "$"

      ···
        55
        63
             Posting j:10:1-11:1

      
        56
        64
               Type: unbalanced virtual

      
        57
        65
               Status: "!"

      
        58
        
        -      Account "assets:cash" j:10:10-10:21

      
        
        66
        +      Account j:10:10-10:21

      
        
        67
        +        SubAccount: "assets" j:10:10-10:16

      
        
        68
        +        SubAccount: "cash" j:10:17-10:21

      
        59
        69
               Amount j:10:24-10:24

      
        60
        70
                 Quantity: 10

      
        61
        71
                 Commodity: "$"

      ···
        66
        76
             Posting j:11:1-12:1

      
        67
        77
               Type: unbalanced virtual

      
        68
        78
               Status: "*"

      
        69
        
        -      Account "income:gift" j:11:8-11:19

      
        
        79
        +      Account j:11:8-11:19

      
        
        80
        +        SubAccount: "income" j:11:8-11:14

      
        
        81
        +        SubAccount: "gift" j:11:15-11:19

      
        70
        82
               Amount j:11:22-11:22

      
        71
        83
                 Quantity: -10

      
        72
        84
                 Commodity: "$"

      
M journal/printer/directives.go
···
        15
        15
         

      
        16
        16
         func (p *printer) writeAccountDirective(a *ast.AccountDirective) {

      
        17
        17
         	p.buf.WriteString("account ")

      
        18
        
        -	p.buf.WriteString(a.Account.Name)

      
        
        18
        +	p.buf.WriteString(a.Account.String())

      
        19
        19
         	p.writeInlineComment(a.Comment)

      
        20
        20
         }

      
        21
        21
         

      ···
        27
        27
         

      
        28
        28
         func (p *printer) writeAliasDirective(a *ast.AliasDirective) {

      
        29
        29
         	p.buf.WriteString("alias ")

      
        30
        
        -	p.buf.WriteString(a.From)

      
        
        30
        +	p.buf.WriteString(a.From.String())

      
        31
        31
         	p.buf.WriteString(" = ")

      
        32
        
        -	p.buf.WriteString(a.To)

      
        
        32
        +	p.buf.WriteString(a.To.String())

      
        33
        33
         	p.writeInlineComment(a.Comment)

      
        34
        34
         }

      
        35
        35
         

      
M journal/printer/transaction_postings.go
···
        67
        67
         		p.buf.WriteByte(' ')

      
        68
        68
         	}

      
        69
        69
         

      
        70
        
        -	acct := pt.Account.Name

      
        
        70
        +	acct := pt.Account.String()

      
        71
        71
         	switch pt.Type {

      
        72
        72
         	case ast.PostingVirtualUnbalanced:

      
        73
        73
         		acct = "(" + acct + ")"

      
M journal/tags/tag.go
···
        129
        129
         func (t *Tagger) collectFromEntry(pf *journal.ParsedFile, fpath string, entry ast.Entry) {

      
        130
        130
         	switch e := entry.(type) {

      
        131
        131
         	case *ast.AccountDirective:

      
        132
        
        -		t.addCandidate(e.Account.Name, fpath, e.Account.Span, pf.Src, KindAccount, prioAccountDirective)

      
        
        132
        +		t.addCandidate(e.Account.String(), fpath, e.Account.Span, pf.Src, KindAccount, prioAccountDirective)

      
        133
        133
         

      
        134
        134
         	case *ast.CommodityDirective:

      
        135
        135
         		t.addCandidate(e.Commodity, fpath, e.Span, pf.Src, KindCommodity, prioCommodityDirective)

      ···
        178
        178
         		}

      
        179
        179
         

      
        180
        180
         	case *ast.AliasDirective:

      
        181
        
        -		t.addCandidate(e.From, fpath, e.Span, pf.Src, KindAccount, prioAliasDirective)

      
        182
        
        -		t.addCandidate(e.To, fpath, e.Span, pf.Src, KindAccount, prioAliasDirective)

      
        
        181
        +		t.addCandidate(e.From.String(), fpath, e.Span, pf.Src, KindAccount, prioAliasDirective)

      
        
        182
        +		t.addCandidate(e.To.String(), fpath, e.Span, pf.Src, KindAccount, prioAliasDirective)

      
        183
        183
         	}

      
        184
        184
         }

      
        185
        185
         

      
        186
        186
         func (t *Tagger) collectFromPosting(p *ast.Posting, filePath string, src []byte) {

      
        187
        
        -	t.addCandidate(p.Account.Name, filePath, p.Account.Span, src, KindAccount, prioAccountPosting)

      
        
        187
        +	t.addCandidate(p.Account.String(), filePath, p.Account.Span, src, KindAccount, prioAccountPosting)

      
        188
        188
         	if p.Amount != nil && p.Amount.Commodity != "" {

      
        189
        189
         		t.addCandidate(p.Amount.Commodity, filePath, p.Amount.Span, src, KindCommodity, prioAmountCommodity)

      
        190
        190
         	}