2013-10-01 21:34:49 +08:00
|
|
|
package eval
|
|
|
|
|
2014-04-02 10:51:09 +08:00
|
|
|
// Builtin functions.
|
|
|
|
|
2013-10-02 22:10:07 +08:00
|
|
|
import (
|
2016-01-31 09:21:46 +08:00
|
|
|
"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"
|
2018-01-05 12:07:11 +08:00
|
|
|
"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
|
|
|
|
2018-01-01 04:31:45 +08:00
|
|
|
"github.com/elves/elvish/eval/types"
|
2016-02-17 02:14:05 +08:00
|
|
|
"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
|
2017-07-13 18:35:06 +08:00
|
|
|
Impl BuiltinFnImpl
|
2016-02-19 05:52:05 +08:00
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
type BuiltinFnImpl func(*Frame, []interface{}, map[string]interface{})
|
2017-07-13 18:35:06 +08:00
|
|
|
|
2018-01-30 01:46:21 +08:00
|
|
|
var _ Callable = &BuiltinFn{}
|
2016-09-15 05:34:10 +08:00
|
|
|
|
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 {
|
2017-07-14 08:15:14 +08:00
|
|
|
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>".
|
2016-02-20 03:11:31 +08:00
|
|
|
func (b *BuiltinFn) Repr(int) string {
|
2016-04-05 12:20:18 +08:00
|
|
|
return "<builtin " + b.Name + ">"
|
2016-02-19 05:52:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Call calls a builtin function.
|
2018-01-30 01:39:41 +08:00
|
|
|
func (b *BuiltinFn) Call(ec *Frame, args []interface{}, opts map[string]interface{}) error {
|
2018-01-21 19:05:36 +08:00
|
|
|
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
|
|
|
|
2017-07-13 17:54:20 +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())
|
2013-10-01 21:34:49 +08:00
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
func nop(ec *Frame, args []interface{}, opts map[string]interface{}) {
|
2015-03-01 21:43:35 +08:00
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +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 {
|
2018-01-25 09:40:15 +08:00
|
|
|
out <- types.Kind(a)
|
2015-01-20 05:04:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +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",
|
2018-01-30 01:39:41 +08:00
|
|
|
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)
|
2015-01-24 02:22:40 +08:00
|
|
|
}
|
2017-04-11 08:16:43 +08:00
|
|
|
out := ec.ports[1].Chan
|
|
|
|
for _, v := range args {
|
|
|
|
out <- v
|
|
|
|
}
|
|
|
|
},
|
2015-01-24 02:22:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
func source(ec *Frame, args []interface{}, opts map[string]interface{}) {
|
2018-01-25 09:40:15 +08:00
|
|
|
var argFname string
|
2018-01-05 12:07:11 +08:00
|
|
|
ScanArgs(args, &argFname)
|
2017-04-11 08:16:43 +08:00
|
|
|
ScanOpts(opts)
|
|
|
|
|
2018-01-25 09:40:15 +08:00
|
|
|
fname := argFname
|
2018-01-05 12:07:11 +08:00
|
|
|
abs, err := filepath.Abs(fname)
|
|
|
|
maybeThrow(err)
|
|
|
|
|
|
|
|
maybeThrow(ec.Source(fname, abs))
|
2017-04-11 08:16:43 +08:00
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
func sleep(ec *Frame, args []interface{}, opts map[string]interface{}) {
|
2017-04-11 06:24:56 +08:00
|
|
|
var t float64
|
|
|
|
ScanArgs(args, &t)
|
|
|
|
TakeNoOpt(opts)
|
2016-03-29 14:44:17 +08:00
|
|
|
|
2016-02-23 00:39:03 +08:00
|
|
|
d := time.Duration(float64(time.Second) * t)
|
|
|
|
select {
|
2016-10-12 23:11:09 +08:00
|
|
|
case <-ec.Interrupts():
|
2016-02-23 00:39:03 +08:00
|
|
|
throw(ErrInterrupted)
|
|
|
|
case <-time.After(d):
|
|
|
|
}
|
2016-02-10 01:18:18 +08:00
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
func _time(ec *Frame, args []interface{}, opts map[string]interface{}) {
|
2018-01-30 01:46:21 +08:00
|
|
|
var f Callable
|
2017-04-11 08:16:43 +08:00
|
|
|
ScanArgs(args, &f)
|
|
|
|
TakeNoOpt(opts)
|
|
|
|
|
|
|
|
t0 := time.Now()
|
2018-01-21 19:05:36 +08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-01-30 01:39:41 +08:00
|
|
|
func _ifaddrs(ec *Frame, args []interface{}, opts map[string]interface{}) {
|
2017-04-11 06:24:56 +08:00
|
|
|
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 {
|
2018-01-25 09:40:15 +08:00
|
|
|
out <- addr.String()
|
2016-11-06 17:47:20 +08:00
|
|
|
}
|
|
|
|
}
|