evcc-io/tariff/embed.go

79 lines
1.4 KiB
Go

package tariff
import (
"errors"
"fmt"
"github.com/traefik/yaegi/interp"
"github.com/traefik/yaegi/stdlib"
)
type embed struct {
Charges float64 `mapstructure:"charges"`
Tax float64 `mapstructure:"tax"`
Formula string `mapstructure:"formula"`
calc func(float64) (float64, error)
}
func (t *embed) init() error {
if t.Formula == "" {
return nil
}
vm := interp.New(interp.Options{})
if err := vm.Use(stdlib.Symbols); err != nil {
return err
}
if _, err := vm.Eval(`import "math"`); err != nil {
return err
}
if _, err := vm.Eval("var price, charges, tax float64"); err != nil {
return err
}
if _, err := vm.Eval(fmt.Sprintf("charges = %f", t.Charges)); err != nil {
return err
}
if _, err := vm.Eval(fmt.Sprintf("tax = %f", t.Tax)); err != nil {
return err
}
prg, err := vm.Compile(t.Formula)
if err != nil {
return err
}
t.calc = func(price float64) (float64, error) {
if _, err := vm.Eval(fmt.Sprintf("price = %f", price)); err != nil {
return 0, err
}
res, err := vm.Execute(prg)
if err != nil {
return 0, err
}
if !res.CanFloat() {
return 0, errors.New("formula did not return a float value")
}
return res.Float(), nil
}
// test the formula
_, err = t.calc(0)
return err
}
func (t *embed) totalPrice(price float64) float64 {
if t.calc != nil {
res, _ := t.calc(price)
return res
}
return (price + t.Charges) * (1 + t.Tax)
}