Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented string_to_account() function expression #28

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions internal/analysis/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const FnSetAccountMeta = "set_account_meta"
const FnVarOriginMeta = "meta"
const FnVarOriginBalance = "balance"
const FnVarOriginOverdraft = "overdraft"
const FnVarOriginStringToAccount = "string_to_account"

var Builtins = map[string]FnCallResolution{
FnSetTxMeta: StatementFnCallResolution{
Expand All @@ -81,6 +82,11 @@ var Builtins = map[string]FnCallResolution{
Return: TypeMonetary,
Docs: "get absolute amount of the overdraft of an account. Returns zero if balance is not negative",
},
FnVarOriginStringToAccount: VarOriginFnCallResolution{
Params: []string{TypeString},
Return: TypeAccount,
Docs: "cast a string to an account",
},
}

type Diagnostic struct {
Expand Down
4 changes: 4 additions & 0 deletions internal/interpreter/evaluate_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func (st *programState) plusOp(left parser.ValueExpr, right parser.ValueExpr) (V
expectMapped(expectNumber, func(bi big.Int) opAdd {
return MonetaryInt(bi)
}),

expectMapped(expectString, func(str string) opAdd {
return String(str)
}),
))

if err != nil {
Expand Down
151 changes: 151 additions & 0 deletions internal/interpreter/function_expressions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package interpreter

import (
"math/big"

"github.com/formancehq/numscript/internal/parser"
)

func stringToAccount(
s *programState,
rng parser.Range,
args []Value,
) (Value, InterpreterError) {
if !s.StringToAccountFunctionFeatureFlag {
return nil, ExperimentalFeature{FlagName: ExperimentalStringToAccountFunctionFeatureFlag}
}

// TODO more precise location
p := NewArgsParser(args)
accountStr := parseArg(p, rng, expectString)
err := p.parse()
if err != nil {
return nil, err
}

return AccountAddress(*accountStr), nil
}

func meta(
s *programState,
rng parser.Range,
args []Value,
) (string, InterpreterError) {
// TODO more precise location
p := NewArgsParser(args)
account := parseArg(p, rng, expectAccount)
key := parseArg(p, rng, expectString)
err := p.parse()
if err != nil {
return "", err
}

meta, fetchMetaErr := s.Store.GetAccountsMetadata(s.ctx, MetadataQuery{
*account: []string{*key},
})
if fetchMetaErr != nil {
return "", QueryMetadataError{WrappedError: fetchMetaErr}
}
s.CachedAccountsMeta = meta

// body
accountMeta := s.CachedAccountsMeta[*account]
value, ok := accountMeta[*key]

if !ok {
return "", MetadataNotFound{Account: *account, Key: *key, Range: rng}
}

return value, nil
}

func balance(
s *programState,
r parser.Range,
args []Value,
) (*Monetary, InterpreterError) {
// TODO more precise args range location
p := NewArgsParser(args)
account := parseArg(p, r, expectAccount)
asset := parseArg(p, r, expectAsset)
err := p.parse()
if err != nil {
return nil, err
}

// body

balance, err := getBalance(s, *account, *asset)
if err != nil {
return nil, err
}

if balance.Cmp(big.NewInt(0)) == -1 {
return nil, NegativeBalanceError{
Account: *account,
Amount: *balance,
}
}

balanceCopy := new(big.Int).Set(balance)

m := Monetary{
Asset: Asset(*asset),
Amount: MonetaryInt(*balanceCopy),
}
return &m, nil
}

func overdraft(
s *programState,
r parser.Range,
args []Value,
) (*Monetary, InterpreterError) {
if !s.OverdraftFunctionFeatureFlag {
return nil, ExperimentalFeature{FlagName: ExperimentalOverdraftFunctionFeatureFlag}
}

// TODO more precise args range location
p := NewArgsParser(args)
account := parseArg(p, r, expectAccount)
asset := parseArg(p, r, expectAsset)
err := p.parse()
if err != nil {
return nil, err
}

balance_, err := getBalance(s, *account, *asset)
if err != nil {
return nil, err
}

balanceIsPositive := balance_.Cmp(big.NewInt(0)) == 1
if balanceIsPositive {
return &Monetary{
Amount: NewMonetaryInt(0),
Asset: Asset(*asset),
}, nil
}

overdraft := new(big.Int).Neg(balance_)
return &Monetary{
Amount: MonetaryInt(*overdraft),
Asset: Asset(*asset),
}, nil
}

// Utility function to get the balance
func getBalance(
s *programState,
account string,
asset string,
) (*big.Int, InterpreterError) {
s.batchQuery(account, asset)
fetchBalanceErr := s.runBalancesQuery()
if fetchBalanceErr != nil {
return nil, QueryBalanceError{WrappedError: fetchBalanceErr}
}
balance := s.getCachedBalance(account, asset)
return balance, nil

}
35 changes: 35 additions & 0 deletions internal/interpreter/function_statements.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package interpreter

import "github.com/formancehq/numscript/internal/parser"

func setTxMeta(st *programState, r parser.Range, args []Value) InterpreterError {
p := NewArgsParser(args)
key := parseArg(p, r, expectString)
meta := parseArg(p, r, expectAnything)
err := p.parse()
if err != nil {
return err
}

st.TxMeta[*key] = *meta
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure thread safety when modifying TxMeta

In the setTxMeta function, assigning to st.TxMeta[*key] occurs without synchronization. If programState may be accessed concurrently, consider implementing mutex locks or other synchronization mechanisms to prevent potential data races.

return nil
}

func setAccountMeta(st *programState, r parser.Range, args []Value) InterpreterError {
p := NewArgsParser(args)
account := parseArg(p, r, expectAccount)
key := parseArg(p, r, expectString)
meta := parseArg(p, r, expectAnything)
err := p.parse()
if err != nil {
return err
}

accountMeta := defaultMapGet(st.SetAccountsMeta, *account, func() AccountMetadata {
return AccountMetadata{}
})

accountMeta[*key] = (*meta).String()

return nil
}
10 changes: 10 additions & 0 deletions internal/interpreter/infix.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type opAdd interface {

var _ opAdd = (*MonetaryInt)(nil)
var _ opAdd = (*Monetary)(nil)
var _ opAdd = (*String)(nil)

func (m MonetaryInt) evalAdd(st *programState, other parser.ValueExpr) (Value, InterpreterError) {
m1 := big.Int(m)
Expand All @@ -24,6 +25,15 @@ func (m MonetaryInt) evalAdd(st *programState, other parser.ValueExpr) (Value, I
return MonetaryInt(*sum), nil
}

func (m String) evalAdd(st *programState, other parser.ValueExpr) (Value, InterpreterError) {
m1 := string(m)
m2, err := evaluateExprAs(st, other, expectString)
if err != nil {
return nil, err
}
return String(string(m1) + *m2), nil
}

func (m Monetary) evalAdd(st *programState, other parser.ValueExpr) (Value, InterpreterError) {
m2, err := evaluateExprAs(st, other, expectMonetary)
if err != nil {
Expand Down
Loading
Loading