From 04546d0a09d4c3e12e5e2bbd3be6cc026b3b2143 Mon Sep 17 00:00:00 2001 From: Andreas Bichinger Date: Tue, 3 May 2022 14:07:01 +0200 Subject: [PATCH] add map support --- dummies_test.go | 11 +++++++++-- evaluationStage.go | 45 +++++++++++++++++++++++++++++++-------------- evaluation_test.go | 16 +++++++++++++++- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/dummies_test.go b/dummies_test.go index e3a1a2e..6f4bf56 100644 --- a/dummies_test.go +++ b/dummies_test.go @@ -3,6 +3,7 @@ package govaluate import ( "errors" "fmt" + "strings" ) /* @@ -14,6 +15,7 @@ type dummyParameter struct { BoolFalse bool Nil interface{} Nested dummyNestedParameter + Map map[string]interface{} } func (this dummyParameter) Func() string { @@ -33,9 +35,9 @@ func (this dummyParameter) FuncArgStr(arg1 string) string { } func (this dummyParameter) TestArgs(str string, ui uint, ui8 uint8, ui16 uint16, ui32 uint32, ui64 uint64, i int, i8 int8, i16 int16, i32 int32, i64 int64, f32 float32, f64 float64, b bool) string { - + var sum float64 - + sum = float64(ui) + float64(ui8) + float64(ui16) + float64(ui32) + float64(ui64) sum += float64(i) + float64(i8) + float64(i16) + float64(i32) + float64(i64) sum += float64(f32) @@ -67,6 +69,11 @@ var dummyParameterInstance = dummyParameter{ Nested: dummyNestedParameter{ Funk: "funkalicious", }, + Map: map[string]interface{}{ + "String": "string!", + "Int": 101, + "StringCompare": strings.Compare, + }, } var fooParameter = EvaluationParameter{ diff --git a/evaluationStage.go b/evaluationStage.go index 11ea587..a19b49b 100644 --- a/evaluationStage.go +++ b/evaluationStage.go @@ -313,6 +313,7 @@ func makeAccessorStage(pair []string) evaluationOperator { } }() + LOOP: for i := 1; i < len(pair); i++ { coreValue := reflect.ValueOf(value) @@ -325,24 +326,40 @@ func makeAccessorStage(pair []string) evaluationOperator { coreValue = coreValue.Elem() } - if coreValue.Kind() != reflect.Struct { - return nil, errors.New("Unable to access '" + pair[i] + "', '" + pair[i-1] + "' is not a struct") - } - - field := coreValue.FieldByName(pair[i]) - if field != (reflect.Value{}) { - value = field.Interface() - continue - } + var field reflect.Value + var method reflect.Value - method := coreValue.MethodByName(pair[i]) - if method == (reflect.Value{}) { - if corePtrVal.IsValid() { - method = corePtrVal.MethodByName(pair[i]) + switch coreValue.Kind() { + case reflect.Struct: + field = coreValue.FieldByName(pair[i]) + if field != (reflect.Value{}) { + value = field.Interface() + continue LOOP } + + method = coreValue.MethodByName(pair[i]) if method == (reflect.Value{}) { - return nil, errors.New("No method or field '" + pair[i] + "' present on parameter '" + pair[i-1] + "'") + if corePtrVal.IsValid() { + method = corePtrVal.MethodByName(pair[i]) + } } + case reflect.Map: + field = coreValue.MapIndex(reflect.ValueOf(pair[i])) + if field != (reflect.Value{}) { + inter := field.Interface() + if reflect.TypeOf(inter).Kind() == reflect.Func { + method = reflect.ValueOf(inter) + } else { + value = inter + continue LOOP + } + } + default: + return nil, errors.New("Unable to access '" + pair[i] + "', '" + pair[i-1] + "' is not a struct or map") + } + + if method == (reflect.Value{}) { + return nil, errors.New("No method or field '" + pair[i] + "' present on parameter '" + pair[i-1] + "'") } switch right.(type) { diff --git a/evaluation_test.go b/evaluation_test.go index a2b65e8..56c1272 100644 --- a/evaluation_test.go +++ b/evaluation_test.go @@ -710,7 +710,7 @@ func TestNoParameterEvaluation(test *testing.T) { Expected: true, }, EvaluationTest{ - + Name: "Ternary/Java EL ambiguity", Input: "false ? foo:length()", Functions: map[string]ExpressionFunction{ @@ -1391,6 +1391,20 @@ func TestParameterizedEvaluation(test *testing.T) { Parameters: []EvaluationParameter{fooParameter}, Expected: "funkalicious", }, + EvaluationTest{ + + Name: "Nested Map string", + Input: "foo.Map.String", + Parameters: []EvaluationParameter{fooParameter}, + Expected: "string!", + }, + EvaluationTest{ + + Name: "Nested Map function", + Input: `foo.Map.StringCompare("foo", "bar")`, + Parameters: []EvaluationParameter{fooParameter}, + Expected: 1.0, + }, EvaluationTest{ Name: "Parameter call with + modifier",