Files
scryer-prolog/src/prolog/lib/atts.pl
2019-02-02 12:20:39 -07:00

120 lines
3.7 KiB
Prolog

:- module(atts, [attribute/1, absent_attr/2, get_attr/2, put_attr/2,
absent_from_list/2, get_from_list/2, add_to_list/2,
del_attr/3, del_attr_step/2, del_attr_non_head/3]).
:- use_module(library(control)).
:- use_module(library(dcgs)).
:- use_module(library(terms)).
:- op(1199, fx, attribute).
absent_attr(V, Attr) :-
'$get_attr_list'(V, Ls),
absent_from_list(Ls, Attr).
absent_from_list(X, _) :-
var(X), !.
absent_from_list([L|Ls], Attr) :-
( L \= Attr -> absent_from_list(Ls, Attr) ).
get_attr(V, Attr) :-
'$get_attr_list'(V, Ls), nonvar(Ls), get_from_list(Ls, Attr).
get_from_list([L|Ls], Attr) :-
nonvar(L),
( L \= Attr -> nonvar(Ls), get_from_list(Ls, Attr)
; copy_term(L, L0), L0 = Attr
; get_from_list(Ls, Attr)
).
put_attr(V, Attr) :-
'$get_attr_list'(V, Ls), add_to_list(Ls, Attr).
add_to_list(Ls, Attr) :-
( var(Ls) -> Ls = [Attr | _]
; Ls = [_ | Ls0] -> add_to_list(Ls0, Attr)
).
del_attr(Ls0, _, _) :-
var(Ls0), !.
del_attr(Ls0, V, Attr) :-
Ls0 = [Att | Ls1],
nonvar(Att),
( Att \= Attr -> del_attr_non_head(Ls0, Ls1, Attr)
; '$del_attr_head'(V), del_attr(Ls1, V, Attr)
).
del_attr_step(Ls1, Attr) :-
( nonvar(Ls1) -> Ls1 = [_ | Ls2], del_attr_non_head(Ls1, Ls2, Attr)
; true ).
%% assumptions: Ls0 is a list, Ls1 is its tail;
%% the head of Ls0 can be ignored.
del_attr_non_head(Ls0, Ls1, Attr) :-
Ls0 = [_, Att | _],
nonvar(Att),
!,
( Att \= Attr -> del_attr_step(Ls1, Attr)
; '$del_attr'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
del_attr_step(Ls1, Attr)
).
del_attr_non_head(_, _, _).
user:term_expansion(Term0, Terms) :-
nonvar(Term0),
Term0 = (:- attribute Atts),
nonvar(Atts),
phrase(put_attrs_var_check, Terms, Terms1),
phrase(put_attrs(Atts), Terms1, Terms2),
phrase(get_attrs_var_check, Terms2, Terms3),
phrase(get_attrs(Atts), Terms3).
put_attrs_var_check -->
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), put_atts/2))),
(put_atts(Var, Attr) :- var(Attr), throw(error(instantiation_error, put_atts/2)))].
get_attrs_var_check -->
{ numbervars([Var, Attr], 0, _) },
[(get_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), get_atts/2))),
(get_atts(Var, Attr) :- var(Attr), !, '$get_attr_list'(Var, Attr))].
put_attrs(Name/Arity) -->
put_attr(Name, Arity),
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr))].
put_attrs((Name/Arity, Atts)) -->
{ nonvar(Atts) },
put_attr(Name, Arity),
put_attrs(Atts).
get_attrs(Name/Arity) -->
get_attr(Name, Arity).
get_attrs((Name/Arity, Atts)) -->
{ nonvar(Atts) },
get_attr(Name, Arity),
get_attrs(Atts).
put_attr(Name, Arity) -->
{ functor(Attr, Name, Arity),
numbervars(Attr, 0, Arity),
V = '$VAR'(Arity) },
[(put_atts(V, +Attr) :- !, functor(Attr, _, _), put_attr(V, Attr)),
(put_atts(V, Attr) :- !, functor(Attr, _, _), put_attr(V, Attr)),
(put_atts(V, -Attr) :- !, functor(Attr, _, _), '$get_attr_list'(V, Ls), del_attr(Ls, V, Attr))].
get_attr(Name, Arity) -->
{ functor(Attr, Name, Arity),
numbervars(Attr, 0, Arity),
V = '$VAR'(Arity) },
[(get_atts(V, +Attr) :- !, functor(Attr, _, _), get_attr(V, Attr)),
(get_atts(V, Attr) :- !, functor(Attr, _, _), get_attr(V, Attr)),
(get_atts(V, -Attr) :- !, functor(Attr, _, _), absent_attr(V, Attr))].
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
nonvar(Term),
Term = put_atts(Var, M, Attr).
user:goal_expansion(Term, M:get_atts(Var, Attr)) :-
nonvar(Term),
Term = get_atts(Var, M, Attr).