mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
eval: ReflectBuiltinFn -> BuiltinFn.
This commit is contained in:
parent
234bcbef26
commit
b7c853151f
|
@ -165,7 +165,7 @@ func makeNs(ed *Editor) eval.Ns {
|
|||
"-narrow-read": NarrowRead,
|
||||
}
|
||||
for name, impl := range fns {
|
||||
ns.SetFn(name, eval.NewReflectBuiltinFn("edit:"+name, impl))
|
||||
ns.SetFn(name, eval.NewBuiltinFn("edit:"+name, impl))
|
||||
}
|
||||
|
||||
submods := make(map[string]eval.Ns)
|
||||
|
|
|
@ -18,11 +18,11 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
matchPrefix = eval.NewReflectBuiltinFn(
|
||||
matchPrefix = eval.NewBuiltinFn(
|
||||
"edit:match-prefix", wrapMatcher(strings.HasPrefix))
|
||||
matchSubstr = eval.NewReflectBuiltinFn(
|
||||
matchSubstr = eval.NewBuiltinFn(
|
||||
"edit:match-substr", wrapMatcher(strings.Contains))
|
||||
matchSubseq = eval.NewReflectBuiltinFn(
|
||||
matchSubseq = eval.NewBuiltinFn(
|
||||
"edit:match-subseq", wrapMatcher(util.HasSubseq))
|
||||
|
||||
_ = RegisterVariable("-matcher", func() vartypes.Variable {
|
||||
|
|
|
@ -43,7 +43,7 @@ func PromptVariable() vartypes.Variable {
|
|||
out <- &ui.Styled{"> ", ui.Styles{}}
|
||||
}
|
||||
}
|
||||
val := eval.Callable(eval.NewReflectBuiltinFn("default prompt", prompt))
|
||||
val := eval.Callable(eval.NewBuiltinFn("default prompt", prompt))
|
||||
return eval.NewVariableFromPtr(&val)
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ func RpromptVariable() vartypes.Variable {
|
|||
out <- &ui.Styled{rpromptStr, ui.Styles{"inverse"}}
|
||||
}
|
||||
|
||||
val := eval.Callable(eval.NewReflectBuiltinFn("default rprompt", rprompt))
|
||||
val := eval.Callable(eval.NewBuiltinFn("default rprompt", rprompt))
|
||||
return eval.NewVariableFromPtr(&val)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,15 +10,15 @@ import (
|
|||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
var reflectBuiltinFns = map[string]interface{}{}
|
||||
var builtinFns = map[string]interface{}{}
|
||||
|
||||
func addToReflectBuiltinFns(moreFns map[string]interface{}) {
|
||||
func addToBuiltinFns(moreFns map[string]interface{}) {
|
||||
for name, impl := range moreFns {
|
||||
reflectBuiltinFns[name] = impl
|
||||
builtinFns[name] = impl
|
||||
}
|
||||
}
|
||||
|
||||
// ReflectBuiltinFn uses reflection to wrap arbitrary Go functions into Elvish
|
||||
// BuiltinFn uses reflection to wrap arbitrary Go functions into Elvish
|
||||
// functions.
|
||||
//
|
||||
// Parameters are passed following these rules:
|
||||
|
@ -41,7 +41,7 @@ func addToReflectBuiltinFns(moreFns map[string]interface{}) {
|
|||
// converted using goToElv. If the last return value has type error and is not
|
||||
// nil, it is turned into an exception and no ouputting happens. If the last
|
||||
// return value is a nil error, it is ignored.
|
||||
type ReflectBuiltinFn struct {
|
||||
type BuiltinFn struct {
|
||||
name string
|
||||
impl interface{}
|
||||
|
||||
|
@ -56,7 +56,7 @@ type ReflectBuiltinFn struct {
|
|||
variadicArg reflect.Type
|
||||
}
|
||||
|
||||
var _ Callable = &ReflectBuiltinFn{}
|
||||
var _ Callable = &BuiltinFn{}
|
||||
|
||||
type (
|
||||
Options map[string]interface{}
|
||||
|
@ -77,10 +77,10 @@ var (
|
|||
inputsType = reflect.TypeOf(Inputs(nil))
|
||||
)
|
||||
|
||||
// NewReflectBuiltinFn creates a new ReflectBuiltinFn instance.
|
||||
func NewReflectBuiltinFn(name string, impl interface{}) *ReflectBuiltinFn {
|
||||
// NewBuiltinFn creates a new ReflectBuiltinFn instance.
|
||||
func NewBuiltinFn(name string, impl interface{}) *BuiltinFn {
|
||||
implType := reflect.TypeOf(impl)
|
||||
b := &ReflectBuiltinFn{name: name, impl: impl}
|
||||
b := &BuiltinFn{name: name, impl: impl}
|
||||
|
||||
i := 0
|
||||
if i < implType.NumIn() && implType.In(i) == frameType {
|
||||
|
@ -108,22 +108,22 @@ func NewReflectBuiltinFn(name string, impl interface{}) *ReflectBuiltinFn {
|
|||
}
|
||||
|
||||
// Kind returns "fn".
|
||||
func (*ReflectBuiltinFn) Kind() string {
|
||||
func (*BuiltinFn) Kind() string {
|
||||
return "fn"
|
||||
}
|
||||
|
||||
// Equal compares identity.
|
||||
func (b *ReflectBuiltinFn) Equal(rhs interface{}) bool {
|
||||
func (b *BuiltinFn) Equal(rhs interface{}) bool {
|
||||
return b == rhs
|
||||
}
|
||||
|
||||
// Hash hashes the address.
|
||||
func (b *ReflectBuiltinFn) Hash() uint32 {
|
||||
func (b *BuiltinFn) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(b))
|
||||
}
|
||||
|
||||
// Repr returns an opaque representation "<builtin $name>".
|
||||
func (b *ReflectBuiltinFn) Repr(int) string {
|
||||
func (b *BuiltinFn) Repr(int) string {
|
||||
return "<builtin " + b.name + ">"
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|||
var errNoOptions = errors.New("function does not accept any options")
|
||||
|
||||
// Call calls the implementation using reflection.
|
||||
func (b *ReflectBuiltinFn) Call(f *Frame, args []interface{}, opts map[string]interface{}) error {
|
||||
func (b *BuiltinFn) Call(f *Frame, args []interface{}, opts map[string]interface{}) error {
|
||||
if b.variadicArg != nil {
|
||||
if len(args) < len(b.normalArgs) {
|
||||
return fmt.Errorf("want %d or more arguments, got %d",
|
|
@ -12,7 +12,7 @@ import (
|
|||
var ErrNotInSameGroup = errors.New("not in the same process group")
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
// Command resolution
|
||||
"external": external,
|
||||
"has-external": hasExternal,
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
// Sequence, list and maps.
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"ns": nsFn,
|
||||
|
||||
"range": rangeFn,
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"src": src,
|
||||
"-gc": _gc,
|
||||
"-stack": _stack,
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
// Flow control.
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"run-parallel": runParallel,
|
||||
// Exception and control
|
||||
"fail": fail,
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
var ErrStoreNotConnected = errors.New("store not connected")
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
// Directory
|
||||
"cd": cd,
|
||||
"dir-history": dirs,
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
// Input and output.
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
// Value output
|
||||
"put": put,
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
var ErrArgs = errors.New("args error")
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"nop": nop,
|
||||
"kind-of": kindOf,
|
||||
"constantly": constantly,
|
||||
|
@ -49,7 +49,7 @@ func kindOf(fm *Frame, args ...interface{}) {
|
|||
|
||||
func constantly(args ...interface{}) Callable {
|
||||
// XXX Repr of this fn is not right
|
||||
return NewReflectBuiltinFn(
|
||||
return NewBuiltinFn(
|
||||
"created by constantly",
|
||||
func(fm *Frame) {
|
||||
out := fm.ports[1].Chan
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
// Numerical operations.
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
// Comparison
|
||||
"<": func(a, b float64) bool { return a < b },
|
||||
"<=": func(a, b float64) bool { return a <= b },
|
||||
|
|
|
@ -5,7 +5,7 @@ import "github.com/elves/elvish/eval/types"
|
|||
// Basic predicate commands.
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"bool": types.Bool,
|
||||
"not": not,
|
||||
"is": is,
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
var ErrInput = errors.New("input error")
|
||||
|
||||
func init() {
|
||||
addToReflectBuiltinFns(map[string]interface{}{
|
||||
addToBuiltinFns(map[string]interface{}{
|
||||
"<s": func(a, b string) bool { return a < b },
|
||||
"<=s": func(a, b string) bool { return a <= b },
|
||||
"==s": func(a, b string) bool { return a == b },
|
||||
|
|
|
@ -1,25 +1,195 @@
|
|||
package eval
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
var builtinFnTests = []Test{
|
||||
NewTest("kind-of $nop~").WantOutStrings("fn"),
|
||||
NewTest("eq $nop~ { }").WantOutBools(false),
|
||||
NewTest("put [&$nop~= foo][$nop~]").WantOutStrings("foo"),
|
||||
NewTest("repr $nop~").WantBytesOutString("<builtin nop>\n"),
|
||||
"github.com/elves/elvish/eval/types"
|
||||
)
|
||||
|
||||
{"nop", wantNothing},
|
||||
{"nop a b", wantNothing},
|
||||
{"nop &k=v", wantNothing},
|
||||
{"nop a b &k=v", wantNothing},
|
||||
func TestReflectBuiltinFnCall(t *testing.T) {
|
||||
theFrame := new(Frame)
|
||||
theOptions := map[string]interface{}{}
|
||||
|
||||
{"kind-of bare 'str' [] [&] []{ }",
|
||||
want{out: strs("string", "string", "list", "map", "fn")}},
|
||||
var f Callable
|
||||
callGood := func(fm *Frame, args []interface{}, opts map[string]interface{}) {
|
||||
err := f.Call(fm, args, opts)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to call f: %v", err)
|
||||
}
|
||||
}
|
||||
callBad := func(fm *Frame, args []interface{}, opts map[string]interface{}) {
|
||||
err := f.Call(fm, args, opts)
|
||||
if err == nil {
|
||||
t.Errorf("Calling f didn't return error")
|
||||
}
|
||||
}
|
||||
|
||||
{`f=(constantly foo); $f; $f`, want{out: strs("foo", "foo")}},
|
||||
{`(constantly foo) bad`, want{err: errAny}},
|
||||
}
|
||||
|
||||
func TestBuiltinFn(t *testing.T) {
|
||||
runTests(t, builtinFnTests)
|
||||
// *Frame parameter gets the Frame.
|
||||
f = NewBuiltinFn("f", func(f *Frame) {
|
||||
if f != theFrame {
|
||||
t.Errorf("*Frame parameter doesn't get current frame")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, theOptions)
|
||||
|
||||
// Options parameter gets options.
|
||||
f = NewBuiltinFn("f", func(opts Options) {
|
||||
if opts["foo"] != "bar" {
|
||||
t.Errorf("Options parameter doesn't get options")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Combination of Frame and Options.
|
||||
f = NewBuiltinFn("f", func(f *Frame, opts Options) {
|
||||
if f != theFrame {
|
||||
t.Errorf("*Frame parameter doesn't get current frame")
|
||||
}
|
||||
if opts["foo"] != "bar" {
|
||||
t.Errorf("Options parameter doesn't get options")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Argument passing.
|
||||
f = NewBuiltinFn("f", func(x, y string) {
|
||||
if x != "lorem" {
|
||||
t.Errorf("Argument x not passed")
|
||||
}
|
||||
if y != "ipsum" {
|
||||
t.Errorf("Argument y not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"lorem", "ipsum"}, theOptions)
|
||||
|
||||
// Variadic arguments.
|
||||
f = NewBuiltinFn("f", func(x ...string) {
|
||||
if len(x) != 2 || x[0] != "lorem" || x[1] != "ipsum" {
|
||||
t.Errorf("Variadic argument not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"lorem", "ipsum"}, theOptions)
|
||||
|
||||
// Conversion into int and float64.
|
||||
f = NewBuiltinFn("f", func(i int, f float64) {
|
||||
if i != 314 {
|
||||
t.Errorf("Integer argument i not passed")
|
||||
}
|
||||
if f != 1.25 {
|
||||
t.Errorf("Float argument f not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"314", "1.25"}, theOptions)
|
||||
|
||||
// Conversion of supplied inputs.
|
||||
f = NewBuiltinFn("f", func(i Inputs) {
|
||||
var values []interface{}
|
||||
i(func(x interface{}) {
|
||||
values = append(values, x)
|
||||
})
|
||||
if len(values) != 2 || values[0] != "foo" || values[1] != "bar" {
|
||||
t.Errorf("Inputs parameter didn't get supplied inputs")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{types.MakeList("foo", "bar")}, theOptions)
|
||||
|
||||
// Conversion of implicit inputs.
|
||||
inFrame := &Frame{ports: make([]*Port, 3)}
|
||||
ch := make(chan interface{}, 10)
|
||||
ch <- "foo"
|
||||
ch <- "bar"
|
||||
close(ch)
|
||||
inFrame.ports[0] = &Port{Chan: ch}
|
||||
f = NewBuiltinFn("f", func(i Inputs) {
|
||||
var values []interface{}
|
||||
i(func(x interface{}) {
|
||||
values = append(values, x)
|
||||
})
|
||||
if len(values) != 2 || values[0] != "foo" || values[1] != "bar" {
|
||||
t.Errorf("Inputs parameter didn't get implicit inputs")
|
||||
}
|
||||
})
|
||||
callGood(inFrame, []interface{}{types.MakeList("foo", "bar")}, theOptions)
|
||||
|
||||
// Outputting of return values.
|
||||
outFrame := &Frame{ports: make([]*Port, 3)}
|
||||
ch = make(chan interface{}, 10)
|
||||
outFrame.ports[1] = &Port{Chan: ch}
|
||||
f = NewBuiltinFn("f", func() string { return "ret" })
|
||||
callGood(outFrame, nil, theOptions)
|
||||
select {
|
||||
case ret := <-ch:
|
||||
if ret != "ret" {
|
||||
t.Errorf("Output is not the same as return value")
|
||||
}
|
||||
default:
|
||||
t.Errorf("Return value is not outputted")
|
||||
}
|
||||
|
||||
// Conversion of return values.
|
||||
f = NewBuiltinFn("f", func() int { return 314 })
|
||||
callGood(outFrame, nil, theOptions)
|
||||
select {
|
||||
case ret := <-ch:
|
||||
if ret != "314" {
|
||||
t.Errorf("Return value is not converted to string")
|
||||
}
|
||||
default:
|
||||
t.Errorf("Return value is not outputted")
|
||||
}
|
||||
|
||||
// Passing of error return value.
|
||||
theError := errors.New("the error")
|
||||
f = NewBuiltinFn("f", func() (string, error) {
|
||||
return "x", theError
|
||||
})
|
||||
if f.Call(outFrame, nil, theOptions) != theError {
|
||||
t.Errorf("Returned error is not passed")
|
||||
}
|
||||
select {
|
||||
case <-ch:
|
||||
t.Errorf("Return value is outputted when error is not nil")
|
||||
default:
|
||||
}
|
||||
|
||||
// Too many arguments.
|
||||
f = NewBuiltinFn("f", func() {
|
||||
t.Errorf("Function called when there are too many arguments")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
|
||||
// Too few arguments.
|
||||
f = NewBuiltinFn("f", func(x string) {
|
||||
t.Errorf("Function called when there are too few arguments")
|
||||
})
|
||||
callBad(theFrame, nil, theOptions)
|
||||
f = NewBuiltinFn("f", func(x string, y ...string) {
|
||||
t.Errorf("Function called when there are too few arguments")
|
||||
})
|
||||
callBad(theFrame, nil, theOptions)
|
||||
|
||||
// Options when the function does not accept options.
|
||||
f = NewBuiltinFn("f", func() {
|
||||
t.Errorf("Function called when there are extra options")
|
||||
})
|
||||
callBad(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Wrong argument type.
|
||||
f = NewBuiltinFn("f", func(x string) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{1}, theOptions)
|
||||
|
||||
// Wrong argument type: cannot convert to int.
|
||||
f = NewBuiltinFn("f", func(x int) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
|
||||
// Wrong argument type: cannot convert to float64.
|
||||
f = NewBuiltinFn("f", func(x float64) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ func makeBuiltinNs() Ns {
|
|||
"paths": &EnvList{envName: "PATH"},
|
||||
"pwd": PwdVariable{},
|
||||
}
|
||||
AddReflectBuiltinFns(ns, "", reflectBuiltinFns)
|
||||
AddReflectBuiltinFns(ns, "", builtinFns)
|
||||
return ns
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,6 @@ func AddReflectBuiltinFns(ns Ns, nsName string, fns map[string]interface{}) {
|
|||
if nsName != "" {
|
||||
qname = nsName + ":" + name
|
||||
}
|
||||
ns.SetFn(name, NewReflectBuiltinFn(qname, impl))
|
||||
ns.SetFn(name, NewBuiltinFn(qname, impl))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ func (op fnOp) Invoke(fm *Frame) error {
|
|||
// Initialize the function variable with the builtin nop function. This step
|
||||
// allows the definition of recursive functions; the actual function will
|
||||
// never be called.
|
||||
fm.local[op.varName] = vartypes.NewAny(NewReflectBuiltinFn("<shouldn't be called>", nop))
|
||||
fm.local[op.varName] = vartypes.NewAny(NewBuiltinFn("<shouldn't be called>", nop))
|
||||
values, err := op.lambdaOp.Invoke(fm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -42,6 +42,6 @@ func Ns(daemon *daemon.Client, spawner *daemonp.Daemon) eval.Ns {
|
|||
"sock": vartypes.NewRo(string(daemon.SockPath())),
|
||||
|
||||
"spawn" + eval.FnSuffix: vartypes.NewRo(
|
||||
eval.NewReflectBuiltinFn("daemon:spawn", daemonSpawn)),
|
||||
eval.NewBuiltinFn("daemon:spawn", daemonSpawn)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,195 +0,0 @@
|
|||
package eval
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/elves/elvish/eval/types"
|
||||
)
|
||||
|
||||
func TestReflectBuiltinFnCall(t *testing.T) {
|
||||
theFrame := new(Frame)
|
||||
theOptions := map[string]interface{}{}
|
||||
|
||||
var f Callable
|
||||
callGood := func(fm *Frame, args []interface{}, opts map[string]interface{}) {
|
||||
err := f.Call(fm, args, opts)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to call f: %v", err)
|
||||
}
|
||||
}
|
||||
callBad := func(fm *Frame, args []interface{}, opts map[string]interface{}) {
|
||||
err := f.Call(fm, args, opts)
|
||||
if err == nil {
|
||||
t.Errorf("Calling f didn't return error")
|
||||
}
|
||||
}
|
||||
|
||||
// *Frame parameter gets the Frame.
|
||||
f = NewReflectBuiltinFn("f", func(f *Frame) {
|
||||
if f != theFrame {
|
||||
t.Errorf("*Frame parameter doesn't get current frame")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, theOptions)
|
||||
|
||||
// Options parameter gets options.
|
||||
f = NewReflectBuiltinFn("f", func(opts Options) {
|
||||
if opts["foo"] != "bar" {
|
||||
t.Errorf("Options parameter doesn't get options")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Combination of Frame and Options.
|
||||
f = NewReflectBuiltinFn("f", func(f *Frame, opts Options) {
|
||||
if f != theFrame {
|
||||
t.Errorf("*Frame parameter doesn't get current frame")
|
||||
}
|
||||
if opts["foo"] != "bar" {
|
||||
t.Errorf("Options parameter doesn't get options")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Argument passing.
|
||||
f = NewReflectBuiltinFn("f", func(x, y string) {
|
||||
if x != "lorem" {
|
||||
t.Errorf("Argument x not passed")
|
||||
}
|
||||
if y != "ipsum" {
|
||||
t.Errorf("Argument y not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"lorem", "ipsum"}, theOptions)
|
||||
|
||||
// Variadic arguments.
|
||||
f = NewReflectBuiltinFn("f", func(x ...string) {
|
||||
if len(x) != 2 || x[0] != "lorem" || x[1] != "ipsum" {
|
||||
t.Errorf("Variadic argument not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"lorem", "ipsum"}, theOptions)
|
||||
|
||||
// Conversion into int and float64.
|
||||
f = NewReflectBuiltinFn("f", func(i int, f float64) {
|
||||
if i != 314 {
|
||||
t.Errorf("Integer argument i not passed")
|
||||
}
|
||||
if f != 1.25 {
|
||||
t.Errorf("Float argument f not passed")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{"314", "1.25"}, theOptions)
|
||||
|
||||
// Conversion of supplied inputs.
|
||||
f = NewReflectBuiltinFn("f", func(i Inputs) {
|
||||
var values []interface{}
|
||||
i(func(x interface{}) {
|
||||
values = append(values, x)
|
||||
})
|
||||
if len(values) != 2 || values[0] != "foo" || values[1] != "bar" {
|
||||
t.Errorf("Inputs parameter didn't get supplied inputs")
|
||||
}
|
||||
})
|
||||
callGood(theFrame, []interface{}{types.MakeList("foo", "bar")}, theOptions)
|
||||
|
||||
// Conversion of implicit inputs.
|
||||
inFrame := &Frame{ports: make([]*Port, 3)}
|
||||
ch := make(chan interface{}, 10)
|
||||
ch <- "foo"
|
||||
ch <- "bar"
|
||||
close(ch)
|
||||
inFrame.ports[0] = &Port{Chan: ch}
|
||||
f = NewReflectBuiltinFn("f", func(i Inputs) {
|
||||
var values []interface{}
|
||||
i(func(x interface{}) {
|
||||
values = append(values, x)
|
||||
})
|
||||
if len(values) != 2 || values[0] != "foo" || values[1] != "bar" {
|
||||
t.Errorf("Inputs parameter didn't get implicit inputs")
|
||||
}
|
||||
})
|
||||
callGood(inFrame, []interface{}{types.MakeList("foo", "bar")}, theOptions)
|
||||
|
||||
// Outputting of return values.
|
||||
outFrame := &Frame{ports: make([]*Port, 3)}
|
||||
ch = make(chan interface{}, 10)
|
||||
outFrame.ports[1] = &Port{Chan: ch}
|
||||
f = NewReflectBuiltinFn("f", func() string { return "ret" })
|
||||
callGood(outFrame, nil, theOptions)
|
||||
select {
|
||||
case ret := <-ch:
|
||||
if ret != "ret" {
|
||||
t.Errorf("Output is not the same as return value")
|
||||
}
|
||||
default:
|
||||
t.Errorf("Return value is not outputted")
|
||||
}
|
||||
|
||||
// Conversion of return values.
|
||||
f = NewReflectBuiltinFn("f", func() int { return 314 })
|
||||
callGood(outFrame, nil, theOptions)
|
||||
select {
|
||||
case ret := <-ch:
|
||||
if ret != "314" {
|
||||
t.Errorf("Return value is not converted to string")
|
||||
}
|
||||
default:
|
||||
t.Errorf("Return value is not outputted")
|
||||
}
|
||||
|
||||
// Passing of error return value.
|
||||
theError := errors.New("the error")
|
||||
f = NewReflectBuiltinFn("f", func() (string, error) {
|
||||
return "x", theError
|
||||
})
|
||||
if f.Call(outFrame, nil, theOptions) != theError {
|
||||
t.Errorf("Returned error is not passed")
|
||||
}
|
||||
select {
|
||||
case <-ch:
|
||||
t.Errorf("Return value is outputted when error is not nil")
|
||||
default:
|
||||
}
|
||||
|
||||
// Too many arguments.
|
||||
f = NewReflectBuiltinFn("f", func() {
|
||||
t.Errorf("Function called when there are too many arguments")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
|
||||
// Too few arguments.
|
||||
f = NewReflectBuiltinFn("f", func(x string) {
|
||||
t.Errorf("Function called when there are too few arguments")
|
||||
})
|
||||
callBad(theFrame, nil, theOptions)
|
||||
f = NewReflectBuiltinFn("f", func(x string, y ...string) {
|
||||
t.Errorf("Function called when there are too few arguments")
|
||||
})
|
||||
callBad(theFrame, nil, theOptions)
|
||||
|
||||
// Options when the function does not accept options.
|
||||
f = NewReflectBuiltinFn("f", func() {
|
||||
t.Errorf("Function called when there are extra options")
|
||||
})
|
||||
callBad(theFrame, nil, Options{"foo": "bar"})
|
||||
|
||||
// Wrong argument type.
|
||||
f = NewReflectBuiltinFn("f", func(x string) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{1}, theOptions)
|
||||
|
||||
// Wrong argument type: cannot convert to int.
|
||||
f = NewReflectBuiltinFn("f", func(x int) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
|
||||
// Wrong argument type: cannot convert to float64.
|
||||
f = NewReflectBuiltinFn("f", func(x float64) {
|
||||
t.Errorf("Function called when arguments have wrong type")
|
||||
})
|
||||
callBad(theFrame, []interface{}{"x"}, theOptions)
|
||||
}
|
|
@ -12,7 +12,7 @@ import (
|
|||
func Ns() eval.Ns {
|
||||
ns := eval.Ns{}
|
||||
for name, impl := range fns {
|
||||
ns[name+eval.FnSuffix] = vartypes.NewRo(eval.NewReflectBuiltinFn("str:"+name, impl))
|
||||
ns[name+eval.FnSuffix] = vartypes.NewRo(eval.NewBuiltinFn("str:"+name, impl))
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user