-module(ephp_stack). -author('manuel@altenwald.com'). -compile([warnings_as_errors, {no_auto_import, [get/1]}]). -include("ephp.hrl"). -export([ start_link/1, destroy/1, get/1, get_array/1, get_array/2, push/7, pop/1 ]). start_link(Ref) -> case get(Ref) of Stack when is_list(Stack) -> ok; undefined -> erlang:put(get_id(Ref), []) end, {ok, get_id(Ref)}. destroy(Ref) -> erlang:erase(get_id(Ref)). push(_Ref, _File, undefined, _Fun, _Args, _Class, _Object) -> ok; push(Ref, File, {{line,Line},_}, Fun, Args, Class, Object) -> Stack = get(Ref), Type = if Class =:= undefined -> undefined; Object =:= undefined -> <<"::">>; true -> <<"->">> end, New = #stack_trace{ function = Fun, args = Args, file = File, line = Line, object = Object, class = Class, type = Type }, case add_function(Fun) of [] when File =:= undefined -> ok; _ -> erlang:put(get_id(Ref), [New|Stack]) end, ok. pop(Ref) -> case get(Ref) of [Head|Stack] -> erlang:put(get_id(Ref), Stack), Head; [] -> undefined end. get(Ref) -> erlang:get(get_id(Ref)). get_array(Ref) -> get_array(Ref, 0). get_array(Ref, PopElements) -> {_, Stack} = lists:foldl(fun (Stack, {0, Array}) -> #stack_trace{ function = Fun, file = File, line = Line, class = Class, object = Object, type = Type, args = Args } = Stack, Element = ephp_array:from_list( [ {<<"file">>, File}, {<<"line">>, Line} ] ++ add_function(Fun) ++ add_class(Class) ++ add_object(Object) ++ add_type(Type) ++ add_args(Fun, Args)), {0, ephp_array:store(auto, Element, Array)}; (_Stack, {N, Array}) -> {N-1, Array} end, {PopElements, ephp_array:new()}, get(Ref)), Stack. add_function(Fun) -> Incs = [<<"include">>, <<"include_once">>, <<"require">>, <<"require_once">>], case lists:member(ephp_string:to_lower(Fun), Incs) of true -> []; false -> [{<<"function">>, Fun}] end. add_class(undefined) -> []; add_class(Class) -> [{<<"class">>, Class}]. add_object(undefined) -> []; add_object(Object) -> [{<<"object">>, Object}]. add_type(undefined) -> []; add_type(Type) -> [{<<"type">>, Type}]. add_args(Fun, Args) -> [{<<"args">>, ephp_array:from_list(Args)}] ++ case add_function(Fun) of [] -> [{<<"function">>, Fun}]; _ -> [] end. get_id(_Ref) -> % FIXME: at this moment it's very complicated to get only the global % reference. Anyway, it's better to work only with one context % per process. stack.