diff --git a/builtins.go b/builtins.go index a5deb411..e426b069 100644 --- a/builtins.go +++ b/builtins.go @@ -1099,6 +1099,16 @@ func liftNumeric(f func(float64) float64) func(*interpreter, value) (value, erro } } +func liftNumericToBoolean(f func(float64) bool) func(*interpreter, value) (value, error) { + return func(i *interpreter, x value) (value, error) { + n, err := i.getNumber(x) + if err != nil { + return nil, err + } + return makeValueBoolean(f(n.value)), nil + } +} + var builtinSqrt = liftNumeric(math.Sqrt) var builtinCeil = liftNumeric(math.Ceil) var builtinFloor = liftNumeric(math.Floor) @@ -1125,6 +1135,22 @@ var builtinExponent = liftNumeric(func(f float64) float64 { return float64(exponent) }) var builtinRound = liftNumeric(math.Round) +var builtinIsEven = liftNumericToBoolean(func(f float64) bool { + i, _ := math.Modf(f) // Get the integral part of the float + return math.Mod(i, 2) == 0 +}) +var builtinIsOdd = liftNumericToBoolean(func(f float64) bool { + i, _ := math.Modf(f) // Get the integral part of the float + return math.Mod(i, 2) != 0 +}) +var builtinIsInteger = liftNumericToBoolean(func(f float64) bool { + _, frac := math.Modf(f) // Get the fraction part of the float + return frac == 0 +}) +var builtinIsDecimal = liftNumericToBoolean(func(f float64) bool { + _, frac := math.Modf(f) // Get the fraction part of the float + return frac != 0 +}) func liftBitwise(f func(int64, int64) int64, positiveRightArg bool) func(*interpreter, value, value) (value, error) { return func(i *interpreter, xv, yv value) (value, error) { @@ -2467,6 +2493,10 @@ var funcBuiltins = buildBuiltinMap([]builtin{ &unaryBuiltin{name: "mantissa", function: builtinMantissa, params: ast.Identifiers{"x"}}, &unaryBuiltin{name: "exponent", function: builtinExponent, params: ast.Identifiers{"x"}}, &unaryBuiltin{name: "round", function: builtinRound, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "isEven", function: builtinIsEven, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "isOdd", function: builtinIsOdd, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "isInteger", function: builtinIsInteger, params: ast.Identifiers{"x"}}, + &unaryBuiltin{name: "isDecimal", function: builtinIsDecimal, params: ast.Identifiers{"x"}}, &binaryBuiltin{name: "pow", function: builtinPow, params: ast.Identifiers{"x", "n"}}, &binaryBuiltin{name: "modulo", function: builtinModulo, params: ast.Identifiers{"x", "y"}}, &unaryBuiltin{name: "md5", function: builtinMd5, params: ast.Identifiers{"s"}}, diff --git a/linter/internal/types/stdlib.go b/linter/internal/types/stdlib.go index eb4646d6..062d0085 100644 --- a/linter/internal/types/stdlib.go +++ b/linter/internal/types/stdlib.go @@ -45,6 +45,10 @@ func prepareStdlib(g *typeGraph) { "isNumber": g.newSimpleFuncType(boolType, "v"), "isObject": g.newSimpleFuncType(boolType, "v"), "isString": g.newSimpleFuncType(boolType, "v"), + "isEven": g.newSimpleFuncType(boolType, "x"), + "isOdd": g.newSimpleFuncType(boolType, "x"), + "isInteger": g.newSimpleFuncType(boolType, "x"), + "isDecimal": g.newSimpleFuncType(boolType, "x"), // Mathematical utilities "abs": g.newSimpleFuncType(numberType, "n"), diff --git a/testdata/builtinIsDecimal.golden b/testdata/builtinIsDecimal.golden new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/testdata/builtinIsDecimal.golden @@ -0,0 +1 @@ +true diff --git a/testdata/builtinIsDecimal.jsonnet b/testdata/builtinIsDecimal.jsonnet new file mode 100644 index 00000000..77d5556f --- /dev/null +++ b/testdata/builtinIsDecimal.jsonnet @@ -0,0 +1 @@ +std.isDecimal(1.1) \ No newline at end of file diff --git a/testdata/builtinIsDecimal.linter.golden b/testdata/builtinIsDecimal.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsDecimal2.golden b/testdata/builtinIsDecimal2.golden new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/testdata/builtinIsDecimal2.golden @@ -0,0 +1 @@ +false diff --git a/testdata/builtinIsDecimal2.jsonnet b/testdata/builtinIsDecimal2.jsonnet new file mode 100644 index 00000000..a21818e4 --- /dev/null +++ b/testdata/builtinIsDecimal2.jsonnet @@ -0,0 +1 @@ +std.isDecimal(1) \ No newline at end of file diff --git a/testdata/builtinIsDecimal2.linter.golden b/testdata/builtinIsDecimal2.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsEven.golden b/testdata/builtinIsEven.golden new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/testdata/builtinIsEven.golden @@ -0,0 +1 @@ +true diff --git a/testdata/builtinIsEven.jsonnet b/testdata/builtinIsEven.jsonnet new file mode 100644 index 00000000..d8078224 --- /dev/null +++ b/testdata/builtinIsEven.jsonnet @@ -0,0 +1 @@ +std.isEven(10) \ No newline at end of file diff --git a/testdata/builtinIsEven.linter.golden b/testdata/builtinIsEven.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsEven2.golden b/testdata/builtinIsEven2.golden new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/testdata/builtinIsEven2.golden @@ -0,0 +1 @@ +false diff --git a/testdata/builtinIsEven2.jsonnet b/testdata/builtinIsEven2.jsonnet new file mode 100644 index 00000000..c0e4fd41 --- /dev/null +++ b/testdata/builtinIsEven2.jsonnet @@ -0,0 +1 @@ +std.isEven(5) \ No newline at end of file diff --git a/testdata/builtinIsEven2.linter.golden b/testdata/builtinIsEven2.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsInteger.golden b/testdata/builtinIsInteger.golden new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/testdata/builtinIsInteger.golden @@ -0,0 +1 @@ +true diff --git a/testdata/builtinIsInteger.jsonnet b/testdata/builtinIsInteger.jsonnet new file mode 100644 index 00000000..ecfe8ee7 --- /dev/null +++ b/testdata/builtinIsInteger.jsonnet @@ -0,0 +1 @@ +std.isInteger(1) \ No newline at end of file diff --git a/testdata/builtinIsInteger.linter.golden b/testdata/builtinIsInteger.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsInteger2.golden b/testdata/builtinIsInteger2.golden new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/testdata/builtinIsInteger2.golden @@ -0,0 +1 @@ +false diff --git a/testdata/builtinIsInteger2.jsonnet b/testdata/builtinIsInteger2.jsonnet new file mode 100644 index 00000000..62c6fe01 --- /dev/null +++ b/testdata/builtinIsInteger2.jsonnet @@ -0,0 +1 @@ +std.isInteger(1.1) \ No newline at end of file diff --git a/testdata/builtinIsInteger2.linter.golden b/testdata/builtinIsInteger2.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsOdd.golden b/testdata/builtinIsOdd.golden new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/testdata/builtinIsOdd.golden @@ -0,0 +1 @@ +true diff --git a/testdata/builtinIsOdd.jsonnet b/testdata/builtinIsOdd.jsonnet new file mode 100644 index 00000000..164a93b0 --- /dev/null +++ b/testdata/builtinIsOdd.jsonnet @@ -0,0 +1 @@ +std.isOdd(5) \ No newline at end of file diff --git a/testdata/builtinIsOdd.linter.golden b/testdata/builtinIsOdd.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtinIsOdd2.golden b/testdata/builtinIsOdd2.golden new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/testdata/builtinIsOdd2.golden @@ -0,0 +1 @@ +false diff --git a/testdata/builtinIsOdd2.jsonnet b/testdata/builtinIsOdd2.jsonnet new file mode 100644 index 00000000..1501bbc1 --- /dev/null +++ b/testdata/builtinIsOdd2.jsonnet @@ -0,0 +1 @@ +std.isOdd(10) \ No newline at end of file diff --git a/testdata/builtinIsOdd2.linter.golden b/testdata/builtinIsOdd2.linter.golden new file mode 100644 index 00000000..e69de29b