35
36:- module(prolog_operator,
37 [ push_operators/1, 38 push_operators/2, 39 pop_operators/0,
40 pop_operators/1, 41 push_op/3 42 ]).
86:- thread_local
87 operator_stack/1. 88:- '$notransact'(operator_stack/1). 89
90:- meta_predicate
91 push_operators(:),
92 push_operators(:,-),
93 push_op(+,+,:).
102push_operators(New, Undo) :-
103 strip_module(New, Module, Ops0),
104 tag_ops(Ops0, Module, Ops),
105 undo_operators(Ops, Undo),
106 set_operators(Ops).
107
108push_operators(New) :-
109 push_operators(New, Undo),
110 asserta(operator_stack(mark-Undo)).
118push_op(P, T, A) :-
119 undo_operator(op(P,T,A), Undo),
120 op(P, T, A),
121 asserta(operator_stack(incremental-Undo)).
128pop_operators :-
129 retract(operator_stack(Mark-Undo)),
130 set_operators(Undo),
131 Mark == mark,
132 !.
138pop_operators(Undo) :-
139 set_operators(Undo).
140
141tag_ops([], _, []).
142tag_ops([op(P,Tp,N0)|T0], M, [op(P,Tp,N)|T]) :-
143 strip_module(M:N0, M1, N1),
144 N = M1:N1,
145 tag_ops(T0, M, T).
146
147set_operators([]).
148set_operators([H|R]) :-
149 set_operators(H),
150 set_operators(R).
151set_operators(op(P,T,A)) :-
152 op(P, T, A).
153
154undo_operators([], []).
155undo_operators([O0|T0], [U0|T]) :-
156 undo_operator(O0, U0),
157 undo_operators(T0, T).
158
159undo_operator(op(_P, T, N), op(OP, OT, N)) :-
160 current_op(OP, OT, N),
161 same_op_type(T, OT),
162 !.
163undo_operator(op(P, T, [H|R]), [OH|OT]) :-
164 !,
165 undo_operator(op(P, T, H), OH),
166 undo_operator(op(P, T, R), OT).
167undo_operator(op(_, _, []), []) :- !.
168undo_operator(op(_P, T, N), op(0, T, N)).
169
170same_op_type(T, OT) :-
171 op_type(T, Type),
172 op_type(OT, Type).
173
174op_type(fx, prefix).
175op_type(fy, prefix).
176op_type(xfx, infix).
177op_type(xfy, infix).
178op_type(yfx, infix).
179op_type(xf, postfix).
180op_type(yf, postfix)
Manage operators
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:
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.