mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-13 09:57:51 +08:00
171 lines
3.2 KiB
Go
171 lines
3.2 KiB
Go
package eval
|
|
|
|
import (
|
|
"math"
|
|
"math/rand"
|
|
"strconv"
|
|
)
|
|
|
|
// Numerical operations.
|
|
|
|
func init() {
|
|
addToBuiltinFns([]*BuiltinFn{
|
|
// Comparison
|
|
{"<",
|
|
wrapNumCompare(func(a, b float64) bool { return a < b })},
|
|
{"<=",
|
|
wrapNumCompare(func(a, b float64) bool { return a <= b })},
|
|
{"==",
|
|
wrapNumCompare(func(a, b float64) bool { return a == b })},
|
|
{"!=",
|
|
wrapNumCompare(func(a, b float64) bool { return a != b })},
|
|
{">",
|
|
wrapNumCompare(func(a, b float64) bool { return a > b })},
|
|
{">=",
|
|
wrapNumCompare(func(a, b float64) bool { return a >= b })},
|
|
|
|
// Arithmetics
|
|
{"+", plus},
|
|
{"-", minus},
|
|
{"*", times},
|
|
{"/", slash},
|
|
{"^", pow},
|
|
{"%", mod},
|
|
|
|
// Random
|
|
{"rand", randFn},
|
|
{"randint", randint},
|
|
})
|
|
}
|
|
|
|
func wrapNumCompare(cmp func(a, b float64) bool) BuiltinFnImpl {
|
|
return func(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
TakeNoOpt(opts)
|
|
floats := make([]float64, len(args))
|
|
for i, a := range args {
|
|
f, err := toFloat(a)
|
|
maybeThrow(err)
|
|
floats[i] = f
|
|
}
|
|
result := true
|
|
for i := 0; i < len(floats)-1; i++ {
|
|
if !cmp(floats[i], floats[i+1]) {
|
|
result = false
|
|
break
|
|
}
|
|
}
|
|
ec.OutputChan() <- Bool(result)
|
|
}
|
|
}
|
|
|
|
func plus(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var nums []float64
|
|
ScanArgsVariadic(args, &nums)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
sum := 0.0
|
|
for _, f := range nums {
|
|
sum += f
|
|
}
|
|
out <- floatToString(sum)
|
|
}
|
|
|
|
func minus(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var (
|
|
sum float64
|
|
nums []float64
|
|
)
|
|
ScanArgsVariadic(args, &sum, &nums)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
if len(nums) == 0 {
|
|
// Unary -
|
|
sum = -sum
|
|
} else {
|
|
for _, f := range nums {
|
|
sum -= f
|
|
}
|
|
}
|
|
out <- floatToString(sum)
|
|
}
|
|
|
|
func times(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var nums []float64
|
|
ScanArgsVariadic(args, &nums)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
prod := 1.0
|
|
for _, f := range nums {
|
|
prod *= f
|
|
}
|
|
out <- floatToString(prod)
|
|
}
|
|
|
|
func slash(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
TakeNoOpt(opts)
|
|
if len(args) == 0 {
|
|
// cd /
|
|
cdInner("/", ec)
|
|
return
|
|
}
|
|
// Division
|
|
divide(ec, args, opts)
|
|
}
|
|
|
|
func divide(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var (
|
|
prod float64
|
|
nums []float64
|
|
)
|
|
ScanArgsVariadic(args, &prod, &nums)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
for _, f := range nums {
|
|
prod /= f
|
|
}
|
|
out <- floatToString(prod)
|
|
}
|
|
|
|
func pow(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var b, p float64
|
|
ScanArgs(args, &b, &p)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
out <- floatToString(math.Pow(b, p))
|
|
}
|
|
|
|
func mod(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var a, b int
|
|
ScanArgs(args, &a, &b)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
out <- String(strconv.Itoa(a % b))
|
|
}
|
|
|
|
func randFn(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
TakeNoArg(args)
|
|
TakeNoOpt(opts)
|
|
|
|
out := ec.ports[1].Chan
|
|
out <- floatToString(rand.Float64())
|
|
}
|
|
|
|
func randint(ec *EvalCtx, args []Value, opts map[string]Value) {
|
|
var low, high int
|
|
ScanArgs(args, &low, &high)
|
|
TakeNoOpt(opts)
|
|
|
|
if low >= high {
|
|
throw(ErrArgs)
|
|
}
|
|
out := ec.ports[1].Chan
|
|
i := low + rand.Intn(high-low)
|
|
out <- String(strconv.Itoa(i))
|
|
}
|