1 % (c) 2009-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5
6 :- module(typechecker,[type_check/2, term_is_of_type/3,
7 (type)/1, check_types/0,
8 ground_check/1, debug_non_ground_term/1,
9 check_cyclic/1]).
10
11
12 /* ------------------------ */
13 /* TYPE CHECKER FOR PROLOG */
14 /* ------------------------ */
15
16 :- op(1150, fx, type).
17 :- op(500,yfx,+-->).
18
19 :- use_module(tools_printing, [print_error/1]).
20
21 :- use_module(module_information).
22 :- module_info(group,testing).
23 :- module_info(description,'A very basic runtime type checker for Prolog.').
24
25 /*
26 =============================================================================
27 Using the type checker:
28 =============================================================================
29
30 1) Built-in types:
31
32 The following are built-in types:
33 any
34 ground
35 nonground
36 var
37 nonvar
38 integer
39 real
40 number
41 atom
42 atomic
43 ask(Type) [ask user whether of type]
44 call(Module:Predicate) [calls an external unary predicate to check the type]
45
46 The following are built-in type constructors:
47 list/1 -> list(TypeOfListElements)
48 vlist/1 -> same as list/1 except that variables also match this type
49 term/2 -> term(Functor,ListOfTypesForArguments)
50 vterm/2 -> same as term/2 except that variables also match this type
51
52 =============================================================================
53
54 2) Defining your own types:
55
56 just enter type/2 definitions for each type you want to use, like:
57
58 type(program,list(clause)).
59 type(clause,term(cl,[atom,list(atom)])).
60 type(atom,any).
61
62 You can also define your own type constructors:
63
64 type(binary_tree(Type),term(null,[])).
65 type(binary_tree(Type),
66 term(tree,[binary_tree(Type),Type,binary_tree(Type)])).
67
68 =============================================================================
69
70 3) Type checking:
71
72 Just call:
73 term_is_of_type([1,2,3],list(integer)).
74 term_is_of_type(tree(null,1,null),binary_tree(ground)).
75
76 You can also call
77 check_for_illegal_types.
78 to test whether you have introduced some illegal type definitions
79 (it might currently loop for badly defined types like "type(rec,rec)." ).
80 =============================================================================
81 */
82
83 ground_check(X) :- (ground(X) -> true ;
84 print_error('### Not ground: '), print_error(X),nl,debug_non_ground_term(X),fail).
85
86 debug_non_ground_term(X) :- var(X),!, print('-> top level is variable: '), print(X),nl.
87 debug_non_ground_term(X) :- debug_non_ground_term(X,[]).
88
89 debug_non_ground_term(X,_) :- ground(X),!.
90 debug_non_ground_term(X,T) :- X =.. [Fun|Args], l_debug_ng(Args,[Fun|T],1).
91
92 l_debug_ng([],_,_).
93 l_debug_ng([H|T],Hist,NrOfArg) :-
94 (var(H) -> print('--> Arg #'), print(NrOfArg), print(' of '), print(Hist),nl ; debug_non_ground_term(H,Hist)),
95 A1 is NrOfArg+1,
96 l_debug_ng(T,Hist,A1).
97
98 :- dynamic user_defined_type/2.
99 % SHOULD NOT BE VOLATILE !
100
101 type(Type +--> Def) :- assert_user_type(Type,Def),!.
102 type(Type = Def) :- assert_user_type(Type,Def),!.
103 type(TD) :- print_error('### Illegal Type Declaration: '), print_error(TD),nl.
104
105
106 assert_user_type(Type,Def) :-
107 %print_message(add_type(Type,Def)),
108 translate_type_def(Def,TranslatedDef,Type),!,
109 (user_defined_type(Type,OldDef)
110 -> (OldDef = TranslatedDef -> true
111 ; print_error('### Type Clash for: '), print_error(Type),
112 print_error(OldDef), print_error(TranslatedDef)
113 )
114 ; (predefined_type(Type)
115 -> print_error('### Trying to redefine built-in type: '), print_error(Type)
116 ; assert(user_defined_type(Type,TranslatedDef))
117 )
118 ).
119 assert_user_type(Type,Def) :-
120 print_error('### Could not translate type description for type:'),
121 print_error(Type), print_error(Def).
122
123 translate_type_def(X,any,_) :- var(X),!,print_error('### Variable Type !').
124 translate_type_def(call(Module:Call),call(Module:Call),_) :- !.
125 translate_type_def(type(X),X,_) :- !.
126 translate_type_def(list(X),list(TX),Cur) :- !, translate_type_def(X,TX,Cur).
127 translate_type_def(vlist(X),vlist(TX),Cur) :- !, translate_type_def(X,TX,Cur).
128 translate_type_def((X;Y),(TX;TY),Cur) :- !,
129 translate_type_def(X,TX,Cur), translate_type_def(Y,TY,Cur).
130 translate_type_def(term(F,A),term(F,TA),Cur) :- !, l_translate_type_def(A,TA,Cur).
131 translate_type_def(vterm(F,A),vterm(F,TA),Cur) :- !, l_translate_type_def(A,TA,Cur).
132 ?translate_type_def(X,X,CurType) :- (predefined_type(X) ; user_defined_type(X,_) ; X=CurType),!.
133 translate_type_def(X,term(Fun,TArgs),Cur) :- nonvar(X), X =.. [Fun|Args], !,
134 l_translate_type_def(Args,TArgs,Cur).
135 translate_type_def(X,X,_) :-
136 print_message(informational,'*** Forward type reference'), print_message(informational,X).
137
138 l_translate_type_def([],[],_Cur).
139 l_translate_type_def([A|T],[AT|TT],Cur) :-
140 translate_type_def(A,AT,Cur), l_translate_type_def(T,TT,Cur).
141
142 /* ----------------- */
143 /* predefined_type/1 */
144 /* ----------------- */
145
146 /* checks whether something is a predefined type */
147
148 predefined_type(any).
149 predefined_type(ground).
150 predefined_type(nonground).
151 predefined_type(var).
152 predefined_type(nonvar).
153 predefined_type(integer).
154 predefined_type(real).
155 predefined_type(number).
156 predefined_type(atom).
157 predefined_type(atomic).
158 predefined_type(list(_X)).
159 predefined_type(term(_F,_TL)).
160 predefined_type(vlist(_X)).
161 predefined_type(vterm(_F,_TL)).
162 predefined_type(ask(_T)).
163 predefined_type(call(_)).
164
165 /* ------------------------ */
166
167 :- public print_types/0.
168 print_types :- print_message(informational,'---------'),user_defined_type(Type,Descr),
169 print_message(informational,type(Type,Descr)),fail.
170 print_types :- print_message(informational,'---------').
171
172 /* ------------------------ */
173 /* legal_type_description/1 */
174 /* ------------------------ */
175
176 /* checks whether something is a legal type description */
177
178 check_types :- % print('% Checking user defined types: '),
179 user_defined_type(Type,Descr),
180 (legal_type_description(Descr) -> true %,(print(Type),print(' '))
181 ; print_error('### Error in type definition:'), print_error(Type),
182 print_error(Descr)),
183 fail.
184 check_types :- % print('% Checking user defined types: '),
185 user_defined_type(Type,Descr), user_defined_type(Type,Descr2),
186 Descr \= Descr2,
187 print_error('### Multiple Definitions for type:'), print_error(Type),
188 fail.
189 check_types. % :- nl.
190
191 legal_type_description(X) :- var(X),!,fail.
192 legal_type_description(any) :- !.
193 legal_type_description(ground) :- !.
194 legal_type_description(nonground) :- !.
195 legal_type_description(var) :- !.
196 legal_type_description(nonvar) :- !.
197 legal_type_description(integer) :- !.
198 legal_type_description(real) :- !.
199 legal_type_description(number) :- !.
200 legal_type_description(atom) :- !.
201 legal_type_description(atomic) :- !.
202 legal_type_description(ask(_Type)) :- !.
203 legal_type_description(call(Call)) :- Call=Module:Pred,atomic(Module),atomic(Pred),!.
204 legal_type_description(list(Type)) :- !,
205 legal_type_description(Type).
206 legal_type_description(vlist(Type)) :- !,
207 legal_type_description(Type).
208 legal_type_description(term(Functor,TypeList)) :- !,
209 ((length(TypeList,Arity),functor(T,Functor,Arity),
210 user_defined_type(T,_))
211 -> print_message(informational,'*** Warning: term also exists as type:'), print_message(informational,T)
212 ; true
213 ),
214 l_legal_type_description(TypeList).
215 legal_type_description(vterm(_Functor,TypeList)) :- !,
216 l_legal_type_description(TypeList).
217 legal_type_description((Type1 ; Type2)) :- !,
218 legal_type_description(Type1),!,legal_type_description(Type2).
219 legal_type_description(Type) :-
220 \+(predefined_type(Type)),
221 user_defined_type(Type,_Descr),!.
222 legal_type_description(type(Type)) :- !,print_error('### Illegal type descriptor: '),
223 print('### type/1 can only be used in type definitions'),
224 print_error(Type),fail.
225 legal_type_description(Type) :- print_error('### Illegal type descriptor: '),
226 print_error(Type),fail.
227
228 l_legal_type_description([]).
229 l_legal_type_description([Type1|Rest]) :-
230 legal_type_description(Type1),
231 l_legal_type_description(Rest).
232
233
234 /* ----------------- */
235 /* term_is_of_type/2 */
236 /* ----------------- */
237
238 type_check(Term,Type) :- %print_message(type_check(Term,Type)),
239 reset_type_error,
240 (term_is_of_type(Term,Type,yes)
241 -> \+(type_error_occurred)
242 ; \+(type_error_occurred), print_type_error(Term,Type,yes,type_check),fail).
243
244
245 /* ----------------- */
246 /* term_is_of_type/3 */
247 /* ----------------- */
248
249 /* if the third argument is yes then an error message is printed if the
250 type check does not succeed and the call to term_is_of_type
251 will NEVER FAIL !! */
252 /* if the third argument is different from yes than no message will be printed
253 but the call will fail if the type check fails */
254
255 /* term_is_of_type(Term,Descr,PE) :-
256 print(tiot(Term,Descr)),nl,fail. */
257
258 term_is_of_type(Term,Descr,PrintErrMsg) :-
259 is_inf(Term),!,
260 print_inf_error(Term,Descr,PrintErrMsg),
261 read(_Cont).
262
263 term_is_of_type(_Term,any,_PrintErrMsg) :-
264 !. /* anything is of type any */
265 term_is_of_type(Term,ground,_PrintErrMsg) :-
266 ground(Term),!.
267 term_is_of_type(Term,nonground,_PrintErrMsg) :-
268 \+(ground(Term)),!.
269 term_is_of_type(Term,var,_PrintErrMsg) :-
270 var(Term),!.
271 term_is_of_type(Term,nonvar,_PrintErrMsg) :-
272 nonvar(Term),!.
273 term_is_of_type(Term,integer,_PrintErrMsg) :-
274 integer(Term),!.
275 term_is_of_type(Term,real,_PrintErrMsg) :-
276 float(Term),!.
277 term_is_of_type(Term,number,_PrintErrMsg) :-
278 number(Term),!.
279 term_is_of_type(Term,atom,_PrintErrMsg) :-
280 atom(Term),!.
281 term_is_of_type(Term,atomic,_PrintErrMsg) :-
282 atomic(Term),!.
283 term_is_of_type(Term,ask(Type),_PrintErrMsg) :-
284 !,
285 print('Type => '),print(Type),nl,
286 print('Term => '),print(Term),nl,
287 print('(y or n) =>'),read(UserChoice),
288 UserChoice=y.
289 term_is_of_type(Term,call(Module:Predicate),_PrintErrMsg) :-
290 functor(Call,Predicate,1),
291 arg(1,Call,Term),
292 call(Module:Call).
293 term_is_of_type(Term,list(Type),PrintErrMsg) :-
294 var(Term),!,
295 print_type_error(Term,list(Type),PrintErrMsg,term_is_of_type).
296 term_is_of_type([],list(_Type),_PrintErrMsg) :- !.
297 term_is_of_type([Head|Tail],list(Type),PrintErrMsg) :-
298 term_is_of_type(Head,Type,PrintErrMsg),!,
299 term_is_of_type(Tail,list(Type),yes).
300 term_is_of_type(Term,vlist(_Type),_PrintErrMsg) :-
301 var(Term),!. /* also to avoid modifying Term in the next 2 clauses */
302 term_is_of_type([],vlist(_Type),_PrintErrMsg) :- !.
303 term_is_of_type([Head|Tail],vlist(Type),PrintErrMsg) :-
304 term_is_of_type(Head,Type,PrintErrMsg),!,
305 term_is_of_type(Tail,vlist(Type),yes).
306 term_is_of_type(Term,term(Functor,ArgTypeList),PrintErrMsg) :-
307 var(Term),!,
308 print_type_error(Term,term(Functor,ArgTypeList),PrintErrMsg,term_is_of_type_var).
309 term_is_of_type(Term,term(Functor,ArgTypeList),_PrintErrMsg) :-
310 Term =.. [Functor|Args],!,
311 l_term_is_of_type(Args,ArgTypeList,yes), !.
312 term_is_of_type(Term,vterm(_Functor,_ArgTypeList),_PrintErrMsg) :-
313 var(Term),!. /* also to avoid modifying Term in the next clause */
314 term_is_of_type(Term,vterm(Functor,ArgTypeList),_PrintErrMsg) :-
315 Term =.. [Functor|Args],!,
316 l_term_is_of_type(Args,ArgTypeList,yes), !.
317 term_is_of_type(Term,Type,PrintErrMsg) :-
318 \+(predefined_type(Type)),
319 user_defined_type(Type,Descr), /* user defined type; we assume single definition exists */
320 !,
321 term_is_of_type(Term,Descr,PrintErrMsg).
322 term_is_of_type(Term,(Type1 ; Type2),PrintErrMsg) :-
323 (term_is_of_type(Term,Type1,no) -> true
324 ; term_is_of_type(Term,Type2,PrintErrMsg)),
325 !.
326 term_is_of_type(Term,Type,PrintErrMsg) :-
327 print_type_error(Term,Type,PrintErrMsg,term_is_of_type_catchall).
328
329
330 l_term_is_of_type([],[],_PrintErrMsg).
331 l_term_is_of_type([Term1|Rest],[Type1|TypeList],PrintErrMsg) :-
332 term_is_of_type(Term1,Type1,PrintErrMsg),!,
333 l_term_is_of_type(Rest,TypeList,PrintErrMsg).
334
335 print_type_error(T,Type,_,PP) :-
336 (legal_type_description(Type) -> true
337 ; print_error(pp(PP)),print_error(illegal_type(Type)),print_error(term(T))),
338 fail.
339 print_type_error(Term,Type,PrintErrMsg,PP) :- PrintErrMsg\=no, nl,
340 %print(err(Term,Type)),nl,nl,
341 print_error('### Type Error Occured! Type:'),print_error(Type),
342 print_error('### Term:'),safe_print_term(Term),nl,
343 print_error('### ProgramPoint:'),safe_print_term(PP),nl,
344 assert_type_error.
345
346
347 print_inf_error(Term,Type,PrintErrMsg) :- PrintErrMsg \= no, nl,
348 print_error('### Cyclic Term Error: Requested Type '),print_error(Type),
349 print_error('### Term: '),safe_print_term(Term),nl,
350 assert_type_error.
351
352 safe_print_term(X) :- var(X),!,print(X).
353 safe_print_term(X) :- is_inf(X),!,
354 X =.. [Func|Args],
355 print(Func),print('('),
356 l_safe_print(Args),
357 print(')').
358 safe_print_term(X) :- print(X).
359
360 l_safe_print([]).
361 l_safe_print([Term|T]) :-
362 (is_inf(Term)
363 -> (print('!CYCLIC!('),write_term(Term,[max_depth(3)]),print(')'))
364 ; (print(Term))
365 ),
366 ((T=[]) -> true ; print(',') ),
367 l_safe_print(T).
368
369 :- dynamic type_error/1.
370 type_error(no).
371
372 assert_type_error :-
373 retract(type_error(_N)),fail.
374 assert_type_error :-
375 assert(type_error(yes)).
376
377
378 reset_type_error :-
379 retract(type_error(_N)),fail.
380 reset_type_error :-
381 assert(type_error(no)).
382
383 type_error_occurred :-
384 type_error(yes).
385
386
387
388 :- use_module(library(terms)).
389 is_inf(X) :- cyclic_term(X).
390
391 check_cyclic(X) :- cyclic_term(X),!,
392 print('### Cyclic Term : '), nl,
393 safe_print_term(X),nl,
394 fail.
395 check_cyclic(_).