Skip to content

Commit

Permalink
implemented save statement
Browse files Browse the repository at this point in the history
  • Loading branch information
ascandone committed Nov 8, 2024
1 parent 142c9cb commit 248f12e
Show file tree
Hide file tree
Showing 4 changed files with 421 additions and 19 deletions.
42 changes: 24 additions & 18 deletions internal/interpreter/batch_balances_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,32 @@ func (st *programState) findBalancesQueriesInStatement(statement parser.Statemen
case *parser.FnCall:
return nil

case *parser.SendStatement:
// set the current asset
switch sentValue := statement.SentValue.(type) {
case *parser.SentValueAll:
asset, err := evaluateLitExpecting(st, sentValue.Asset, expectAsset)
if err != nil {
return err
}
st.CurrentAsset = *asset
case *parser.SaveStatement:
asset, _, err := st.evaluateSentAmt(statement.SentValue)
if err != nil {
return err
}

Check warning on line 22 in internal/interpreter/batch_balances_query.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/batch_balances_query.go#L21-L22

Added lines #L21 - L22 were not covered by tests

case *parser.SentValueLiteral:
monetary, err := evaluateLitExpecting(st, sentValue.Monetary, expectMonetary)
if err != nil {
return err
}
st.CurrentAsset = string(monetary.Asset)
// Although we don't technically need this account's balance rn,
// having access to the balance simplifies the "save" statement implementation
// this means that we would have a needless query in the case in which the account
// which is selected in the "save" statement never actually appears as source
//
// this would mean that the "save" statement was not needed in the first place,
// so preventing this query would hardly be an useful optimization
account, err := evaluateLitExpecting(st, statement.Literal, expectAccount)
if err != nil {
return err
}

Check warning on line 34 in internal/interpreter/batch_balances_query.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/batch_balances_query.go#L33-L34

Added lines #L33 - L34 were not covered by tests
st.batchQuery(*account, *asset)
return nil

default:
utils.NonExhaustiveMatchPanic[any](sentValue)
case *parser.SendStatement:
asset, _, err := st.evaluateSentAmt(statement.SentValue)
if err != nil {
return err
}
st.CurrentAsset = *asset

// traverse source
return st.findBalancesQueries(statement.Source)
Expand All @@ -51,7 +57,7 @@ func (st *programState) batchQuery(account string, asset string) {
}

previousValues := st.CurrentBalanceQuery[account]
if !slices.Contains[[]string, string](previousValues, account) {
if !slices.Contains[[]string, string](previousValues, asset) {
st.CurrentBalanceQuery[account] = append(previousValues, asset)
}
}
Expand Down
63 changes: 63 additions & 0 deletions internal/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ func (st *programState) runStatement(statement parser.Statement) ([]Posting, Int

case *parser.SendStatement:
return st.runSendStatement(*statement)

case *parser.SaveStatement:
return st.runSaveStatement(*statement)

default:
utils.NonExhaustiveMatchPanic[any](statement)
return nil, nil
Expand All @@ -299,6 +303,41 @@ func (st *programState) getPostings() ([]Posting, InterpreterError) {
return postings, nil
}

func (st *programState) runSaveStatement(saveStatement parser.SaveStatement) ([]Posting, InterpreterError) {
asset, amt, err := st.evaluateSentAmt(saveStatement.SentValue)
if err != nil {
return nil, err
}

Check warning on line 310 in internal/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/interpreter.go#L309-L310

Added lines #L309 - L310 were not covered by tests

account, err := evaluateLitExpecting(st, saveStatement.Literal, expectAccount)
if err != nil {
return nil, err
}

Check warning on line 315 in internal/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/interpreter.go#L314-L315

Added lines #L314 - L315 were not covered by tests

balance := st.getCachedBalance(*account, *asset)

if amt == nil {
balance.Set(big.NewInt(0))
} else {
// Do not allow negative saves
if amt.Cmp(big.NewInt(0)) == -1 {
return nil, NegativeAmountErr{
Range: saveStatement.SentValue.GetRange(),
Amount: MonetaryInt(*amt),
}
}

// we decrease the balance by "amt"
balance.Sub(balance, amt)
// without going under 0
if balance.Cmp(big.NewInt(0)) == -1 {
balance.Set(big.NewInt(0))
}
}

return nil, nil
}

func (st *programState) runSendStatement(statement parser.SendStatement) ([]Posting, InterpreterError) {
switch sentValue := statement.SentValue.(type) {
case *parser.SentValueAll:
Expand Down Expand Up @@ -796,3 +835,27 @@ func setAccountMeta(st *programState, r parser.Range, args []Value) InterpreterE

return nil
}

func (st *programState) evaluateSentAmt(sentValue parser.SentValue) (*string, *big.Int, InterpreterError) {
switch sentValue := sentValue.(type) {
case *parser.SentValueAll:
asset, err := evaluateLitExpecting(st, sentValue.Asset, expectAsset)
if err != nil {
return nil, nil, err
}

Check warning on line 845 in internal/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/interpreter.go#L844-L845

Added lines #L844 - L845 were not covered by tests
return asset, nil, nil

case *parser.SentValueLiteral:
monetary, err := evaluateLitExpecting(st, sentValue.Monetary, expectMonetary)
if err != nil {
return nil, nil, err
}
s := string(monetary.Asset)
bi := big.Int(monetary.Amount)
return &s, &bi, nil

default:
utils.NonExhaustiveMatchPanic[any](sentValue)
return nil, nil, nil

Check warning on line 859 in internal/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

internal/interpreter/interpreter.go#L857-L859

Added lines #L857 - L859 were not covered by tests
}
}
Loading

0 comments on commit 248f12e

Please sign in to comment.