elvish/pkg/eval/builtin_fn_num.go
2019-12-23 20:00:59 +00:00

155 lines
2.2 KiB
Go

package eval
import (
"math"
"math/rand"
"github.com/elves/elvish/pkg/eval/vals"
)
// Numerical operations.
func init() {
addBuiltinFns(map[string]interface{}{
// Constructor
"float64": toFloat64,
// Comparison
"<": lt,
"<=": le,
"==": eqNum,
"!=": ne,
">": gt,
">=": ge,
// Arithmetics
"+": plus,
"-": minus,
"*": times,
"/": slash,
"^": math.Pow,
"%": mod,
// Random
"rand": rand.Float64,
"randint": randint,
})
}
func toFloat64(f float64) float64 {
return f
}
func lt(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] < nums[i+1]) {
return false
}
}
return true
}
func le(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] <= nums[i+1]) {
return false
}
}
return true
}
func eqNum(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] == nums[i+1]) {
return false
}
}
return true
}
func ne(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] != nums[i+1]) {
return false
}
}
return true
}
func gt(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] > nums[i+1]) {
return false
}
}
return true
}
func ge(nums ...float64) bool {
for i := 0; i < len(nums)-1; i++ {
if !(nums[i] >= nums[i+1]) {
return false
}
}
return true
}
func plus(nums ...float64) float64 {
sum := 0.0
for _, f := range nums {
sum += f
}
return sum
}
func minus(sum float64, nums ...float64) float64 {
if len(nums) == 0 {
// Unary -
return -sum
}
for _, f := range nums {
sum -= f
}
return sum
}
func times(nums ...float64) float64 {
prod := 1.0
for _, f := range nums {
prod *= f
}
return prod
}
func slash(fm *Frame, args ...float64) error {
if len(args) == 0 {
// cd /
return fm.Chdir("/")
}
// Division
divide(fm, args[0], args[1:]...)
return nil
}
func divide(fm *Frame, prod float64, nums ...float64) {
out := fm.ports[1].Chan
for _, f := range nums {
prod /= f
}
out <- vals.FromGo(prod)
}
func mod(a, b int) (int, error) {
if b == 0 {
return 0, ErrArgs
}
return a % b, nil
}
func randint(low, high int) (int, error) {
if low >= high {
return 0, ErrArgs
}
return low + rand.Intn(high-low), nil
}