diff --git a/jp_test.go b/jp_test.go index 78c0d18..7c95b10 100644 --- a/jp_test.go +++ b/jp_test.go @@ -34,11 +34,11 @@ var whiteListed = []string{ "compliance/tests/filters.json", "compliance/tests/functions.json", "compliance/tests/function_group_by.json", - "compliance/tests/function_let.json", + // "compliance/tests/function_let.json", "compliance/tests/function_strings.json", "compliance/tests/identifiers.json", "compliance/tests/indices.json", - "compliance/tests/lexical_scoping.json", + // "compliance/tests/lexical_scoping.json", "compliance/tests/literal.json", "compliance/tests/multiselect.json", "compliance/tests/ormatch.json", diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 15d7143..45c6eef 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -64,11 +64,6 @@ func TestSearch(t *testing.T) { expression: "not a valid expression", }, wantErr: true, - }, { - args: args{ - expression: "let({root: @}, &root).root", - data: map[string]interface{}{}, - }, }, { args: args{ expression: "sort_by(@, &@ *`-1.0`)", diff --git a/pkg/functions/default.go b/pkg/functions/default.go index 66bbf49..8b942db 100644 --- a/pkg/functions/default.go +++ b/pkg/functions/default.go @@ -101,13 +101,6 @@ func GetDefaultFunctions() []FunctionEntry { {Types: []JpType{JpString}}, }, Handler: jpfLower, - }, { - Name: "let", - Arguments: []ArgSpec{ - {Types: []JpType{JpObject}}, - {Types: []JpType{JpExpref}}, - }, - Handler: jpfLet, }, { Name: "map", Arguments: []ArgSpec{ diff --git a/pkg/functions/functions.go b/pkg/functions/functions.go index 3337caa..53b6312 100644 --- a/pkg/functions/functions.go +++ b/pkg/functions/functions.go @@ -18,7 +18,7 @@ import ( type ( JpFunction = func([]interface{}) (interface{}, error) - ExpRef = func(interface{}, map[string]interface{}) (interface{}, error) + ExpRef = func(interface{}) (interface{}, error) JpType string ) @@ -230,7 +230,7 @@ func jpfGroupBy(arguments []interface{}) (interface{}, error) { } groups := map[string]interface{}{} for _, element := range arr { - spec, err := exp(element, nil) + spec, err := exp(element) if err != nil { return nil, err } @@ -294,22 +294,12 @@ func jpfLower(arguments []interface{}) (interface{}, error) { return strings.ToLower(arguments[0].(string)), nil } -func jpfLet(arguments []interface{}) (interface{}, error) { - scope := arguments[0].(map[string]interface{}) - exp := arguments[1].(ExpRef) - result, err := exp(nil, scope) - if err != nil { - return nil, err - } - return result, nil -} - func jpfMap(arguments []interface{}) (interface{}, error) { exp := arguments[0].(ExpRef) arr := arguments[1].([]interface{}) mapped := make([]interface{}, 0, len(arr)) for _, value := range arr { - current, err := exp(value, nil) + current, err := exp(value) if err != nil { return nil, err } @@ -359,7 +349,7 @@ func jpfMaxBy(arguments []interface{}) (interface{}, error) { } else if len(arr) == 1 { return arr[0], nil } - start, err := exp(arr[0], nil) + start, err := exp(arr[0]) if err != nil { return nil, err } @@ -368,7 +358,7 @@ func jpfMaxBy(arguments []interface{}) (interface{}, error) { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { - result, err := exp(item, nil) + result, err := exp(item) if err != nil { return nil, err } @@ -386,7 +376,7 @@ func jpfMaxBy(arguments []interface{}) (interface{}, error) { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { - result, err := exp(item, nil) + result, err := exp(item) if err != nil { return nil, err } @@ -456,7 +446,7 @@ func jpfMinBy(arguments []interface{}) (interface{}, error) { } else if len(arr) == 1 { return arr[0], nil } - start, err := exp(arr[0], nil) + start, err := exp(arr[0]) if err != nil { return nil, err } @@ -464,7 +454,7 @@ func jpfMinBy(arguments []interface{}) (interface{}, error) { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { - result, err := exp(item, nil) + result, err := exp(item) if err != nil { return nil, err } @@ -482,7 +472,7 @@ func jpfMinBy(arguments []interface{}) (interface{}, error) { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { - result, err := exp(item, nil) + result, err := exp(item) if err != nil { return nil, err } @@ -617,7 +607,7 @@ func jpfSortBy(arguments []interface{}) (interface{}, error) { } var sortKeys []interface{} for _, item := range arr { - if value, err := exp(item, nil); err != nil { + if value, err := exp(item); err != nil { return nil, err } else { sortKeys = append(sortKeys, value) diff --git a/pkg/interpreter/functions.go b/pkg/interpreter/functions.go index 59f2d91..6e32ff6 100644 --- a/pkg/interpreter/functions.go +++ b/pkg/interpreter/functions.go @@ -10,7 +10,7 @@ import ( ) type FunctionCaller interface { - CallFunction(string, []interface{}, Interpreter) (interface{}, error) + CallFunction(string, []interface{}) (interface{}, error) } type functionEntry struct { @@ -146,7 +146,7 @@ func typeCheck(a functions.ArgSpec, arg interface{}) error { return fmt.Errorf("invalid type for: %v, expected: %#v", arg, a.Types) } -func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr Interpreter) (interface{}, error) { +func (f *functionCaller) CallFunction(name string, arguments []interface{}) (interface{}, error) { entry, ok := f.functionTable[name] if !ok { return nil, errors.New("unknown function: " + name) diff --git a/pkg/interpreter/interpreter.go b/pkg/interpreter/interpreter.go index 185eff9..5f837a1 100644 --- a/pkg/interpreter/interpreter.go +++ b/pkg/interpreter/interpreter.go @@ -18,31 +18,20 @@ This is a tree based interpreter. It walks the AST and directly */ type Interpreter interface { Execute(parsing.ASTNode, interface{}) (interface{}, error) - WithScope(map[string]interface{}) Interpreter } type treeInterpreter struct { caller FunctionCaller - scope Scope root interface{} } func NewInterpreter(data interface{}, caller FunctionCaller) Interpreter { return &treeInterpreter{ caller: caller, - scope: newScope(nil), root: data, } } -func (intr *treeInterpreter) WithScope(data map[string]interface{}) Interpreter { - return &treeInterpreter{ - caller: intr.caller, - scope: intr.scope.With(data), - root: intr.root, - } -} - // Execute takes an ASTNode and input data and interprets the AST directly. // It will produce the result of applying the JMESPath expression associated // with the ASTNode to the input data "value". @@ -130,10 +119,7 @@ func (intr *treeInterpreter) Execute(node parsing.ASTNode, value interface{}) (i return leftNum <= rightNum, nil } case parsing.ASTExpRef: - return func(data interface{}, scope map[string]interface{}) (interface{}, error) { - if scope != nil { - return intr.WithScope(scope).Execute(node.Children[0], value) - } + return func(data interface{}) (interface{}, error) { return intr.Execute(node.Children[0], data) }, nil case parsing.ASTFunctionExpression: @@ -145,7 +131,7 @@ func (intr *treeInterpreter) Execute(node parsing.ASTNode, value interface{}) (i } resolvedArgs = append(resolvedArgs, current) } - return intr.caller.CallFunction(node.Value.(string), resolvedArgs, intr) + return intr.caller.CallFunction(node.Value.(string), resolvedArgs) case parsing.ASTField: key := node.Value.(string) var result interface{} @@ -159,9 +145,6 @@ func (intr *treeInterpreter) Execute(node parsing.ASTNode, value interface{}) (i if result != nil { return result, nil } - if result, ok := intr.scope.GetValue(key); ok { - return result, nil - } return nil, nil case parsing.ASTFilterProjection: left, err := intr.Execute(node.Children[0], value) diff --git a/pkg/interpreter/scopes.go b/pkg/interpreter/scopes.go deleted file mode 100644 index 3331672..0000000 --- a/pkg/interpreter/scopes.go +++ /dev/null @@ -1,37 +0,0 @@ -package interpreter - -type Scope interface { - GetValue(string) (interface{}, bool) - With(data map[string]interface{}) Scope -} - -type scope struct { - inner Scope - data map[string]interface{} -} - -// newScope creates a new instance of JMESPath scope. -func newScope(data map[string]interface{}) Scope { - return scope{ - data: data, - } -} - -func (s scope) GetValue(identifier string) (interface{}, bool) { - if s.data != nil { - if item, ok := s.data[identifier]; ok { - return item, true - } - } - if s.inner != nil { - return s.inner.GetValue(identifier) - } - return nil, false -} - -func (s scope) With(data map[string]interface{}) Scope { - return scope{ - data: data, - inner: s, - } -} diff --git a/pkg/interpreter/scopes_test.go b/pkg/interpreter/scopes_test.go deleted file mode 100644 index fd3664f..0000000 --- a/pkg/interpreter/scopes_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package interpreter - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestScopesMissing(t *testing.T) { - assert := assert.New(t) - scopes := newScope(nil) - - _, found := scopes.GetValue("foo") - assert.False(found) -} - -func TestScopesRoot(t *testing.T) { - assert := assert.New(t) - scopes := newScope(map[string]interface{}{"foo": "bar"}) - - value, found := scopes.GetValue("foo") - assert.True(found) - assert.Equal("bar", value.(string)) -} - -func TestScopesNested(t *testing.T) { - assert := assert.New(t) - scopes := newScope(nil) - - { - scopes := scopes.With(map[string]interface{}{"foo": "bar", "qux": "quux"}) - - { - scopes := scopes.With(map[string]interface{}{"foo": "baz"}) - - value, found := scopes.GetValue("foo") - assert.True(found) - assert.Equal("baz", value.(string)) - - value, found = scopes.GetValue("qux") - assert.True(found) - assert.Equal("quux", value.(string)) - } - - value, found := scopes.GetValue("foo") - assert.True(found) - assert.Equal("bar", value.(string)) - } - - _, found := scopes.GetValue("foo") - assert.False(found) -}