Skip to content

Commit aa52e70

Browse files
committed
Fix type checker for filter builtin
1 parent d7ffa9a commit aa52e70

File tree

4 files changed

+34
-12
lines changed

4 files changed

+34
-12
lines changed

checker/checker.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func (v *visitor) checkFunc(fn reflect.Type, method bool, node ast.Node, name st
423423
continue
424424
}
425425

426-
if !t.AssignableTo(in) {
426+
if !t.AssignableTo(in) && t.Kind() != reflect.Interface {
427427
return v.error(arg, "cannot use %v as argument (type %v) to call %v ", t, in, name)
428428
}
429429
}
@@ -479,7 +479,10 @@ func (v *visitor) BuiltinNode(node *ast.BuiltinNode) reflect.Type {
479479
if !isBool(closure.Out(0)) {
480480
return v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String())
481481
}
482-
return arrayType
482+
if isInterface(collection) {
483+
return arrayType
484+
}
485+
return reflect.SliceOf(collection.Elem())
483486
}
484487
return v.error(node.Arguments[1], "closure should has one input and one output param")
485488

checker/checker_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ func TestCheck(t *testing.T) {
159159
"Foo.Variadic('', 1, 2) + Foo.Variadic('')",
160160
"count(1..30, {# % 3 == 0}) > 0",
161161
"map(1..3, {#}) == [1,2,3]",
162+
"map(filter(ArrayOfFoo, {.Int64 > 0}), {.Bar})",
162163
}
163164
for _, test := range typeTests {
164165
var err error
@@ -466,6 +467,11 @@ map(1, {2})
466467
builtin map takes only array (got int) (1:5)
467468
| map(1, {2})
468469
| ....^
470+
471+
map(filter(ArrayOfFoo, {.Int64 > 0}), {.Var})
472+
type *checker_test.foo has no field Var (1:41)
473+
| map(filter(ArrayOfFoo, {.Int64 > 0}), {.Var})
474+
| ........................................^
469475
`
470476

471477
func TestCheck_error(t *testing.T) {

docs/Getting-Started.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,9 @@ type Tweet struct {
9090
}
9191

9292
func main() {
93-
code := `all(Tweets, {len(.Text) > 0}) ? map(Tweets, {.Text + Format(.Date)}) : nil`
93+
code := `map(filter(Tweets, {len(.Text) > 0}), {.Text + Format(.Date)})`
9494

9595
// We can use an empty instance of the struct as an environment.
96-
9796
program, err := expr.Compile(code, expr.Env(Env{}))
9897
if err != nil {
9998
panic(err)

expr_test.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ func TestExpr_readme_example(t *testing.T) {
472472
}
473473

474474
func TestExpr(t *testing.T) {
475+
date := time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC)
475476
env := &mockEnv{
476477
Any: "any",
477478
Int: 0,
@@ -492,7 +493,7 @@ func TestExpr(t *testing.T) {
492493
{Origin: "MOW", Destination: "LED"},
493494
{Origin: "LED", Destination: "MOW"},
494495
},
495-
BirthDay: time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC),
496+
BirthDay: date,
496497
Now: time.Now(),
497498
One: 1,
498499
Two: 2,
@@ -505,8 +506,9 @@ func TestExpr(t *testing.T) {
505506
}
506507
return ret
507508
},
508-
Inc: func(a int) int { return a + 1 },
509-
Nil: nil,
509+
Inc: func(a int) int { return a + 1 },
510+
Nil: nil,
511+
Tweets: []tweet{{"Oh My God!", date}, {"How you doin?", date}, {"Could I be wearing any more clothes?", date}},
510512
}
511513

512514
tests := []struct {
@@ -849,31 +851,35 @@ func TestExpr(t *testing.T) {
849851
`Float(0)`,
850852
float64(0),
851853
},
854+
{
855+
`map(filter(Tweets, {len(.Text) > 10}), {Format(.Date)})`,
856+
[]interface{}{"23 Oct 17 18:30 UTC", "23 Oct 17 18:30 UTC"},
857+
},
852858
}
853859

854860
for _, tt := range tests {
855861
program, err := expr.Compile(tt.code, expr.Env(&mockEnv{}))
856-
require.NoError(t, err, tt.code)
862+
require.NoError(t, err, "compile error")
857863

858864
got, err := expr.Run(program, env)
859-
require.NoError(t, err, tt.code)
865+
require.NoError(t, err, "execution error")
860866

861867
assert.Equal(t, tt.want, got, tt.code)
862868
}
863869

864870
for _, tt := range tests {
865871
program, err := expr.Compile(tt.code, expr.Optimize(false))
866-
require.NoError(t, err, tt.code)
872+
require.NoError(t, err, "compile error")
867873

868874
got, err := expr.Run(program, env)
869-
require.NoError(t, err, tt.code)
875+
require.NoError(t, err, "execution error")
870876

871877
assert.Equal(t, tt.want, got, "unoptimized: "+tt.code)
872878
}
873879

874880
for _, tt := range tests {
875881
got, err := expr.Eval(tt.code, env)
876-
require.NoError(t, err, tt.code)
882+
require.NoError(t, err, "eval error")
877883

878884
assert.Equal(t, tt.want, got, "eval: "+tt.code)
879885
}
@@ -1079,6 +1085,7 @@ type mockEnv struct {
10791085
NilStruct *time.Time
10801086
NilInt *int
10811087
NilSlice []ticket
1088+
Tweets []tweet
10821089
}
10831090

10841091
func (e *mockEnv) GetInt() int {
@@ -1144,6 +1151,8 @@ func (*mockEnv) Float(i interface{}) float64 {
11441151
}
11451152
}
11461153

1154+
func (*mockEnv) Format(t time.Time) string { return t.Format(time.RFC822) }
1155+
11471156
type ticket struct {
11481157
Price int
11491158
}
@@ -1168,6 +1177,11 @@ type segment struct {
11681177
Date time.Time
11691178
}
11701179

1180+
type tweet struct {
1181+
Text string
1182+
Date time.Time
1183+
}
1184+
11711185
type mockMapStringStringEnv map[string]string
11721186

11731187
func (m mockMapStringStringEnv) Split(s, sep string) []string {

0 commit comments

Comments
 (0)