:- module(parse_spec, [parse_functor_spec/5], []).

% Parse predicate spec or a list of them.
% TODO: wrong module name

:- use_module(engine(hiord_rt), [call/1]).
:- use_module(engine(internals), 
    [module_concat/3, '$setarg'/4, '$current_predicate'/2]).

:- meta_predicate parse_functor_spec(?,?,?,goal,?).

parse_functor_spec(Arg, _, _, _, _) :-
    nonvar(Arg), Arg=[], !.
parse_functor_spec(Arg, Module, GoalArg, Goal, Doing) :-
    nonvar(Arg), Arg=[X|Rest], !,
    Flag=f(0),
    (   
        functor_spec(X, Name, Low, High),
        module_concat(Module, Name, PredName),
        '$current_predicate'(PredName, GoalArg),
        functor(GoalArg, _, N),
        N >= Low, N =< High,
        '$setarg'(1, Flag, 1, true),
        call(Goal),
        fail
    ;   
        Goal = listing1(_) -> 
        true
    ;   
        Flag=f(0),
        X=GoalArg,
        throw(error(domain_error(predicate_indicator_list,Arg), Doing))
    ;   true
    ),
    parse_functor_spec(Rest, Module, GoalArg, Goal, Doing).
parse_functor_spec(Arg, Module, GoalArg, Goal, Doing) :-
    parse_functor_spec([Arg], Module, GoalArg, Goal, Doing).

functor_spec(Name/Low-High, Name, Low, High) :-
    atom(Name),
    integer(Low), integer(High), !.
functor_spec(Name/(Low-High), Name, Low, High) :-
    atom(Name),
    integer(Low), integer(High), !.
functor_spec(Name/Arity, Name, Arity, Arity) :-
    atom(Name),
    integer(Arity), !.
functor_spec(Name, Name, 0, 255) :-             % 255 is max. arity
    atom(Name).
