183 lines
4.6 KiB
Go
183 lines
4.6 KiB
Go
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()...)
|
|
}
|
|
|
|
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
|
|
}
|