200 lines
4.9 KiB
Prolog
200 lines
4.9 KiB
Prolog
/* $Id: operators.pl,v 1.1 2008-02-12 17:03:53 vsc Exp $
|
|
|
|
Part of SWI-Prolog
|
|
|
|
Author: Jan Wielemaker
|
|
E-mail: jan@swi.psy.uva.nl
|
|
WWW: http://www.swi-prolog.org
|
|
Copyright (C): 1985-2004, University of Amsterdam
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
As a special exception, if you link this library with other files,
|
|
compiled with a Free Software compiler, to produce an executable, this
|
|
library does not by itself cause the resulting executable to be covered
|
|
by the GNU General Public License. This exception does not however
|
|
invalidate any other reasons why the executable file might be covered by
|
|
the GNU General Public License.
|
|
*/
|
|
|
|
|
|
:- module(prolog_operator,
|
|
[ push_operators/1, % +List
|
|
push_operators/2, % +List, -Undo
|
|
pop_operators/0,
|
|
pop_operators/1, % +Undo
|
|
push_op/3 % Precedence, Type, Name
|
|
]).
|
|
|
|
|
|
/** <module> Manage operators
|
|
@ingroup swi
|
|
|
|
Often, one wants to define operators to improve the readibility of some
|
|
very specific code. Operators in Prolog are global objects and changing
|
|
operators changes syntax and possible semantics of existing sources. For
|
|
this reason it is desirable to reset operator declarations after the
|
|
code that needs them has been read. This module defines a rather cruel
|
|
-but portable- method to do this.
|
|
|
|
Usage:
|
|
|
|
==
|
|
:- push_operators(
|
|
[ op(900, fx, hello_world)
|
|
, op(600, xf, *)
|
|
]).
|
|
|
|
hello_world World :-
|
|
....
|
|
|
|
:- pop_operators.
|
|
==
|
|
|
|
While the above are for source-code, the calls push_operators/2 and
|
|
pop_operators/1 can be used for local processing where it is more
|
|
comfortable to carry the undo context around.
|
|
|
|
NOTE: In recent versions of SWI-Prolog operators are local to a module
|
|
and can be exported using the syntax below. This is not portable, but
|
|
otherwise a more structured approach for operator handling.
|
|
|
|
==
|
|
:- module(mymodule,
|
|
[ mypred/1,
|
|
op(500, fx, myop)
|
|
]).
|
|
==
|
|
|
|
@compat SWI-Prolog
|
|
*/
|
|
|
|
:- thread_local
|
|
operator_stack/1.
|
|
|
|
:- module_transparent
|
|
push_operators/1,
|
|
push_operators/2,
|
|
push_op/3.
|
|
|
|
%% push_operators(:New) is det.
|
|
%% push_operators(:New, -Undo) is det.
|
|
%
|
|
% Installs the operators from New, where New is a list of op(Prec,
|
|
% Type, :Name). The modifications to the operator table are undone
|
|
% in a matching call to pop_operators/0.
|
|
|
|
push_operators(New, Undo) :-
|
|
strip_module(New, Module, Ops0),
|
|
tag_ops(Ops0, Module, Ops),
|
|
undo_operators(Ops, Undo),
|
|
set_operators(Ops).
|
|
|
|
push_operators(New) :-
|
|
push_operators(New, Undo),
|
|
assert_op(mark),
|
|
assert_op(Undo).
|
|
|
|
%% push_op(+Precedence, +Type, :Name) is det.
|
|
%
|
|
% As op/3, but this call must appear between push_operators/1 and
|
|
% pop_operators/0. The change is undone by the call to
|
|
% pop_operators/0
|
|
|
|
push_op(P, T, A0) :-
|
|
( A0 = _:_
|
|
-> A = A0
|
|
; context_module(M),
|
|
A = M:A0
|
|
),
|
|
undo_operator(op(P,T,A), Undo),
|
|
assert_op(Undo),
|
|
op(P, T, A).
|
|
|
|
%% pop_operators is det.
|
|
%
|
|
% Revert all changes to the operator table realised since the last
|
|
% push_operators/1.
|
|
|
|
pop_operators :-
|
|
retract_op(Undo),
|
|
( Undo == mark
|
|
-> !
|
|
; set_operators(Undo),
|
|
fail
|
|
).
|
|
|
|
%% pop_operators(+Undo) is det.
|
|
%
|
|
% Reset operators as pushed by push_operators/2.
|
|
|
|
pop_operators(Undo) :-
|
|
set_operators(Undo).
|
|
|
|
tag_ops([], _, []).
|
|
tag_ops([op(P,Tp,N0)|T0], M, [op(P,Tp,N)|T]) :-
|
|
( N0 = _:_
|
|
-> N = N0
|
|
; N = M:N0
|
|
),
|
|
tag_ops(T0, M, T).
|
|
|
|
set_operators([]).
|
|
set_operators([H|R]) :-
|
|
set_operators(H),
|
|
set_operators(R).
|
|
set_operators(op(P,T,A)) :-
|
|
op(P, T, A).
|
|
|
|
undo_operators([], []).
|
|
undo_operators([O0|T0], [U0|T]) :-
|
|
undo_operator(O0, U0),
|
|
undo_operators(T0, T).
|
|
|
|
undo_operator(op(_P, T, N), op(OP, OT, N)) :-
|
|
current_op(OP, OT, N),
|
|
same_op_type(T, OT), !.
|
|
undo_operator(op(P, T, [H|R]), [OH|OT]) :- !,
|
|
undo_operator(op(P, T, H), OH),
|
|
undo_operator(op(P, T, R), OT).
|
|
undo_operator(op(_, _, []), []) :- !.
|
|
undo_operator(op(_P, T, N), op(0, T, N)).
|
|
|
|
same_op_type(T, OT) :-
|
|
op_type(T, Type),
|
|
op_type(OT, Type).
|
|
|
|
op_type(fx, prefix).
|
|
op_type(fy, prefix).
|
|
op_type(xfx, infix).
|
|
op_type(xfy, infix).
|
|
op_type(yfx, infix).
|
|
op_type(yfy, infix).
|
|
op_type(xf, postfix).
|
|
op_type(yf, postfix).
|
|
|
|
%% assert_op(+Term) is det.
|
|
%% retract_op(-Term) is det.
|
|
%
|
|
% Force local assert/retract.
|
|
|
|
assert_op(Term) :-
|
|
asserta(operator_stack(Term)).
|
|
|
|
retract_op(Term) :-
|
|
retract(operator_stack(Term)).
|
|
|
|
|