Skip to content

Commit 7518d8a

Browse files
authored
auto: Add FromFunc and Support for Function Arguments (#139)
* auto: Rework rules for passing some values. * auto: Add support for function arguments. * auto: Add a test of `Func()` using a `stream.Stream`. * wdte: Update some dependencies. * auto: Export `fromFunc()` as `FromFunc()`.
1 parent 5193e32 commit 7518d8a

File tree

5 files changed

+105
-37
lines changed

5 files changed

+105
-37
lines changed

auto/auto.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ var (
1414
stringType = reflect.TypeOf(wdte.String(""))
1515
)
1616

17-
func fromWDTE(w wdte.Func, expected reflect.Type) reflect.Value {
17+
func fromWDTE(frame wdte.Frame, w wdte.Func, expected reflect.Type) reflect.Value {
1818
v := reflect.ValueOf(w)
19+
if v.Type() == expected {
20+
return v
21+
}
1922

2023
switch expected.Kind() {
21-
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
22-
return v.Convert(expected)
23-
2424
case reflect.Array:
2525
v := v.Convert(arrayType).Interface().(wdte.Array)
2626
if len(v) != expected.Len() {
@@ -30,12 +30,12 @@ func fromWDTE(w wdte.Func, expected reflect.Type) reflect.Value {
3030
t := reflect.ArrayOf(expected.Len(), expected.Elem())
3131
r := reflect.New(t).Elem()
3232
for i := 0; i < r.Len(); i++ {
33-
r.Index(i).Set(fromWDTE(v[i], expected.Elem()))
33+
r.Index(i).Set(fromWDTE(frame, v[i], expected.Elem()))
3434
}
3535
return r
3636

3737
case reflect.Func:
38-
panic(errors.New("func arguments are not yet supported"))
38+
return FromFunc(frame, w, expected)
3939

4040
case reflect.Map:
4141
panic(errors.New("map arguments are not yet supported"))
@@ -46,18 +46,19 @@ func fromWDTE(w wdte.Func, expected reflect.Type) reflect.Value {
4646
t := reflect.SliceOf(expected.Elem())
4747
r := reflect.MakeSlice(t, 0, len(v))
4848
for _, e := range v {
49-
r = reflect.Append(r, fromWDTE(e, expected.Elem()))
49+
r = reflect.Append(r, fromWDTE(frame, e, expected.Elem()))
5050
}
5151
return r
52-
53-
case reflect.Struct:
54-
panic(errors.New("struct arguments are not yet supported"))
5552
}
5653

57-
panic(fmt.Errorf("unsupported type: %v", expected))
54+
return v.Convert(expected)
5855
}
5956

6057
func toWDTE(v reflect.Value) wdte.Func {
58+
if v, ok := v.Interface().(wdte.Func); ok {
59+
return v
60+
}
61+
6162
switch v.Kind() {
6263
case reflect.Bool:
6364
return wdte.Bool(v.Bool())

auto/func.go

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,25 @@ import (
1515
// function.
1616
//
1717
// Note that currently this is limited to functions that have a single
18-
// return value, and not all types are supported. Currently supported
19-
// types are as follows:
18+
// return value.
19+
//
20+
// Unrecognized types are passed through with an attempted conversion,
21+
// allowing a function to, for example, take a stream.Stream as an
22+
// argument. Similarly, if an expected type of an argument is the
23+
// exact type of the value passed, the value is passed through
24+
// directly. If a return value's type implements wdte.Func, it is also
25+
// passed directly. Types with special handling are as follows:
2026
//
2127
// Arguments:
22-
// * Any number type, including uintptrs.
23-
// * Arrays and slices of supported types. Note that the passed WDTE
24-
// array's length must match the expected length of the array in the
25-
// Go function's arguments.
26-
// * Booleans.
27-
// * Strings.
28+
// * Arrays and slices. Note that the passed WDTE array's length
29+
// must match the expected length of the array in the Go
30+
// function's arguments.
2831
//
2932
// Return types:
30-
// * Any number type, including uintptrs.
31-
// * Arrays and slices of supported types.
32-
// * Booleans.
33-
// * Strings.
34-
// * Pointers to supported types.
35-
// * Functions that are supported by this function. The functions will
36-
// use a frame with the name "<auto>".
33+
// * Arrays and slices.
34+
// * Pointers.
35+
// * Functions that are supported by this function. The functions
36+
// will use a frame with the name "<auto>".
3737
func Func(name string, f interface{}) wdte.Func {
3838
v := reflect.ValueOf(f)
3939

@@ -57,7 +57,7 @@ func Func(name string, f interface{}) wdte.Func {
5757

5858
in := make([]reflect.Value, t.NumIn())
5959
for i := range in {
60-
in[i] = fromWDTE(args[i].Call(frame), t.In(i))
60+
in[i] = fromWDTE(frame, args[i].Call(frame), t.In(i))
6161
}
6262

6363
out := v.Call(in)
@@ -66,3 +66,33 @@ func Func(name string, f interface{}) wdte.Func {
6666
})
6767
return r
6868
}
69+
70+
// FromFunc does the opposite of Func, returning a Go function with
71+
// the signature given by expected that, when called, calls w with
72+
// frame. Type conversions are handled the same as in Func, but in
73+
// reverse, such that the return type stipulations in Func apply to
74+
// the arguments to w, and vice versa for the return value of w. The
75+
// requested function type must return exactly zero or one values.
76+
func FromFunc(frame wdte.Frame, w wdte.Func, expected reflect.Type) reflect.Value {
77+
if expected.Kind() != reflect.Func {
78+
panic(errors.New("expected is not a function type"))
79+
}
80+
if expected.NumOut() > 1 {
81+
panic(fmt.Errorf("invalid number of returns: %v", expected.NumOut()))
82+
}
83+
84+
return reflect.MakeFunc(expected, func(args []reflect.Value) []reflect.Value {
85+
wargs := make([]wdte.Func, 0, len(args))
86+
for _, arg := range args {
87+
wargs = append(wargs, toWDTE(arg))
88+
}
89+
90+
fmt.Println(w)
91+
r := w.Call(frame, wargs...)
92+
if expected.NumOut() == 0 {
93+
// TODO: Should zero return values be allowed?
94+
return nil
95+
}
96+
return []reflect.Value{fromWDTE(frame, r, expected.Out(0))}
97+
})
98+
}

auto/func_test.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@ import (
77

88
"github.com/DeedleFake/wdte"
99
"github.com/DeedleFake/wdte/auto"
10+
"github.com/DeedleFake/wdte/std/stream"
1011
)
1112

13+
func testFunc(frame wdte.Frame, args ...wdte.Func) wdte.Func {
14+
if len(args) == 0 {
15+
return wdte.GoFunc(testFunc)
16+
}
17+
18+
return args[0].(wdte.Number) + 1
19+
}
20+
1221
func TestFunc(t *testing.T) {
1322
tests := []struct {
1423
name string
@@ -49,15 +58,43 @@ func TestFunc(t *testing.T) {
4958
},
5059
{
5160
name: "Func",
52-
f: func(v int) func() int {
61+
f: func(f func(v int) int) func() int {
62+
var v int
5363
return func() int {
54-
v++
55-
return v - 1
64+
p := v
65+
v = f(v)
66+
return p
5667
}
5768
},
58-
args: []wdte.Func{wdte.Number(0)},
69+
args: []wdte.Func{wdte.GoFunc(testFunc)},
5970
calls: []wdte.Func{wdte.Number(0), wdte.Number(1), wdte.Number(2)},
6071
},
72+
{
73+
name: "Direct",
74+
f: func(a wdte.Array) wdte.String {
75+
return wdte.String(fmt.Sprint(a))
76+
},
77+
args: []wdte.Func{wdte.Array{wdte.String("a"), wdte.String("test")}},
78+
ret: wdte.String("[a; test]"),
79+
},
80+
{
81+
name: "Bool",
82+
f: func(v bool) bool {
83+
return !v
84+
},
85+
args: []wdte.Func{wdte.Bool(false)},
86+
ret: wdte.Bool(true),
87+
},
88+
{
89+
name: "Stream",
90+
f: func(s stream.Stream) int {
91+
s.Next(wdte.F())
92+
v, _ := s.Next(wdte.F())
93+
return int(v.(wdte.Number))
94+
},
95+
args: []wdte.Func{stream.Range(wdte.F(), wdte.Number(10))},
96+
ret: wdte.Number(1),
97+
},
6198
}
6299

63100
for _, test := range tests {

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ module github.com/DeedleFake/wdte
22

33
require (
44
github.com/peterh/liner v1.1.0
5-
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a
6-
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746 // indirect
5+
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774
6+
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2 // indirect
77
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8Bz
22
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
33
github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os=
44
github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
5-
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a h1:Pg1/+l4/QV6z7N506eGnLiJ/Rl4IJf1FwYQKvP51OjA=
6-
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
7-
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746 h1:zTiiIq2XH/ldZGPA59ILL7NbDlz/btn3iJvO7H57mY8=
8-
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5+
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774 h1:a4tQYYYuK9QdeO/+kEvNYyuR21S+7ve5EANok6hABhI=
6+
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
7+
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2 h1:W7CqTdBJ1CmxLKe7LptKDnBYV6PHrVLiGnoyBjaG/JQ=
8+
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

0 commit comments

Comments
 (0)