Skip to content

Commit

Permalink
Fix type checker for filter builtin
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Mar 26, 2020
1 parent d7ffa9a commit aa52e70
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 12 deletions.
7 changes: 5 additions & 2 deletions checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (v *visitor) checkFunc(fn reflect.Type, method bool, node ast.Node, name st
continue
}

if !t.AssignableTo(in) {
if !t.AssignableTo(in) && t.Kind() != reflect.Interface {
return v.error(arg, "cannot use %v as argument (type %v) to call %v ", t, in, name)
}
}
Expand Down Expand Up @@ -479,7 +479,10 @@ func (v *visitor) BuiltinNode(node *ast.BuiltinNode) reflect.Type {
if !isBool(closure.Out(0)) {
return v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String())
}
return arrayType
if isInterface(collection) {
return arrayType
}
return reflect.SliceOf(collection.Elem())
}
return v.error(node.Arguments[1], "closure should has one input and one output param")

Expand Down
6 changes: 6 additions & 0 deletions checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func TestCheck(t *testing.T) {
"Foo.Variadic('', 1, 2) + Foo.Variadic('')",
"count(1..30, {# % 3 == 0}) > 0",
"map(1..3, {#}) == [1,2,3]",
"map(filter(ArrayOfFoo, {.Int64 > 0}), {.Bar})",
}
for _, test := range typeTests {
var err error
Expand Down Expand Up @@ -466,6 +467,11 @@ map(1, {2})
builtin map takes only array (got int) (1:5)
| map(1, {2})
| ....^
map(filter(ArrayOfFoo, {.Int64 > 0}), {.Var})
type *checker_test.foo has no field Var (1:41)
| map(filter(ArrayOfFoo, {.Int64 > 0}), {.Var})
| ........................................^
`

func TestCheck_error(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions docs/Getting-Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ type Tweet struct {
}

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

// We can use an empty instance of the struct as an environment.

program, err := expr.Compile(code, expr.Env(Env{}))
if err != nil {
panic(err)
Expand Down
30 changes: 22 additions & 8 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ func TestExpr_readme_example(t *testing.T) {
}

func TestExpr(t *testing.T) {
date := time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC)
env := &mockEnv{
Any: "any",
Int: 0,
Expand All @@ -492,7 +493,7 @@ func TestExpr(t *testing.T) {
{Origin: "MOW", Destination: "LED"},
{Origin: "LED", Destination: "MOW"},
},
BirthDay: time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC),
BirthDay: date,
Now: time.Now(),
One: 1,
Two: 2,
Expand All @@ -505,8 +506,9 @@ func TestExpr(t *testing.T) {
}
return ret
},
Inc: func(a int) int { return a + 1 },
Nil: nil,
Inc: func(a int) int { return a + 1 },
Nil: nil,
Tweets: []tweet{{"Oh My God!", date}, {"How you doin?", date}, {"Could I be wearing any more clothes?", date}},
}

tests := []struct {
Expand Down Expand Up @@ -849,31 +851,35 @@ func TestExpr(t *testing.T) {
`Float(0)`,
float64(0),
},
{
`map(filter(Tweets, {len(.Text) > 10}), {Format(.Date)})`,
[]interface{}{"23 Oct 17 18:30 UTC", "23 Oct 17 18:30 UTC"},
},
}

for _, tt := range tests {
program, err := expr.Compile(tt.code, expr.Env(&mockEnv{}))
require.NoError(t, err, tt.code)
require.NoError(t, err, "compile error")

got, err := expr.Run(program, env)
require.NoError(t, err, tt.code)
require.NoError(t, err, "execution error")

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

for _, tt := range tests {
program, err := expr.Compile(tt.code, expr.Optimize(false))
require.NoError(t, err, tt.code)
require.NoError(t, err, "compile error")

got, err := expr.Run(program, env)
require.NoError(t, err, tt.code)
require.NoError(t, err, "execution error")

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

for _, tt := range tests {
got, err := expr.Eval(tt.code, env)
require.NoError(t, err, tt.code)
require.NoError(t, err, "eval error")

assert.Equal(t, tt.want, got, "eval: "+tt.code)
}
Expand Down Expand Up @@ -1079,6 +1085,7 @@ type mockEnv struct {
NilStruct *time.Time
NilInt *int
NilSlice []ticket
Tweets []tweet
}

func (e *mockEnv) GetInt() int {
Expand Down Expand Up @@ -1144,6 +1151,8 @@ func (*mockEnv) Float(i interface{}) float64 {
}
}

func (*mockEnv) Format(t time.Time) string { return t.Format(time.RFC822) }

type ticket struct {
Price int
}
Expand All @@ -1168,6 +1177,11 @@ type segment struct {
Date time.Time
}

type tweet struct {
Text string
Date time.Time
}

type mockMapStringStringEnv map[string]string

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

0 comments on commit aa52e70

Please sign in to comment.