Skip to content

Commit

Permalink
contains operates on strings not arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
osteele committed Jun 30, 2017
1 parent ebc29dc commit 9dda87f
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 49 deletions.
63 changes: 36 additions & 27 deletions expressions/builders.go
Expand Up @@ -2,39 +2,18 @@ package expressions

import (
"reflect"
"strings"
)

func makeObjectPropertyEvaluator(obj func(Context) interface{}, attr string) func(Context) interface{} {
func makeContainsExpr(e1, e2 func(Context) interface{}) func(Context) interface{} {
return func(ctx Context) interface{} {
ref := reflect.ValueOf(obj(ctx))
switch ref.Kind() {
case reflect.Array, reflect.Slice:
if ref.Len() == 0 {
return nil
}
switch attr {
case "first":
return ref.Index(0).Interface()
case "last":
return ref.Index(ref.Len() - 1).Interface()
case "size":
return ref.Len()
}
case reflect.String:
if attr == "size" {
return ref.Len()
}
case reflect.Map:
value := ref.MapIndex(reflect.ValueOf(attr))
if value.Kind() != reflect.Invalid {
return value.Interface()
}
}
return nil
a, aok := e1(ctx).(string)
b, bok := e2(ctx).(string)
return aok && bok && strings.Contains(a, b)
}
}

func makeIndexEvaluator(obj, index func(Context) interface{}) func(Context) interface{} {
func makeIndexExpr(obj, index func(Context) interface{}) func(Context) interface{} {
return func(ctx Context) interface{} {
ref := reflect.ValueOf(obj(ctx))
i := reflect.ValueOf(index(ctx))
Expand All @@ -61,3 +40,33 @@ func makeIndexEvaluator(obj, index func(Context) interface{}) func(Context) inte
return nil
}
}

func makeObjectPropertyExpr(obj func(Context) interface{}, attr string) func(Context) interface{} {
return func(ctx Context) interface{} {
ref := reflect.ValueOf(obj(ctx))
switch ref.Kind() {
case reflect.Array, reflect.Slice:
if ref.Len() == 0 {
return nil
}
switch attr {
case "first":
return ref.Index(0).Interface()
case "last":
return ref.Index(ref.Len() - 1).Interface()
case "size":
return ref.Len()
}
case reflect.String:
if attr == "size" {
return ref.Len()
}
case reflect.Map:
value := ref.MapIndex(reflect.ValueOf(attr))
if value.Kind() != reflect.Invalid {
return value.Interface()
}
}
return nil
}
}
11 changes: 3 additions & 8 deletions expressions/expressions.y
Expand Up @@ -83,8 +83,8 @@ loop_modifiers: /* empty */ { $$ = loopModifiers{} }
expr:
LITERAL { val := $1; $$ = func(_ Context) interface{} { return val } }
| IDENTIFIER { name := $1; $$ = func(ctx Context) interface{} { return ctx.Get(name) } }
| expr '.' IDENTIFIER { $$ = makeObjectPropertyEvaluator($1, $3) }
| expr '[' expr ']' { $$ = makeIndexEvaluator($1, $3) }
| expr '.' IDENTIFIER { $$ = makeObjectPropertyExpr($1, $3) }
| expr '[' expr ']' { $$ = makeIndexExpr($1, $3) }
| '(' cond ')' { $$ = $2 }
;

Expand Down Expand Up @@ -143,12 +143,7 @@ rel:
return generics.Less(a, b) || generics.Equal(a, b)
}
}
| expr CONTAINS expr {
fa, fb := $1, $3
$$ = func(ctx Context) interface{} {
return generics.Contains(fa(ctx), fb(ctx))
}
}
| expr CONTAINS expr { $$ = makeContainsExpr($1, $3) }
;

cond:
Expand Down
12 changes: 6 additions & 6 deletions expressions/expressions_test.go
Expand Up @@ -34,9 +34,9 @@ var evaluatorTests = []struct {
{`fruits.size`, 4},

// Indices
{`ar[1]`, "second"},
{`ar[-1]`, "third"}, // undocumented
{`ar[100]`, nil},
{`array[1]`, "second"},
{`array[-1]`, "third"}, // undocumented
{`array[100]`, nil},
{`obj[1]`, nil},
{`obj.c[0]`, "r"},

Expand Down Expand Up @@ -89,13 +89,13 @@ var evaluatorTests = []struct {
{`false or false`, false},
{`false or true`, true},

{`ar contains "first"`, true},
{`ar contains "missing"`, false},
{`"seafood" contains "foo"`, true},
{`"seafood" contains "bar"`, false},
}

var evaluatorTestContext = NewContext(map[string]interface{}{
"n": 123,
"ar": []string{"first", "second", "third"},
"array": []string{"first", "second", "third"},
"empty_list": []interface{}{},
"fruits": []string{"apples", "oranges", "peaches", "plums"},
"obj": map[string]interface{}{
Expand Down
13 changes: 5 additions & 8 deletions expressions/y.go
Expand Up @@ -591,13 +591,13 @@ yydefault:
yyDollar = yyS[yypt-3 : yypt+1]
//line expressions.y:86
{
yyVAL.f = makeObjectPropertyEvaluator(yyDollar[1].f, yyDollar[3].name)
yyVAL.f = makeObjectPropertyExpr(yyDollar[1].f, yyDollar[3].name)
}
case 11:
yyDollar = yyS[yypt-4 : yypt+1]
//line expressions.y:87
{
yyVAL.f = makeIndexEvaluator(yyDollar[1].f, yyDollar[3].f)
yyVAL.f = makeIndexExpr(yyDollar[1].f, yyDollar[3].f)
}
case 12:
yyDollar = yyS[yypt-3 : yypt+1]
Expand Down Expand Up @@ -693,14 +693,11 @@ yydefault:
yyDollar = yyS[yypt-3 : yypt+1]
//line expressions.y:146
{
fa, fb := yyDollar[1].f, yyDollar[3].f
yyVAL.f = func(ctx Context) interface{} {
return generics.Contains(fa(ctx), fb(ctx))
}
yyVAL.f = makeContainsExpr(yyDollar[1].f, yyDollar[3].f)
}
case 27:
yyDollar = yyS[yypt-3 : yypt+1]
//line expressions.y:156
//line expressions.y:151
{
fa, fb := yyDollar[1].f, yyDollar[3].f
yyVAL.f = func(ctx Context) interface{} {
Expand All @@ -709,7 +706,7 @@ yydefault:
}
case 28:
yyDollar = yyS[yypt-3 : yypt+1]
//line expressions.y:162
//line expressions.y:157
{
fa, fb := yyDollar[1].f, yyDollar[3].f
yyVAL.f = func(ctx Context) interface{} {
Expand Down

0 comments on commit 9dda87f

Please sign in to comment.