package calc import ( "gitea.zaclys.com/bvaudour/gob/number" "gitea.zaclys.com/bvaudour/gob/option" ) type Calc struct { stack Stack registry Registry macro Macro } type CalcFunc func(*Calc) option.Option[error] type IntCalcFunc[N integer] func(...N) CalcFunc type WordCalcFunc func(string) CalcFunc type CalcErrFunc func(*Calc) []error func New() *Calc { return &Calc{ registry: make(Registry), macro: make(Macro), } } func (c *Calc) SetPrecision(precision option.Option[uint64], fix option.Option[bool]) { if p, ok := precision.Get(); ok { number.FloatingPrecision = p } if f, ok := fix.Get(); ok { number.FixedPrecision = f } } func (c *Calc) Precision() (precision uint64, fix bool) { return number.FloatingPrecision, number.FixedPrecision } func (c *Calc) Push(numbers ...number.Number) { c.stack.Push(numbers...) } func (c *Calc) Stack() Stack { return c.stack.Clone() } func (c *Calc) GetStack() (result option.Result[Stack]) { if c.stack.IsEmpty() { result = option.Err[Stack](ErrIsEmpty(errStack)) } else { result = option.Ok(c.Stack()) } return } func (c *Calc) Len() { c.Push(number.IntOf(c.stack.Len())) } func (c *Calc) Last() option.Result[number.Number] { return c.stack.Last() } func (c *Calc) Pop() (err option.Option[error]) { if e, ok := c.stack.Pop().Err(); ok { err = option.Some(e) } return } func (c *Calc) Reset() option.Option[error] { return c.stack.Reset() } func (c *Calc) Duplicate() option.Option[error] { return c.stack.Duplicate() } func (c *Calc) DuplicateStack() option.Option[error] { return c.stack.DuplicateAll() } func (c *Calc) Reverse() option.Option[error] { return c.stack.Reverse() } func (c *Calc) ReverseStack() option.Option[error] { return c.stack.ReverseAll() } func (c *Calc) Sort() option.Option[error] { return c.stack.Sort() } func (c *Calc) SortDesc() option.Option[error] { return c.stack.SortDesc() } func (c *Calc) Registries() Registry { return c.registry.Clone() } func (c *Calc) GetRegistries() (result option.Result[Registry]) { if len(c.registry) == 0 { result = option.Err[Registry](ErrIsEmpty(errMemory)) } else { result = option.Ok(c.Registries()) } return } func (c *Calc) Registry(k string) option.Result[Stack] { return c.registry.Get(k) } func (c *Calc) ResetRegistry(k string) option.Option[error] { return c.registry.Reset(k) } func (c *Calc) ResetRegistries() option.Option[error] { return c.registry.ResetAll() } func (c *Calc) Store(k string) (err option.Option[error]) { pop := c.stack.Pop() if n, ok := pop.Ok(); ok { c.registry.Set(k, n) } else if e, ok := pop.Err(); ok { err = option.Some(e) } return } func (c *Calc) StoreStack(k string) (err option.Option[error]) { if c.stack.IsEmpty() { err = option.Some(ErrIsEmpty(errStack)) } else { c.registry.Set(k, c.Stack()...) c.Reset() } return } func (c *Calc) Load(k string) (err option.Option[error]) { result := c.registry.Get(k) if s, ok := result.Ok(); ok { c.Push(s...) } else if e, ok := result.Err(); ok { err = option.Some(e) } return } func (c *Calc) Macros() Macro { return c.macro.Clone() } func (c *Calc) GetMacros() (result option.Result[Macro]) { if len(c.macro) == 0 { result = option.Err[Macro](ErrIsEmpty(errMemory)) } else { result = option.Ok(c.Macros()) } return } func (c *Calc) Macro(k string) (result option.Result[MacroStack]) { return c.macro.Get(k) } func (c *Calc) StoreMacro(k string, args ...MacroElement) { c.macro.Set(k, args) } func (c *Calc) Exec(s MacroStack) (errors []error) { for _, e := range s { if n, ok := e.Left(); ok { c.Push(n) } else if f, ok := e.Right(); ok { if err, ok := f(c).Get(); ok { errors = append(errors, err) } } } return } func (c *Calc) ExecMacro(k string) (errors []error) { result := c.macro.Get(k) if s, ok := result.Ok(); ok { errors = c.Exec(s) } else if err, ok := result.Err(); ok { errors = append(errors, err) } return } func (c *Calc) ResetMacro(k string) option.Option[error] { return c.macro.Reset(k) } func (c *Calc) ResetMacros() option.Option[error] { return c.macro.ResetAll() } func (c *Calc) NoAction() (error option.Option[error]) { return } func (c *Calc) If(e1, e2 MacroElement) (err option.Option[error]) { result := c.stack.Pop() if n, ok := result.Ok(); ok { if n.IsZero() || n.IsNan() { if n2, ok := e2.Left(); ok { c.Push(n2) } else if c2, ok := e2.Right(); ok { c2(c) } } else if n1, ok := e1.Left(); ok { c.Push(n1) } else if c1, ok := e1.Right(); ok { c1(c) } } else if e, ok := result.Err(); ok { err = option.Some(e) } return }