diff --git a/config/lang/ast/arithmetic_op.go b/config/lang/ast/arithmetic_op.go index 920b1d56e9..e36dd42dce 100644 --- a/config/lang/ast/arithmetic_op.go +++ b/config/lang/ast/arithmetic_op.go @@ -9,4 +9,5 @@ const ( ArithmeticOpSub ArithmeticOpMul ArithmeticOpDiv + ArithmeticOpMod ) diff --git a/config/lang/builtins.go b/config/lang/builtins.go index e14aba0d88..bf918c9c75 100644 --- a/config/lang/builtins.go +++ b/config/lang/builtins.go @@ -77,6 +77,8 @@ func builtinIntMath() ast.Function { result *= arg case ast.ArithmeticOpDiv: result /= arg + case ast.ArithmeticOpMod: + result = result % arg } } diff --git a/config/lang/check_types.go b/config/lang/check_types.go index 3b6eefbf00..f5cf166809 100644 --- a/config/lang/check_types.go +++ b/config/lang/check_types.go @@ -131,6 +131,11 @@ func (tc *typeCheckArithmetic) TypeCheck(v *TypeCheck) (ast.Node, error) { } } + // Modulo doesn't work for floats + if mathType == ast.TypeFloat && tc.n.Op == ast.ArithmeticOpMod { + return nil, fmt.Errorf("modulo cannot be used with floats") + } + // Return type v.StackPush(mathType) diff --git a/config/lang/eval_test.go b/config/lang/eval_test.go index 8a3195fe1d..602880cf27 100644 --- a/config/lang/eval_test.go +++ b/config/lang/eval_test.go @@ -71,6 +71,14 @@ func TestEval(t *testing.T) { ast.TypeString, }, + { + "foo ${42%4}", + nil, + false, + "foo 2", + ast.TypeString, + }, + { "foo ${42.0+1.0}", nil, diff --git a/config/lang/lex.go b/config/lang/lex.go index 6b30f2a4c7..6e70acfbc8 100644 --- a/config/lang/lex.go +++ b/config/lang/lex.go @@ -180,6 +180,9 @@ func (x *parserLex) lexModeInterpolation(yylval *parserSymType) int { case '/': yylval.token = &parserToken{Value: ast.ArithmeticOpDiv} return ARITH_OP + case '%': + yylval.token = &parserToken{Value: ast.ArithmeticOpMod} + return ARITH_OP default: x.backup() return x.lexId(yylval)