diff --git a/builtins.go b/builtins.go index 44dc304..33719b6 100644 --- a/builtins.go +++ b/builtins.go @@ -248,7 +248,7 @@ func builtinToString(e *evaluator, xp potentialValue) (value, error) { } func builtinMakeArray(e *evaluator, szp potentialValue, funcp potentialValue) (value, error) { - sz, err := e.evaluateNumber(szp) + sz, err := e.evaluateInt(szp) if err != nil { return nil, err } @@ -256,9 +256,8 @@ func builtinMakeArray(e *evaluator, szp potentialValue, funcp potentialValue) (v if err != nil { return nil, err } - num := int(sz.value) var elems []potentialValue - for i := 0; i < num; i++ { + for i := 0; i < sz; i++ { elem := fun.call(args(&readyValue{intToValue(i)})) elems = append(elems, elem) } @@ -274,7 +273,7 @@ func builtinFlatMap(e *evaluator, funcp potentialValue, arrp potentialValue) (va if err != nil { return nil, err } - num := int(arr.length()) + num := arr.length() // Start with capacity of the original array. // This may spare us a few reallocations. // TODO(sbarzowski) verify that it actually helps @@ -300,7 +299,7 @@ func builtinFilter(e *evaluator, funcp potentialValue, arrp potentialValue) (val if err != nil { return nil, err } - num := int(arr.length()) + num := arr.length() // Start with capacity of the original array. // This may spare us a few reallocations. // TODO(sbarzowski) verify that it actually helps @@ -479,17 +478,15 @@ var builtinExponent = liftNumeric(func(f float64) float64 { func liftBitwise(f func(int64, int64) int64) func(*evaluator, potentialValue, potentialValue) (value, error) { return func(e *evaluator, xp, yp potentialValue) (value, error) { - x, err := e.evaluateNumber(xp) + x, err := e.evaluateInt64(xp) if err != nil { return nil, err } - y, err := e.evaluateNumber(yp) + y, err := e.evaluateInt64(yp) if err != nil { return nil, err } - xInt := int64(x.value) - yInt := int64(y.value) - return makeDoubleCheck(e, float64(f(xInt, yInt))) + return makeDoubleCheck(e, float64(f(x, y))) } } diff --git a/evaluator.go b/evaluator.go index 43e80a4..5409a85 100644 --- a/evaluator.go +++ b/evaluator.go @@ -83,6 +83,50 @@ func (e *evaluator) evaluateNumber(pv potentialValue) (*valueNumber, error) { return e.getNumber(v) } +func (e *evaluator) getInt(val value) (int, error) { + num, err := e.getNumber(val) + if err != nil { + return 0, err + } + // We conservatively convert ot int32, so that it can be machine-sized int + // on any machine. And it's used only for indexing anyway. + intNum := int(int32(num.value)) + if float64(intNum) != num.value { + return 0, e.Error(fmt.Sprintf("Expected an integer, but got %v", num.value)) + } + return intNum, nil +} + +func (e *evaluator) evaluateInt(pv potentialValue) (int, error) { + v, err := e.evaluate(pv) + if err != nil { + return 0, err + } + return e.getInt(v) +} + +func (e *evaluator) getInt64(val value) (int64, error) { + num, err := e.getNumber(val) + if err != nil { + return 0, err + } + // We conservatively convert ot int32, so that it can be machine-sized int + // on any machine. And it's used only for indexing anyway. + intNum := int64(num.value) + if float64(intNum) != num.value { + return 0, e.Error(fmt.Sprintf("Expected an integer, but got %v", num.value)) + } + return intNum, nil +} + +func (e *evaluator) evaluateInt64(pv potentialValue) (int64, error) { + v, err := e.evaluate(pv) + if err != nil { + return 0, err + } + return e.getInt64(v) +} + func (e *evaluator) getString(val value) (*valueString, error) { switch v := val.(type) { case *valueString: diff --git a/testdata/bitwise_and3.golden b/testdata/bitwise_and3.golden index 573541a..836e54d 100644 --- a/testdata/bitwise_and3.golden +++ b/testdata/bitwise_and3.golden @@ -1 +1,10 @@ -0 +RUNTIME ERROR: Expected an integer, but got 1e+30 +------------------------------------------------- + testdata/bitwise_and3:1:1-10 $ + +1e30 & 42 + +------------------------------------------------- + During evaluation + + diff --git a/testdata/std.makeArray_noninteger.golden b/testdata/std.makeArray_noninteger.golden new file mode 100644 index 0000000..15485d3 --- /dev/null +++ b/testdata/std.makeArray_noninteger.golden @@ -0,0 +1,8 @@ +RUNTIME ERROR: Expected an integer, but got 2.5 +------------------------------------------------- + builtin function + +------------------------------------------------- + During evaluation + + diff --git a/testdata/std.makeArray_noninteger.jsonnet b/testdata/std.makeArray_noninteger.jsonnet new file mode 100644 index 0000000..c046e67 --- /dev/null +++ b/testdata/std.makeArray_noninteger.jsonnet @@ -0,0 +1 @@ +std.makeArray(2.5, function(i) i) diff --git a/testdata/std.makeArray_noninteger_big.golden b/testdata/std.makeArray_noninteger_big.golden new file mode 100644 index 0000000..974142d --- /dev/null +++ b/testdata/std.makeArray_noninteger_big.golden @@ -0,0 +1,8 @@ +RUNTIME ERROR: Expected an integer, but got 1e+100 +------------------------------------------------- + builtin function + +------------------------------------------------- + During evaluation + + diff --git a/testdata/std.makeArray_noninteger_big.jsonnet b/testdata/std.makeArray_noninteger_big.jsonnet new file mode 100644 index 0000000..9bd2ba3 --- /dev/null +++ b/testdata/std.makeArray_noninteger_big.jsonnet @@ -0,0 +1 @@ +std.makeArray(1e100, error "shouldn't happen")