Skip to content

Commit b97663e

Browse files
committed
Added type conversion for function input arguments
- this uses the built-in go methods to convert from one type to another - the main impetus was to support function calls with numeric parameters that weren’t doubles
1 parent aa73cfd commit b97663e

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

dummies_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package govaluate
22

33
import (
44
"errors"
5+
"fmt"
56
)
67

78
/*
@@ -31,6 +32,16 @@ func (this dummyParameter) FuncArgStr(arg1 string) string {
3132
return arg1
3233
}
3334

35+
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) string {
36+
var sum float64
37+
sum = float64(ui) + float64(ui8) + float64(ui16) + float64(ui32) + float64(ui64)
38+
sum += float64(i) + float64(i8) + float64(i16) + float64(i32) + float64(i64)
39+
sum += float64(f32)
40+
sum += f64
41+
42+
return fmt.Sprintf("%v: %v", str, sum)
43+
}
44+
3445
func (this dummyParameter) AlwaysFail() (interface{}, error) {
3546
return nil, errors.New("function should always fail")
3647
}

evaluationFailure_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ const (
3333
ABSENT_PARAMETER = "No parameter"
3434
INVALID_REGEX = "Unable to compile regexp pattern"
3535
INVALID_PARAMETER_CALL = "No method or field"
36-
TOO_FEW_ARGS = "reflect: Call with too few input arguments"
37-
TOO_MANY_ARGS = "reflect: Call with too many input arguments"
38-
MISMATCHED_PARAMETERS = "reflect: Call using"
36+
TOO_FEW_ARGS = "Too few arguments to parameter call"
37+
TOO_MANY_ARGS = "Too many arguments to parameter call"
38+
MISMATCHED_PARAMETERS = "Argument type conversion failed"
3939
)
4040

4141
// preset parameter map of types that can be used in an evaluation failure test to check typing.

evaluationStage.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,48 @@ func makeFunctionStage(function ExpressionFunction) evaluationOperator {
247247
}
248248
}
249249

250+
func typeConvertParam(p reflect.Value, t reflect.Type) (ret reflect.Value, err error) {
251+
defer func() {
252+
if r := recover(); r != nil {
253+
errorMsg := fmt.Sprintf("Argument type conversion failed: failed to convert '%s' to '%s'", p.Kind().String(), t.Kind().String())
254+
err = errors.New(errorMsg)
255+
ret = p
256+
}
257+
}()
258+
259+
return p.Convert(t), nil
260+
}
261+
262+
func typeConvertParams(method reflect.Value, params []reflect.Value) ([]reflect.Value, error) {
263+
264+
methodType := method.Type()
265+
numIn := methodType.NumIn()
266+
numParams := len(params)
267+
268+
if numIn != numParams {
269+
if numIn > numParams {
270+
return nil, fmt.Errorf("Too few arguments to parameter call: got %d arguments, expected %d", len(params), numIn)
271+
}
272+
return nil, fmt.Errorf("Too many arguments to parameter call: got %d arguments, expected %d", len(params), numIn)
273+
}
274+
275+
for i := 0; i < numIn; i++ {
276+
t := methodType.In(i)
277+
p := params[i]
278+
pt := p.Type()
279+
280+
if t.Kind() != pt.Kind() {
281+
np, err := typeConvertParam(p, t)
282+
if err != nil {
283+
return nil, err
284+
}
285+
params[i] = np
286+
}
287+
}
288+
289+
return params, nil
290+
}
291+
250292
func makeAccessorStage(pair []string) evaluationOperator {
251293

252294
reconstructed := strings.Join(pair, ".")
@@ -322,6 +364,12 @@ func makeAccessorStage(pair []string) evaluationOperator {
322364
params = []reflect.Value{reflect.ValueOf(right.(interface{}))}
323365
}
324366

367+
params, err = typeConvertParams(method, params)
368+
369+
if err != nil {
370+
return nil, errors.New("Method call failed - '" + pair[0] + "." + pair[1] + "': " + err.Error())
371+
}
372+
325373
returned := method.Call(params)
326374
retLength := len(returned)
327375

evaluation_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,14 @@ func TestParameterizedEvaluation(test *testing.T) {
13281328
Parameters: []EvaluationParameter{fooParameter},
13291329
Expected: "frink",
13301330
},
1331+
EvaluationTest{
1332+
1333+
Name: "Parameter function call with all argument types",
1334+
Input: "foo.TestArgs(\"hello\", 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1.0, 2.0)",
1335+
Parameters: []EvaluationParameter{fooParameter},
1336+
Expected: "hello: 33",
1337+
},
1338+
13311339
EvaluationTest{
13321340

13331341
Name: "Simple parameter function call, one arg",

0 commit comments

Comments
 (0)