/*  ATNCOMMON.PL  */



/*
Introduction.
-------------

This file defines the text representation of ATNs, and those predicates
that don't depend on the internal representation. For how ATNs are
used, see the documentation.


Exported predicates.
--------------------

This file exports these predicates:
    assert_atn( T+ )
    retractall_atn( Node+ )
    atn_reconsult( Filename+ )

'assert_atn(T)' takes the text representation of an ATN and asserts it.

'retractall_atn(Node+)' takes a node term, and retracts all nodes which
match it.

'atn_reconsult(F)' reads and asserts definitions from a file. The file can
also contain directives and Prolog clauses: see the documentation.
*/



/*
Syntax.
-------

Define the following operators to implement the syntax. These are for
PDP-11 compatible Prolog. YOU WILL NEED TO CHANGE THEM FOR DEC-10
COMPATIBLE VERSIONS.
*/


:- op( 255, xfx, :: ).
:- op( 254, xfx, to ).
:- op( 254, fx, to ).
:- op( 254, xfx, if ).



/*
Converting from text to expanded form.
--------------------------------------

See ATNC.PL for a description of expanded form. The main predicate defined
is 'expand( T+, E- ) which expands T (text form) into E (expanded form).
*/


expand( ::(A,B), atn(A,Command,Arcs) ) :-
    get_command_and_arcs( B, Command, Arcs ).


/*  get_command_and_arcs( Body+, Command-, Arcs- ):
        Expand Body into a Command and a list of arcs. These are
        the expanded representation of command and arcs as defined
        in ATNC.
*/
get_command_and_arcs( (to Arcs), true, Arcs_ ) :-
    !,
    get_arcs( Arcs, Arcs_ ).

get_command_and_arcs( to(Command,Arcs), Command, Arcs_ ) :-
    !,
    get_arcs( Arcs, Arcs_ ).

get_command_and_arcs( Command, Command, [] ).


get_arcs( if( Node, to( Cond, Rest ) ), [ Cond, Node | Rest_ ] ) :-
    !,
    get_arcs( Rest, Rest_ ).

get_arcs( if( Node, Cond ), [ Cond, Node, true, failure ] ) :- !.

get_arcs( Node, [ true, Node ] ).



/*
Loading files.
--------------

This section defines the predicate 'atn_reconsult(File)'.
*/


atn_reconsult( File ) :-
    seeing( CIS ),
    see( File ), seen,
    see( File ),
    atn_reconsult_1( '$none' ),
    seen,
    see( CIS ).


/*  atn_reconsult_1( Previous+ ):
        Previous is a representation of the previous term in the file.
        If there was none, or the term was a directive, Previous
        is '$none'.
        If the term was a clause, Previous is 'clause(F,A)' where F/A
        are the clause's head functor and arity.
        If the term was a node definition, Previous is 'atn(F,A)'
        where F/A are the node's functor and arity.

        Previous is used by 'process_term'. 'process_term' compares
        Previous against its first argument, Term. If they are not
        a node with the same functor and arity, or a clause with
        the same functor and arity, the old definitions will be
        deleted.
*/
atn_reconsult_1( Previous ) :-
    read( Term ),
    (
        Term = end_of_file
    ->
        true
    ;
        process_term( Term, Previous, Next ),
        atn_reconsult_1( Next )
    ).


process_term( ?-(Term), _, '$none' ) :-
    call( Term ) -> true ; true.

process_term( :-(Term), _, '$none' ) :-
    call( Term ) -> true ; true.

process_term( ::(Node,Body), Previous, atn(F,A) ) :-
    !,
    expand( ::(Node,Body), ATN ),
    functor( Node, F, A ),
    (
        Previous \= atn(F,A)
    ->
        functor( Template, F, A ),
        retractall_expanded_atn( Template )
        /*  Template is the same functor and arity as Node, but all its
            arguments are new variables. So retractall_expanded_atn will
            delete all nodes with that functor and arity.
        */                    
    ;
        true
    ),
    assert_expanded_atn( ATN ).

process_term( :-(Head,Tail), Previous, clause(Functor,Arity) ) :-
    !,
    functor( Head, Functor, Arity ),
    (
        Previous \= clause(Functor,Arity)
    ->
        abolish( Functor, Arity )
    ;
        true
    ),
    assert( (Head:-Tail) ).

process_term( Head, Previous, Next ) :-
    process_term( (Head:-true), Previous, Next ).


assert_atn( ::(A,B) ) :-
    expand( ::(A,B), ATN ),
    assert_expanded_atn( ATN ).


retractall_atn( ::(A,B) ) :-
    expand( ::(A,B), atn(Node,_,_) ),
    retractall_expanded_atn( Node ).
