diff --git a/apps/emqx_utils/src/emqx_variform.erl b/apps/emqx_utils/src/emqx_variform.erl index 834d22750..0a26f7480 100644 --- a/apps/emqx_utils/src/emqx_variform.erl +++ b/apps/emqx_utils/src/emqx_variform.erl @@ -83,8 +83,10 @@ eval_as_string(Expr, Bindings, _Opts) -> eval({str, Str}, _Bindings) -> str(Str); -eval({num, Num}, _Bindings) -> - str(Num); +eval({integer, Num}, _Bindings) -> + Num; +eval({float, Num}, _Bindings) -> + Num; eval({array, Args}, Bindings) -> eval(Args, Bindings); eval({call, FuncNameStr, Args}, Bindings) -> @@ -150,7 +152,7 @@ resolve_func_name(FuncNameStr) -> resolve_var_value(VarName, Bindings) -> case emqx_template:lookup_var(split(VarName), Bindings) of {ok, Value} -> - str(Value); + Value; {error, _Reason} -> <<>> end. diff --git a/apps/emqx_utils/src/emqx_variform_parser.yrl b/apps/emqx_utils/src/emqx_variform_parser.yrl index 508ef46d0..45d92696b 100644 --- a/apps/emqx_utils/src/emqx_variform_parser.yrl +++ b/apps/emqx_utils/src/emqx_variform_parser.yrl @@ -7,7 +7,8 @@ Nonterminals Terminals identifier - number + integer + float string '(' ')' ',' '[' ']'. @@ -34,7 +35,8 @@ args -> args ',' arg : '$1' ++ ['$3']. %% Arguments can be expressions, arrays, numbers, or strings arg -> expr : '$1'. arg -> array : '$1'. -arg -> number : {num, element(3, '$1')}. +arg -> integer: {integer, element(3, '$1')}. +arg -> float: {float, element(3, '$1')}. arg -> string : {str, element(3, '$1')}. Erlang code. diff --git a/apps/emqx_utils/src/emqx_variform_scan.xrl b/apps/emqx_utils/src/emqx_variform_scan.xrl index 29a45ef92..63c9fba29 100644 --- a/apps/emqx_utils/src/emqx_variform_scan.xrl +++ b/apps/emqx_utils/src/emqx_variform_scan.xrl @@ -3,7 +3,8 @@ Definitions. IDENTIFIER = [a-zA-Z][a-zA-Z0-9_.]* SQ_STRING = \'[^\']*\' DQ_STRING = \"[^\"]*\" -NUMBER = [+-]?(\\d+\\.\\d+|[0-9]+) +INTEGER = [+-]?[0-9]+ +FLOAT = [+-]?\\d+\\.\\d+ LPAREN = \( RPAREN = \) LBRACKET = \[ @@ -12,12 +13,12 @@ COMMA = , WHITESPACE = [\s\t\n]+ Rules. -%% Match function names, variable names (with ${}), strings, numbers, and structural characters {WHITESPACE} : skip_token. {IDENTIFIER} : {token, {identifier, TokenLine, TokenChars}}. {SQ_STRING} : {token, {string, TokenLine, unquote(TokenChars, $')}}. {DQ_STRING} : {token, {string, TokenLine, unquote(TokenChars, $")}}. -{NUMBER} : {token, {number, TokenLine, TokenChars}}. +{INTEGER} : {token, {integer, TokenLine, list_to_integer(TokenChars)}}. +{FLOAT} : {token, {float, TokenLine, list_to_float(TokenChars)}}. {LPAREN} : {token, {'(', TokenLine}}. {RPAREN} : {token, {')', TokenLine}}. {LBRACKET} : {token, {'[', TokenLine}}. diff --git a/apps/emqx_utils/test/emqx_variform_tests.erl b/apps/emqx_utils/test/emqx_variform_tests.erl index da26a383d..72fbf2637 100644 --- a/apps/emqx_utils/test/emqx_variform_tests.erl +++ b/apps/emqx_utils/test/emqx_variform_tests.erl @@ -39,11 +39,44 @@ redner_test_() -> {"out of range nth index", fun() -> ?assertEqual({ok, <<>>}, render("nth(2, tokens(var, ','))", #{var => <<"a">>})) end}, + {"string for nth index", fun() -> + ?assertEqual({ok, <<"a">>}, render("nth('1', tokens(var, ','))", #{var => <<"a">>})) + end}, {"not a index number for nth", fun() -> ?assertMatch( {error, #{reason := invalid_argument, func := nth, index := <<"notnum">>}}, render("nth('notnum', tokens(var, ','))", #{var => <<"a">>}) ) + end}, + {"substr", fun() -> + ?assertMatch( + {ok, <<"b">>}, + render("substr(var,1)", #{var => <<"ab">>}) + ) + end}, + {"result in integer", fun() -> + ?assertMatch( + {ok, <<"2">>}, + render("strlen(var)", #{var => <<"ab">>}) + ) + end}, + {"result in float", fun() -> + ?assertMatch( + {ok, <<"2.2">>}, + render("var", #{var => 2.2}) + ) + end}, + {"concat a number", fun() -> + ?assertMatch( + {ok, <<"2.2">>}, + render("concat(strlen(var),'.2')", #{var => <<"xy">>}) + ) + end}, + {"var is an array", fun() -> + ?assertMatch( + {ok, <<"y">>}, + render("nth(2,var)", #{var => [<<"x">>, <<"y">>]}) + ) end} ].