%% ## consult with macro Convert to Normal clause  2015.09.25 by T.Inaba ##
%% [Usage]  ?- macro_consult(file). % file ; ?-macro_consult(user). % cosole
%%
%%  How to consult from AZedit buffer
%%    ?- e_jump(0),e_markend,macro_consult(edit).
%%  How to detect error point in file
%%    ?- echo(OnOff,on), macro_consult(file), echo(_,OnOff).

:- s_mode(_,on).
:- public macro_consult/1.

macro_consult(File):-
	see(File), s_constraints_mode(Mode,off),
	     repeat, ( errorset(s_exec,Err),!,Err \==fail ),  % only fail is repeat
	!,seen,    s_constraints_mode(_,  Mode).

s_exec:- read(X),(X == end_of_file->true ; s_dcg(X,Y),s_convM(Y,Z),s_do(Z),fail).

s_do((:-G)):- !,call_goal(G),!.
s_do((?-G)):- !,call_goal(G),!.
s_do(X):- assertz(X).

call_goal((A,B)):-!,call_goal_check(A),call_goal(B).
call_goal(A):-!,call_goal_check(A).

call_goal_check(s_constraints_mode(_,_)):-!.
call_goal_check(A):- call(A).

%%%%%% DCG Convert %%%%%%
s_dcg((P --> Q),PQ):-!,s_dcgH(P,P1,S0,S),s_dcgB(Q,Q1,_,S0,S),s_strip(Q1,Q2,P1,Q2,PQ).
s_dcg(X,X).

s_dcgH((P1,P2),Q,S0,S):- !,P1=..[F|A],append(P2,S,S1),append(A,[S0,S1],A1),Q=..[F|A1].
s_dcgH(P,Q,S0,S) :-  P=..[F|A],append(A,[S0,S],A1),Q=..[F|A1].

s_dcgB((P1,P2),QQ,Q2,S0,S) :- !,s_dcgB(P1,QQ,Q1,S0,S1),s_dcgB(P2,Q1,Q2,S1,S).
s_dcgB(P,Q,Q,S0,S) :- (P==[];list(P)),!,append(P,S,S0).
s_dcgB({P},QQ,Q,S,S):- !,s_dcgM(P,Q,QQ).
s_dcgB(!,(!,Q1),Q1,S,S) :- !.
s_dcgB(P,(Q,Q1),Q1,S0,S) :- P=..[F|A],append(A,[S0,S],A1),Q=..[F|A1].

s_dcgM((Q,Q1),Q2,(Q,Q3)):- !,s_dcgM(Q1,Q2,Q3).      % (a,b,c)+Q => (a,b,c,Q)
s_dcgM(Q1,Q2,(Q1,Q2)).                              %  a+Q => (a,Q)

s_strip(M,    _,     P,_,P):- var(M),!.             %  Var     =>  _,     P
s_strip((N,M),N,     P,Q,(P:-Q)):- var(M),!.        % (a,b,c,_)=>(a,b,c), P:-a,b,c.
s_strip((N,M),(N,E), P,Q,PQ):- s_strip(M,E,P,Q,PQ). 

%%%%% Macro Convert %%%%%
s_convM( G, G ):-  is_clp_macro_exist(off,off),!.   % Macro is not exist in recent Read
s_convM((:-G), (:-GG)   ):- !,s_goals(G,GG).
s_convM((H:-G),(H2:-New)):- !,s_a_goal(H,H2,New,Tail),s_goals(G,Tail).
s_convM(H,     (H2:-New)):- s_a_goal(H,H2,C,_),!,s_strip(C,New, _,_,_).  % _ is dummy

   %%%%% Convert Body's each Goal %%%%%
s_goals(G,G):- (atomic(G);var(G)),!.
s_goals(G,GG):- G=..[F,A],member(F,[call,'\+']),!,s_goals(A,AA),GG=..[F,AA].
s_goals(G,GG):- G=..[F,A,B],member(F,[',',';','->',catch]),!,s_goals(A,AA),s_goals(B,BB),GG=..[F,AA,BB].
s_goals(errorset(G,V),Goal):-!,s_goals(G,GG),s_a_goal(V,V2,Goal,errorset(GG,V2)).
s_goals(G,PreAdded) :- s_a_goal(G,G2,PreAdded,G2).

   %%%%%% Convert a Goal(or Head) :: +Goal,-ConvertedGoal,-Constraint,-Tail %%%%%%%%
s_a_goal(G,G,C,C):-            (atomic(G);var(G)),!.
s_a_goal(X#C,X,Cs,T):-         var(X),!,s_macro(X,C,Cs,T).
s_a_goal([X|Y],[X2|Y2],C,C2):- !,s_a_goal(X,X2,C,C1),s_a_goal(Y,Y2,C1,C2).
s_a_goal(X,X2,C,T):-           X=..[F|L],s_a_goal(L,L2,C,T),X2=..[F|L2].

   %%%%%% Convert Macro Part %%%%%%
s_macro(X,List,(put_clp_area(X,List2),T),T):- list(List),!,sort(List,List2).
s_macro(X,Var,(freeze(X,Var),T),T):-          var(Var),!.
s_macro(X,(A,B),C,T):-                        !,s_macro(X,A,C,T1),s_macro(X,B,T1,T).
s_macro(X,G,(freeze(X,PreAdded),C),C):-       !,s_a_goal(G,G2,PreAdded,G2).

:- s_mode(_,off).
