-module(emqx_rule_actions_trans). -include_lib("syntax_tools/include/merl.hrl"). -export([parse_transform/2]). parse_transform(Forms, _Options) -> trans(Forms, []). trans([], ResAST) -> lists:reverse(ResAST); trans([{eof, L} | AST], ResAST) -> lists:reverse([{eof, L} | ResAST]) ++ AST; trans([{function, LineNo, FuncName, Arity, Clauses} | AST], ResAST) -> NewClauses = trans_func_clauses(atom_to_list(FuncName), Clauses), trans(AST, [{function, LineNo, FuncName, Arity, NewClauses} | ResAST]); trans([Form | AST], ResAST) -> trans(AST, [Form | ResAST]). trans_func_clauses("on_action_create_" ++ _ = _FuncName , Clauses) -> %io:format("~n[[transing function: ~p]]~n", [_FuncName]), %io:format("~n-----old clauses:~n", []), merl:print(Clauses), NewClauses = [ begin Bindings = lists:flatten(get_vars(Args) ++ get_vars(Body, lefth)), Body2 = append_to_result(Bindings, Body), {clause, LineNo, Args, Guards, Body2} end || {clause, LineNo, Args, Guards, Body} <- Clauses], %io:format("~n-----new clauses: ~n"), merl:print(NewClauses), NewClauses; trans_func_clauses(_FuncName, Clauses) -> %io:format("~n[[discarding function: ~p]]~n", [_FuncName]), Clauses. get_vars(Exprs) -> get_vars(Exprs, all). get_vars(Exprs, Type) -> do_get_vars(Exprs, [], Type). do_get_vars([], Vars, _Type) -> Vars; do_get_vars([Line | Expr], Vars, all) -> do_get_vars(Expr, [syntax_vars(erl_syntax:form_list([Line])) | Vars], all); do_get_vars([Line | Expr], Vars, lefth) -> do_get_vars(Expr, case (Line) of ?Q("_@LeftV = _@@_") -> Vars ++ syntax_vars(LeftV); _ -> Vars end, lefth). syntax_vars(Line) -> sets:to_list(erl_syntax_lib:variables(Line)). %% append bindings to the return value as the first tuple element. %% e.g. if the original result is R, then the new result will be {[binding()], R}. append_to_result(Bindings, Exprs) -> erl_syntax:revert_forms(do_append_to_result(to_keyword(Bindings), Exprs, [])). do_append_to_result(KeyWordVars, [Line], Res) -> case Line of ?Q("_@LeftV = _@RightV") -> lists:reverse([?Q("{[_@KeyWordVars], _@LeftV}"), Line | Res]); _ -> lists:reverse([?Q("{[_@KeyWordVars], _@Line}") | Res]) end; do_append_to_result(KeyWordVars, [Line | Exprs], Res) -> do_append_to_result(KeyWordVars, Exprs, [Line | Res]). to_keyword(Vars) -> [erl_syntax:tuple([erl_syntax:atom(Var), merl:var(Var)]) || Var <- Vars].