From 956e0f067720638a8ea071830ab91ccfb1c6af37 Mon Sep 17 00:00:00 2001 From: ascandone Date: Tue, 17 Feb 2026 10:35:03 +0100 Subject: [PATCH 1/4] refactor: renamed file (no code changes) --- internal/interpreter/{funds_stack.go => funds_queue.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/interpreter/{funds_stack.go => funds_queue.go} (100%) diff --git a/internal/interpreter/funds_stack.go b/internal/interpreter/funds_queue.go similarity index 100% rename from internal/interpreter/funds_stack.go rename to internal/interpreter/funds_queue.go From 799615f69e3b578c40e0910f669ba2b65cfa0d00 Mon Sep 17 00:00:00 2001 From: ascandone Date: Tue, 17 Feb 2026 11:22:07 +0100 Subject: [PATCH 2/4] refactor: renamed test file (no code change) --- internal/interpreter/{funds_stack_test.go => funds_queue_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/interpreter/{funds_stack_test.go => funds_queue_test.go} (100%) diff --git a/internal/interpreter/funds_stack_test.go b/internal/interpreter/funds_queue_test.go similarity index 100% rename from internal/interpreter/funds_stack_test.go rename to internal/interpreter/funds_queue_test.go From 5e26cb405ec2576a85a103ae2736825ccc4b291e Mon Sep 17 00:00:00 2001 From: ascandone Date: Tue, 17 Feb 2026 11:21:08 +0100 Subject: [PATCH 3/4] refactor: renamed stack to queue --- internal/interpreter/funds_queue.go | 50 ++++++++--------- internal/interpreter/funds_queue_test.go | 68 ++++++++++++------------ internal/interpreter/interpreter.go | 14 ++--- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/internal/interpreter/funds_queue.go b/internal/interpreter/funds_queue.go index ca82877c..5a472aa8 100644 --- a/internal/interpreter/funds_queue.go +++ b/internal/interpreter/funds_queue.go @@ -10,9 +10,9 @@ type Sender struct { Color string } -type stack[T any] struct { +type queue[T any] struct { Head T - Tail *stack[T] + Tail *queue[T] // Instead of keeping a single ref of the lastCell and updating the invariant on every push/pop operation, // we keep a cache of the last cell on every cell. @@ -20,10 +20,10 @@ type stack[T any] struct { // // While, unlike keeping a single reference (like golang's queue `container/list` package does), this is not always O(1), // the amortized time should still be O(1) (the number of steps of traversal while searching the last elem is not higher than the number of .Push() calls) - lastCell *stack[T] + lastCell *queue[T] } -func (s *stack[T]) getLastCell() *stack[T] { +func (s *queue[T]) getLastCell() *queue[T] { // check if this is the last cell without reading cache first if s.Tail == nil { return s @@ -43,11 +43,11 @@ func (s *stack[T]) getLastCell() *stack[T] { return s.lastCell } -func fromSlice[T any](slice []T) *stack[T] { - var ret *stack[T] +func fromSlice[T any](slice []T) *queue[T] { + var ret *queue[T] // TODO use https://pkg.go.dev/slices#Backward in golang 1.23 for i := len(slice) - 1; i >= 0; i-- { - ret = &stack[T]{ + ret = &queue[T]{ Head: slice[i], Tail: ret, } @@ -55,24 +55,24 @@ func fromSlice[T any](slice []T) *stack[T] { return ret } -type fundsStack struct { - senders *stack[Sender] +type fundsQueue struct { + senders *queue[Sender] } -func newFundsStack(senders []Sender) fundsStack { - return fundsStack{ +func newFundsQueue(senders []Sender) fundsQueue { + return fundsQueue{ senders: fromSlice(senders), } } -func (s *fundsStack) compactTop() { +func (s *fundsQueue) compactTop() { for s.senders != nil && s.senders.Tail != nil { first := s.senders.Head second := s.senders.Tail.Head if second.Amount.Cmp(big.NewInt(0)) == 0 { - s.senders = &stack[Sender]{Head: first, Tail: s.senders.Tail.Tail} + s.senders = &queue[Sender]{Head: first, Tail: s.senders.Tail.Tail} continue } @@ -80,7 +80,7 @@ func (s *fundsStack) compactTop() { return } - s.senders = &stack[Sender]{ + s.senders = &queue[Sender]{ Head: Sender{ Name: first.Name, Color: first.Color, @@ -91,7 +91,7 @@ func (s *fundsStack) compactTop() { } } -func (s *fundsStack) PullAll() []Sender { +func (s *fundsQueue) PullAll() []Sender { var senders []Sender for s.senders != nil { senders = append(senders, s.senders.Head) @@ -100,7 +100,7 @@ func (s *fundsStack) PullAll() []Sender { return senders } -func (s *fundsStack) Push(senders ...Sender) { +func (s *fundsQueue) Push(senders ...Sender) { newTail := fromSlice(senders) if s.senders == nil { s.senders = newTail @@ -110,18 +110,18 @@ func (s *fundsStack) Push(senders ...Sender) { } } -func (s *fundsStack) PullAnything(requiredAmount *big.Int) []Sender { +func (s *fundsQueue) PullAnything(requiredAmount *big.Int) []Sender { return s.Pull(requiredAmount, nil) } -func (s *fundsStack) PullColored(requiredAmount *big.Int, color string) []Sender { +func (s *fundsQueue) PullColored(requiredAmount *big.Int, color string) []Sender { return s.Pull(requiredAmount, &color) } -func (s *fundsStack) PullUncolored(requiredAmount *big.Int) []Sender { +func (s *fundsQueue) PullUncolored(requiredAmount *big.Int) []Sender { return s.PullColored(requiredAmount, "") } -func (s *fundsStack) Pull(requiredAmount *big.Int, color *string) []Sender { +func (s *fundsQueue) Pull(requiredAmount *big.Int, color *string) []Sender { // clone so that we can manipulate this arg requiredAmount = new(big.Int).Set(requiredAmount) @@ -136,7 +136,7 @@ func (s *fundsStack) Pull(requiredAmount *big.Int, color *string) []Sender { if color != nil && available.Color != *color { out1 := s.Pull(requiredAmount, color) - s.senders = &stack[Sender]{ + s.senders = &queue[Sender]{ Head: available, Tail: s.senders, } @@ -150,7 +150,7 @@ func (s *fundsStack) Pull(requiredAmount *big.Int, color *string) []Sender { requiredAmount.Sub(requiredAmount, available.Amount) case 1: // more than enough - s.senders = &stack[Sender]{ + s.senders = &queue[Sender]{ Head: Sender{ Name: available.Name, Color: available.Color, @@ -174,9 +174,9 @@ func (s *fundsStack) Pull(requiredAmount *big.Int, color *string) []Sender { return out } -// Clone the stack so that you can safely mutate one without mutating the other -func (s fundsStack) Clone() fundsStack { - fs := newFundsStack(nil) +// Clone the queue so that you can safely mutate one without mutating the other +func (s fundsQueue) Clone() fundsQueue { + fs := newFundsQueue(nil) senders := s.senders for senders != nil { diff --git a/internal/interpreter/funds_queue_test.go b/internal/interpreter/funds_queue_test.go index a7a5d6af..fcfaf1ee 100644 --- a/internal/interpreter/funds_queue_test.go +++ b/internal/interpreter/funds_queue_test.go @@ -8,11 +8,11 @@ import ( ) func TestEnoughBalance(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(100)}, }) - out := stack.PullAnything(big.NewInt(2)) + out := queue.PullAnything(big.NewInt(2)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(2)}, }, out) @@ -20,10 +20,10 @@ func TestEnoughBalance(t *testing.T) { } func TestPush(t *testing.T) { - stack := newFundsStack(nil) - stack.Push(Sender{Name: "acc", Amount: big.NewInt(100)}) + queue := newFundsQueue(nil) + queue.Push(Sender{Name: "acc", Amount: big.NewInt(100)}) - out := stack.PullUncolored(big.NewInt(20)) + out := queue.PullUncolored(big.NewInt(20)) require.Equal(t, []Sender{ {Name: "acc", Amount: big.NewInt(20)}, }, out) @@ -31,107 +31,107 @@ func TestPush(t *testing.T) { } func TestSimple(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s2", Amount: big.NewInt(10)}, }) - out := stack.PullAnything(big.NewInt(5)) + out := queue.PullAnything(big.NewInt(5)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s2", Amount: big.NewInt(3)}, }, out) - out = stack.PullAnything(big.NewInt(7)) + out = queue.PullAnything(big.NewInt(7)) require.Equal(t, []Sender{ {Name: "s2", Amount: big.NewInt(7)}, }, out) } func TestPullZero(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s2", Amount: big.NewInt(10)}, }) - out := stack.PullAnything(big.NewInt(0)) + out := queue.PullAnything(big.NewInt(0)) require.Equal(t, []Sender(nil), out) } func TestCompactFunds(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s1", Amount: big.NewInt(10)}, }) - out := stack.PullAnything(big.NewInt(5)) + out := queue.PullAnything(big.NewInt(5)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(5)}, }, out) } func TestCompactFunds3Times(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s1", Amount: big.NewInt(3)}, {Name: "s1", Amount: big.NewInt(1)}, }) - out := stack.PullAnything(big.NewInt(6)) + out := queue.PullAnything(big.NewInt(6)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(6)}, }, out) } func TestCompactFundsWithEmptySender(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s2", Amount: big.NewInt(0)}, {Name: "s1", Amount: big.NewInt(10)}, }) - out := stack.PullAnything(big.NewInt(5)) + out := queue.PullAnything(big.NewInt(5)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(5)}, }, out) } func TestMissingFunds(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, }) - out := stack.PullAnything(big.NewInt(300)) + out := queue.PullAnything(big.NewInt(300)) require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(2)}, }, out) } func TestNoZeroLeftovers(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(10)}, {Name: "s2", Amount: big.NewInt(15)}, }) - stack.PullAnything(big.NewInt(10)) + queue.PullAnything(big.NewInt(10)) - out := stack.PullAnything(big.NewInt(15)) + out := queue.PullAnything(big.NewInt(15)) require.Equal(t, []Sender{ {Name: "s2", Amount: big.NewInt(15)}, }, out) } func TestReconcileColoredManyDestPerSender(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {"src", big.NewInt(10), "X"}, }) - out := stack.PullColored(big.NewInt(5), "X") + out := queue.PullColored(big.NewInt(5), "X") require.Equal(t, []Sender{ {Name: "src", Amount: big.NewInt(5), Color: "X"}, }, out) - out = stack.PullColored(big.NewInt(5), "X") + out = queue.PullColored(big.NewInt(5), "X") require.Equal(t, []Sender{ {Name: "src", Amount: big.NewInt(5), Color: "X"}, }, out) @@ -139,7 +139,7 @@ func TestReconcileColoredManyDestPerSender(t *testing.T) { } func TestPullColored(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(5)}, {Name: "s2", Amount: big.NewInt(1), Color: "red"}, {Name: "s3", Amount: big.NewInt(10)}, @@ -147,7 +147,7 @@ func TestPullColored(t *testing.T) { {Name: "s5", Amount: big.NewInt(5)}, }) - out := stack.PullColored(big.NewInt(2), "red") + out := queue.PullColored(big.NewInt(2), "red") require.Equal(t, []Sender{ {Name: "s2", Amount: big.NewInt(1), Color: "red"}, {Name: "s4", Amount: big.NewInt(1), Color: "red"}, @@ -158,16 +158,16 @@ func TestPullColored(t *testing.T) { {Name: "s3", Amount: big.NewInt(10)}, {Name: "s4", Amount: big.NewInt(1), Color: "red"}, {Name: "s5", Amount: big.NewInt(5)}, - }, stack.PullAll()) + }, queue.PullAll()) } func TestPullColoredComplex(t *testing.T) { - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {"s1", big.NewInt(1), "c1"}, {"s2", big.NewInt(1), "c2"}, }) - out := stack.PullColored(big.NewInt(1), "c2") + out := queue.PullColored(big.NewInt(1), "c2") require.Equal(t, []Sender{ {Name: "s2", Amount: big.NewInt(1), Color: "c2"}, }, out) @@ -175,7 +175,7 @@ func TestPullColoredComplex(t *testing.T) { func TestClone(t *testing.T) { - fs := newFundsStack([]Sender{ + fs := newFundsQueue([]Sender{ {"s1", big.NewInt(10), ""}, }) @@ -192,19 +192,19 @@ func TestClone(t *testing.T) { func TestCompactFundsAndPush(t *testing.T) { noCol := "" - stack := newFundsStack([]Sender{ + queue := newFundsQueue([]Sender{ {Name: "s1", Amount: big.NewInt(2)}, {Name: "s1", Amount: big.NewInt(10)}, }) - stack.Pull(big.NewInt(1), &noCol) + queue.Pull(big.NewInt(1), &noCol) - stack.Push(Sender{ + queue.Push(Sender{ Name: "pushed", Amount: big.NewInt(42), }) - out := stack.PullAll() + out := queue.PullAll() require.Equal(t, []Sender{ {Name: "s1", Amount: big.NewInt(11)}, {Name: "pushed", Amount: big.NewInt(42)}, diff --git a/internal/interpreter/interpreter.go b/internal/interpreter/interpreter.go index 64ff651f..07c58d47 100644 --- a/internal/interpreter/interpreter.go +++ b/internal/interpreter/interpreter.go @@ -294,7 +294,7 @@ func RunProgram( SetAccountsMeta: AccountsMetadata{}, Store: store, Postings: make([]Posting, 0), - fundsStack: newFundsStack(nil), + fundsQueue: newFundsQueue(nil), CurrentBalanceQuery: BalanceQuery{}, ctx: ctx, @@ -358,7 +358,7 @@ type programState struct { ParsedVars map[string]Value TxMeta map[string]Value Postings []Posting - fundsStack fundsStack + fundsQueue fundsQueue Store Store @@ -380,7 +380,7 @@ func (st *programState) pushSender(name string, monetary *big.Int, color string) balance := st.CachedBalances.fetchBalance(name, st.CurrentAsset, color) balance.Sub(balance, monetary) - st.fundsStack.Push(Sender{Name: name, Amount: monetary, Color: color}) + st.fundsQueue.Push(Sender{Name: name, Amount: monetary, Color: color}) } // Append a posting without checking if account has enough balance. @@ -407,7 +407,7 @@ func (st *programState) pushReceiver(name string, monetary *big.Int) { return } - senders := st.fundsStack.PullAnything(monetary) + senders := st.fundsQueue.PullAnything(monetary) for _, sender := range senders { postings := Posting{ @@ -729,11 +729,11 @@ func (s *programState) trySendingToAccount(accountLiteral parser.ValueExpr, amou } func (s *programState) cloneState() func() { - fsBackup := s.fundsStack.Clone() + fsBackup := s.fundsQueue.Clone() balancesBackup := s.CachedBalances.DeepClone() return func() { - s.fundsStack = fsBackup + s.fundsQueue = fsBackup s.CachedBalances = balancesBackup } } @@ -822,7 +822,7 @@ func (s *programState) trySendingUpTo(source parser.Source, amount *big.Int) (*b leadingSources := source.Sources[0 : len(source.Sources)-1] for _, source := range leadingSources { - // do not move this line below (as .trySendingUpTo() will mutate the fundsStack) + // do not move this line below (as .trySendingUpTo() will mutate the fundsQueue) undo := s.cloneState() sentAmt, err := s.trySendingUpTo(source, amount) From 420328dbc39c4347d17ded416621b5407d864716 Mon Sep 17 00:00:00 2001 From: ascandone Date: Tue, 17 Feb 2026 11:27:59 +0100 Subject: [PATCH 4/4] refactor: renamed some other vars --- internal/interpreter/funds_queue.go | 6 +++--- internal/interpreter/funds_queue_test.go | 6 +++--- internal/interpreter/interpreter.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/interpreter/funds_queue.go b/internal/interpreter/funds_queue.go index 5a472aa8..007c791a 100644 --- a/internal/interpreter/funds_queue.go +++ b/internal/interpreter/funds_queue.go @@ -176,13 +176,13 @@ func (s *fundsQueue) Pull(requiredAmount *big.Int, color *string) []Sender { // Clone the queue so that you can safely mutate one without mutating the other func (s fundsQueue) Clone() fundsQueue { - fs := newFundsQueue(nil) + fq := newFundsQueue(nil) senders := s.senders for senders != nil { - fs.Push(senders.Head) + fq.Push(senders.Head) senders = senders.Tail } - return fs + return fq } diff --git a/internal/interpreter/funds_queue_test.go b/internal/interpreter/funds_queue_test.go index fcfaf1ee..87672be9 100644 --- a/internal/interpreter/funds_queue_test.go +++ b/internal/interpreter/funds_queue_test.go @@ -175,13 +175,13 @@ func TestPullColoredComplex(t *testing.T) { func TestClone(t *testing.T) { - fs := newFundsQueue([]Sender{ + fq := newFundsQueue([]Sender{ {"s1", big.NewInt(10), ""}, }) - cloned := fs.Clone() + cloned := fq.Clone() - fs.PullAll() + fq.PullAll() require.Equal(t, []Sender{ {"s1", big.NewInt(10), ""}, diff --git a/internal/interpreter/interpreter.go b/internal/interpreter/interpreter.go index 07c58d47..04c94bdf 100644 --- a/internal/interpreter/interpreter.go +++ b/internal/interpreter/interpreter.go @@ -729,11 +729,11 @@ func (s *programState) trySendingToAccount(accountLiteral parser.ValueExpr, amou } func (s *programState) cloneState() func() { - fsBackup := s.fundsQueue.Clone() + fqBackup := s.fundsQueue.Clone() balancesBackup := s.CachedBalances.DeepClone() return func() { - s.fundsQueue = fsBackup + s.fundsQueue = fqBackup s.CachedBalances = balancesBackup } }