elvish/eval/builtin_fn.go

165 lines
3.1 KiB
Go
Raw Normal View History

package eval
// Builtin functions.
2013-10-02 22:10:07 +08:00
import (
"errors"
2014-01-16 09:24:14 +08:00
"fmt"
2016-03-17 22:28:00 +08:00
"math/rand"
2016-11-06 17:47:20 +08:00
"net"
"path/filepath"
2016-02-10 01:18:18 +08:00
"time"
2017-08-31 02:52:27 +08:00
"unsafe"
2016-02-14 04:05:35 +08:00
"github.com/elves/elvish/eval/types"
"github.com/elves/elvish/util"
2017-08-31 02:52:27 +08:00
"github.com/xiaq/persistent/hash"
2013-10-02 22:10:07 +08:00
)
2016-02-19 05:52:05 +08:00
// BuiltinFn is a builtin function.
type BuiltinFn struct {
Name string
Impl BuiltinFnImpl
2016-02-19 05:52:05 +08:00
}
type BuiltinFnImpl func(*Frame, []interface{}, map[string]interface{})
var _ Callable = &BuiltinFn{}
2017-06-11 07:04:53 +08:00
// Kind returns "fn".
2016-02-19 05:52:05 +08:00
func (*BuiltinFn) Kind() string {
return "fn"
}
2017-08-31 01:47:50 +08:00
// Equal compares based on identity.
func (b *BuiltinFn) Equal(rhs interface{}) bool {
return b == rhs
}
2017-08-31 02:52:27 +08:00
func (b *BuiltinFn) Hash() uint32 {
return hash.Pointer(unsafe.Pointer(b))
}
2017-06-11 07:04:53 +08:00
// Repr returns an opaque representation "<builtin xxx>".
func (b *BuiltinFn) Repr(int) string {
return "<builtin " + b.Name + ">"
2016-02-19 05:52:05 +08:00
}
// Call calls a builtin function.
func (b *BuiltinFn) Call(ec *Frame, args []interface{}, opts map[string]interface{}) error {
return util.PCall(func() { b.Impl(ec, args, opts) })
2016-02-19 05:52:05 +08:00
}
2017-12-17 13:20:03 +08:00
var builtinFns []*BuiltinFn
func addToBuiltinFns(moreFns []*BuiltinFn) {
builtinFns = append(builtinFns, moreFns...)
}
// Builtins that have not been put into their own groups go here.
var ErrArgs = errors.New("args error")
2015-01-23 06:19:27 +08:00
func init() {
2017-12-17 13:20:03 +08:00
addToBuiltinFns([]*BuiltinFn{
2017-05-22 06:18:24 +08:00
{"nop", nop},
2015-03-01 21:43:35 +08:00
2017-05-22 06:18:24 +08:00
{"kind-of", kindOf},
2016-10-13 17:59:06 +08:00
2017-05-22 06:18:24 +08:00
{"constantly", constantly},
2017-04-11 08:16:43 +08:00
{"-source", source},
2017-04-11 08:16:43 +08:00
// Time
2017-05-22 06:18:24 +08:00
{"esleep", sleep},
{"-time", _time},
2017-04-11 08:16:43 +08:00
2017-05-22 06:18:24 +08:00
{"-ifaddrs", _ifaddrs},
2017-12-17 13:20:03 +08:00
})
2016-03-17 22:30:15 +08:00
// For rand and randint.
rand.Seed(time.Now().UTC().UnixNano())
}
func nop(ec *Frame, args []interface{}, opts map[string]interface{}) {
2015-03-01 21:43:35 +08:00
}
func kindOf(ec *Frame, args []interface{}, opts map[string]interface{}) {
2016-09-15 08:45:44 +08:00
TakeNoOpt(opts)
2016-02-09 03:11:20 +08:00
out := ec.ports[1].Chan
2015-01-20 05:04:37 +08:00
for _, a := range args {
out <- types.Kind(a)
2015-01-20 05:04:37 +08:00
}
}
func constantly(ec *Frame, args []interface{}, opts map[string]interface{}) {
2017-04-11 08:16:43 +08:00
TakeNoOpt(opts)
out := ec.ports[1].Chan
// XXX Repr of this fn is not right
out <- &BuiltinFn{
"created by constantly",
func(ec *Frame, a []interface{}, o map[string]interface{}) {
2017-04-11 08:16:43 +08:00
TakeNoOpt(o)
if len(a) != 0 {
throw(ErrArgs)
}
2017-04-11 08:16:43 +08:00
out := ec.ports[1].Chan
for _, v := range args {
out <- v
}
},
}
}
func source(ec *Frame, args []interface{}, opts map[string]interface{}) {
var argFname string
ScanArgs(args, &argFname)
2017-04-11 08:16:43 +08:00
ScanOpts(opts)
fname := argFname
abs, err := filepath.Abs(fname)
maybeThrow(err)
maybeThrow(ec.Source(fname, abs))
2017-04-11 08:16:43 +08:00
}
func sleep(ec *Frame, args []interface{}, opts map[string]interface{}) {
var t float64
ScanArgs(args, &t)
TakeNoOpt(opts)
d := time.Duration(float64(time.Second) * t)
select {
case <-ec.Interrupts():
throw(ErrInterrupted)
case <-time.After(d):
}
2016-02-10 01:18:18 +08:00
}
func _time(ec *Frame, args []interface{}, opts map[string]interface{}) {
var f Callable
2017-04-11 08:16:43 +08:00
ScanArgs(args, &f)
TakeNoOpt(opts)
t0 := time.Now()
err := f.Call(ec, NoArgs, NoOpts)
maybeThrow(err)
2017-04-11 08:16:43 +08:00
t1 := time.Now()
dt := t1.Sub(t0)
fmt.Fprintln(ec.ports[1].File, dt)
}
func _ifaddrs(ec *Frame, args []interface{}, opts map[string]interface{}) {
TakeNoArg(args)
TakeNoOpt(opts)
2016-11-06 17:47:20 +08:00
out := ec.ports[1].Chan
addrs, err := net.InterfaceAddrs()
maybeThrow(err)
for _, addr := range addrs {
out <- addr.String()
2016-11-06 17:47:20 +08:00
}
}