37
38:- module('$autoload',
39 [ '$find_library'/5,
40 '$in_library'/3,
41 '$define_predicate'/1,
42 '$update_library_index'/1, 43 '$autoload'/1,
44
45 make_library_index/1,
46 make_library_index/2,
47 reload_library_index/0,
48 autoload_path/1,
49
50 autoload/1, 51 autoload/2, 52
53 autoload_call/1, 54
55 require/1 56 ]). 57
58:- meta_predicate
59 '$autoload'(:),
60 autoload(:),
61 autoload(:, +),
62 autoload_call(0),
63 require(:). 64
65:- dynamic
66 library_index/3, 67 autoload_directories/1, 68 index_checked_at/1. 69:- volatile
70 library_index/3,
71 autoload_directories/1,
72 index_checked_at/1. 73
74user:file_search_path(autoload, swi(library)).
75user:file_search_path(autoload, pce(prolog/lib)).
76user:file_search_path(autoload, app_config(lib)).
77user:file_search_path(autoload, Dir) :-
78 '$ext_library_directory'(Dir).
79
80:- create_prolog_flag(warn_autoload, false, []). 81
89
90'$find_library'(_Module, :, 2, _LoadModule, _Library) :-
91 !, fail.
92'$find_library'(Module, Name, Arity, LoadModule, Library) :-
93 load_library_index(Name, Arity),
94 functor(Head, Name, Arity),
95 ( library_index(Head, Module, Library),
96 LoadModule = Module
97 ; library_index(Head, LoadModule, Library)
98 ),
99 !.
100
105
106'$in_library'(Name, Arity, Path) :-
107 atom(Name), integer(Arity),
108 !,
109 Name/Arity \= (:)/2,
110 load_library_index(Name, Arity),
111 functor(Head, Name, Arity),
112 library_index(Head, _, Path).
113'$in_library'(Name, Arity, Path) :-
114 load_library_index(Name, Arity),
115 library_index(Head, _, Path),
116 Head \= _:_,
117 functor(Head, Name, Arity).
118
123
124:- meta_predicate
125 '$define_predicate'(:). 126
127'$define_predicate'(Head) :-
128 '$defined_predicate'(Head),
129 !.
130'$define_predicate'(Term) :-
131 Term = Module:Head,
132 ( compound(Head)
133 -> compound_name_arity(Head, Name, Arity)
134 ; Name = Head, Arity = 0
135 ),
136 '$undefined_procedure'(Module, Name, Arity, retry).
137
138
139 142
143:- thread_local
144 silent/0. 145
157
158'$update_library_index'(Options) :-
159 setof(Dir, writable_indexed_directory(Dir, Options), Dirs),
160 !,
161 setup_call_cleanup(
162 asserta(silent, Ref),
163 guarded_make_library_index(Dirs),
164 erase(Ref)),
165 ( flag('$modified_index', true, false)
166 -> reload_library_index
167 ; true
168 ).
169'$update_library_index'(_).
170
171guarded_make_library_index([]).
172guarded_make_library_index([Dir|Dirs]) :-
173 ( catch(make_library_index(Dir), E,
174 print_message(error, E))
175 -> true
176 ; print_message(warning, goal_failed(make_library_index(Dir)))
177 ),
178 guarded_make_library_index(Dirs).
179
184
185writable_indexed_directory(Dir, Options) :-
186 current_prolog_flag(home, Home),
187 writable_indexed_directory(Dir),
188 ( sub_atom(Dir, 0, _, _, Home)
189 -> '$option'(system(true), Options, false)
190 ; '$option'(user(true), Options, true)
191 ).
192
193writable_indexed_directory(Dir) :-
194 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]),
195 file_directory_name(IndexFile, Dir).
196writable_indexed_directory(Dir) :-
197 absolute_file_name(library('MKINDEX'),
198 [ file_type(prolog),
199 access(read),
200 solutions(all),
201 file_errors(fail)
202 ], MkIndexFile),
203 file_directory_name(MkIndexFile, Dir),
204 plfile_in_dir(Dir, 'INDEX', _, IndexFile),
205 access_file(IndexFile, write).
206
207
208 211
215
216reload_library_index :-
217 context_module(M),
218 reload_library_index(M).
219
220reload_library_index(M) :-
221 with_mutex('$autoload', clear_library_index(M)).
222
223clear_library_index(M) :-
224 retractall(M:library_index(_, _, _)),
225 retractall(M:autoload_directories(_)),
226 retractall(M:index_checked_at(_)).
227
228
235
236:- meta_predicate load_library_index(?, ?, :). 237:- public load_library_index/3. 238
239load_library_index(Name, Arity) :-
240 load_library_index(Name, Arity, autoload('INDEX')).
241
242load_library_index(Name, Arity, M:_Spec) :-
243 atom(Name), integer(Arity),
244 functor(Head, Name, Arity),
245 M:library_index(Head, _, _),
246 !.
247load_library_index(_, _, Spec) :-
248 notrace(with_mutex('$autoload', load_library_index_p(Spec))).
249
250load_library_index_p(M:_) :-
251 M:index_checked_at(Time),
252 get_time(Now),
253 Now-Time < 60,
254 !.
255load_library_index_p(M:Spec) :-
256 findall(Index, index_file_name(Index, Spec, [access(read)]), List0),
257 '$list_to_set'(List0, List),
258 retractall(M:index_checked_at(_)),
259 get_time(Now),
260 assert(M:index_checked_at(Now)),
261 ( M:autoload_directories(List)
262 -> true
263 ; retractall(M:library_index(_, _, _)),
264 retractall(M:autoload_directories(_)),
265 read_index(List, M),
266 assert(M:autoload_directories(List))
267 ).
268
276
277index_file_name(IndexFile, FileSpec, Options) :-
278 absolute_file_name(FileSpec,
279 IndexFile,
280 [ file_type(prolog),
281 solutions(all),
282 file_errors(fail)
283 | Options
284 ]).
285
286read_index([], _) :- !.
287read_index([H|T], M) :-
288 !,
289 read_index(H, M),
290 read_index(T, M).
291read_index(Index, M) :-
292 print_message(silent, autoload(read_index(Dir))),
293 file_directory_name(Index, Dir),
294 setup_call_cleanup(
295 '$push_input_context'(autoload_index),
296 setup_call_cleanup(
297 win_open_index(Index, In),
298 read_index_from_stream(Dir, In, M),
299 close(In)),
300 '$pop_input_context').
301
306
307:- if(current_prolog_flag(windows, true)). 308win_open_index(Index, In) :-
309 between(1, 10, _),
310 catch(open(Index, read, In, [encoding(utf8)]),
311 error(permission_error(open, source_sink, _),_), (sleep(0.1),fail)),
312 !.
313:- endif. 314win_open_index(Index, In) :-
315 open(Index, read, In, [encoding(utf8)]).
316
317read_index_from_stream(Dir, In, M) :-
318 repeat,
319 read(In, Term),
320 assert_index(Term, Dir, M),
321 !.
322
323assert_index(end_of_file, _, _) :- !.
324assert_index(index(Term, Module, File), Dir, M) :-
325 !,
326 atomic_list_concat([Dir, '/', File], Path),
327 assertz(M:library_index(Term, Module, Path)),
328 fail.
329assert_index(index(Name, Arity, Module, File), Dir, M) :-
330 !, 331 functor(Head, Name, Arity),
332 head_meta_any(Head),
333 assert_index(index(Head, Module, File), Dir, M).
334assert_index(Term, Dir, _) :-
335 print_message(error, illegal_autoload_index(Dir, Term)),
336 fail.
337
338
339 342
353
354make_library_index(Dir0) :-
355 forall(absolute_file_name(Dir0, Dir,
356 [ expand(true),
357 file_type(directory),
358 file_errors(fail),
359 solutions(all)
360 ]),
361 make_library_index2(Dir)).
362
363make_library_index2(Dir) :-
364 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex),
365 access_file(AbsMkIndex, read),
366 !,
367 load_files(user:AbsMkIndex, [silent(true)]).
368make_library_index2(Dir) :-
369 findall(Pattern, source_file_pattern(Pattern), PatternList),
370 make_library_index2(Dir, PatternList).
371
384
385make_library_index(Dir0, Patterns) :-
386 forall(absolute_file_name(Dir0, Dir,
387 [ expand(true),
388 file_type(directory),
389 file_errors(fail),
390 solutions(all)
391 ]),
392 make_library_index2(Dir, Patterns)).
393
394make_library_index2(Dir, Patterns) :-
395 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex),
396 ensure_slash(Dir, DirS),
397 pattern_files(Patterns, DirS, Files),
398 ( library_index_out_of_date(Dir, AbsIndex, Files)
399 -> do_make_library_index(AbsIndex, DirS, Files),
400 set_flag('$modified_index', true)
401 ; true
402 ).
403
404ensure_slash(Dir, DirS) :-
405 ( sub_atom(Dir, _, _, 0, /)
406 -> DirS = Dir
407 ; atom_concat(Dir, /, DirS)
408 ).
409
410source_file_pattern(Pattern) :-
411 user:prolog_file_type(PlExt, prolog),
412 PlExt \== qlf,
413 atom_concat('*.', PlExt, Pattern).
414
415plfile_in_dir(Dir, Base, PlBase, File) :-
416 file_name_extension(Base, pl, PlBase),
417 atomic_list_concat([Dir, '/', PlBase], File).
418
419pattern_files([], _, []).
420pattern_files([H|T], DirS, Files) :-
421 atom_concat(DirS, H, P0),
422 expand_file_name(P0, Files0),
423 '$append'(Files0, Rest, Files),
424 pattern_files(T, DirS, Rest).
425
426library_index_out_of_date(_Dir, Index, _Files) :-
427 \+ exists_file(Index),
428 !.
429library_index_out_of_date(Dir, Index, Files) :-
430 time_file(Index, IndexTime),
431 ( time_file(Dir, DotTime),
432 DotTime - IndexTime > 0.001 433 ; '$member'(File, Files), 434 time_file(File, FileTime),
435 FileTime - IndexTime > 0.001
436 ),
437 !.
438
439
440do_make_library_index(Index, Dir, Files) :-
441 ensure_slash(Dir, DirS),
442 '$stage_file'(Index, StagedIndex),
443 setup_call_catcher_cleanup(
444 open(StagedIndex, write, Out),
445 ( print_message(informational, make(library_index(Dir))),
446 index_header(Out),
447 index_files(Files, DirS, Out)
448 ),
449 Catcher,
450 install_index(Out, Catcher, StagedIndex, Index)).
451
452install_index(Out, Catcher, StagedIndex, Index) :-
453 catch(close(Out), Error, true),
454 ( silent
455 -> OnError = silent
456 ; OnError = error
457 ),
458 ( var(Error)
459 -> TheCatcher = Catcher
460 ; TheCatcher = exception(Error)
461 ),
462 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
463
467
468index_files([], _, _).
469index_files([File|Files], DirS, Fd) :-
470 ( catch(exports(File, Module, Exports, Meta, Public), E,
471 print_message(warning, E)),
472 nonvar(Module)
473 -> atom_concat(DirS, Local, File),
474 file_name_extension(Base, _, Local),
475 forall(index_term(Exports, Meta, Public, Term),
476 format(Fd, 'index(~k, ~k, ~k).~n',
477 [Term, Module, Base]))
478 ; true
479 ),
480 index_files(Files, DirS, Fd).
481
482index_term(Exports, Meta, _Public, Term) :-
483 '$member'(Export, Exports),
484 ground(Export),
485 export_term(Export, Meta, Term).
486index_term(_Exports, _Meta, Publics, (public):Head) :-
487 '$member'(Public, Publics),
488 '$pi_head'(Public, Head).
489
490export_term(Op, _Meta, Term) :-
491 Op = op(_Pri,_Type,_Name),
492 !,
493 Term = op:Op.
494export_term(PI, Meta, Head) :-
495 '$pi_head'(PI, Head),
496 ( '$member'(Head, Meta)
497 -> true
498 ; head_meta_any(Head)
499 ).
500
501head_meta_any(Head) :-
502 ( atom(Head)
503 -> true
504 ; compound_name_arguments(Head, _, Args),
505 meta_any(Args)
506 ).
507
508meta_any([]).
509meta_any([?|T]) :-
510 meta_any(T).
511
(Fd):-
513 format(Fd, '/* Creator: make/0~n~n', []),
514 format(Fd, ' Purpose: Provide index for autoload~n', []),
515 format(Fd, '*/~n~n', []).
516
524
525:- public exports/3. 526exports(File, Module, Exports) :-
527 exports(File, Module, Exports, _Meta, _Public).
528
529exports(File, Module, Exports, Meta, Public) :-
530 ( current_prolog_flag(xref, Old)
531 -> true
532 ; Old = false
533 ),
534 setup_call_cleanup(
535 set_prolog_flag(xref, true),
536 snapshot(exports_(File, Module, Exports, Meta, Public)),
537 set_prolog_flag(xref, Old)).
538
539exports_(File, Module, Exports, Meta, Public) :-
540 State = state(true, _, [], [], []),
541 ( '$source_term'(File,
542 _Read,_RLayout,
543 Term,_TermLayout,
544 _Stream,
545 [ syntax_errors(quiet)
546 ]),
547 ( Term = (:- module(M,ModuleExports)),
548 is_list(ModuleExports),
549 arg(1, State, true)
550 -> nb_setarg(1, State, false),
551 nb_setarg(2, State, M),
552 nb_setarg(3, State, ModuleExports),
553 fail
554 ; nb_setarg(1, State, false),
555 fail
556 ; Term = (:- export(Export))
557 -> phrase(export_pi(Export), PIs),
558 arg(3, State, E0),
559 '$append'(E0, PIs, E1),
560 nb_setarg(3, State, E1),
561 fail
562 ; Term = (:- public(Public))
563 -> phrase(export_pi(Public), PIs),
564 arg(5, State, E0),
565 '$append'(E0, PIs, E1),
566 nb_setarg(5, State, E1),
567 fail
568 ; Term = (:- meta_predicate(Heads)),
569 phrase(meta(Heads), M1),
570 arg(4, State, M0),
571 '$append'(M0, M1, M2),
572 nb_setarg(4, State, M2)
573 ; Term = (:- use_foreign_library(Lib)),
574 nonvar(Lib),
575 arg(2, State, M),
576 atom(M)
577 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
578 fail
579 ; Term = (:- Directive),
580 nonvar(Directive)
581 -> fail
582 ; Term == [] 583 -> fail
584 ; !
585 )
586 ; true
587 ),
588 arg(2, State, Module),
589 arg(3, State, Exports),
590 arg(4, State, Meta),
591 arg(5, State, Public).
592
593export_pi(Var) -->
594 { var(Var) },
595 !.
596export_pi((A,B)) -->
597 !,
598 export_pi(A),
599 export_pi(B).
600export_pi(PI) -->
601 { ground(PI) },
602 [PI].
603
604meta(Var) -->
605 { var(Var) },
606 !.
607meta((A,B)) -->
608 !,
609 meta(A),
610 meta(B).
611meta(Head) -->
612 { callable(Head) },
613 [Head].
614
615
616 619
634
635autoload_path(Alias) :-
636 ( user:file_search_path(autoload, Alias)
637 -> true
638 ; assertz(user:file_search_path(autoload, Alias)),
639 reload_library_index
640 ).
641
642system:term_expansion((:- autoload_path(Alias)),
643 [ user:file_search_path(autoload, Alias),
644 (:- reload_library_index)
645 ]).
646
647
648 651
659
660'$autoload'(PI) :-
661 source_location(File, _Line),
662 !,
663 setup_call_cleanup(
664 '$start_aux'(File, Context),
665 '$autoload2'(PI),
666 '$end_aux'(File, Context)).
667'$autoload'(PI) :-
668 '$autoload2'(PI).
669
670'$autoload2'(PI) :-
671 setup_call_cleanup(
672 leave_sandbox(Old),
673 '$autoload3'(PI),
674 restore_sandbox(Old)).
675
676leave_sandbox(Sandboxed) :-
677 current_prolog_flag(sandboxed_load, Sandboxed),
678 set_prolog_flag(sandboxed_load, false).
679restore_sandbox(Sandboxed) :-
680 set_prolog_flag(sandboxed_load, Sandboxed).
681
682'$autoload3'(PI) :-
683 autoload_from(PI, LoadModule, FullFile),
684 do_autoload(FullFile, PI, LoadModule).
685
690
691autoload_from(Module:PI, LoadModule, FullFile) :-
692 autoload_in(Module, explicit),
693 current_autoload(Module:File, Ctx, import(Imports)),
694 memberchk(PI, Imports),
695 library_info(File, Ctx, FullFile, LoadModule, Exports),
696 ( pi_in_exports(PI, Exports)
697 -> !
698 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
699 fail
700 ).
701autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
702 autoload_in(Module, explicit),
703 PI = Name/Arity,
704 current_autoload(Module:File, Ctx, all),
705 library_info(File, Ctx, FullFile, LoadModule, Exports),
706 pi_in_exports(PI, Exports).
707autoload_from(Module:Name/Arity, LoadModule, Library) :-
708 autoload_in(Module, general),
709 '$find_library'(Module, Name, Arity, LoadModule, Library).
710
711:- public autoload_in/2. 712
713autoload_in(Module, How) :-
714 current_prolog_flag(autoload, AutoLoad),
715 autoload_in(AutoLoad, How, Module),
716 !.
717
719
720autoload_in(true, _, _).
721autoload_in(explicit, explicit, _).
722autoload_in(user, _, user).
723autoload_in(user_or_explicit, explicit, _).
724autoload_in(user_or_explicit, _, user).
725
726
742
743do_autoload(Library, Module:Name/Arity, LoadModule) :-
744 functor(Head, Name, Arity),
745 '$update_autoload_level'([autoload(true)], Old),
746 verbose_autoload(Module:Name/Arity, Library),
747 loadable_file(Library, File),
748 '$compilation_mode'(OldComp, database),
749 ( Module == LoadModule
750 -> ensure_loaded(Module:File)
751 ; ( '$c_current_predicate'(_, LoadModule:Head),
752 '$get_predicate_attribute'(LoadModule:Head, defined, 1),
753 \+ '$loading'(Library)
754 -> Module:import(LoadModule:Name/Arity)
755 ; use_module(Module:File, [Name/Arity])
756 ),
757 warn_autoload(Module, LoadModule:Name/Arity)
758 ),
759 '$set_compilation_mode'(OldComp),
760 '$set_autoload_level'(Old),
761 '$c_current_predicate'(_, Module:Head).
762
763loadable_file(PlFile, File) :-
764 exists_file(PlFile), !,
765 File = PlFile.
766loadable_file(PlFile, Base) :-
767 file_name_extension(Base, pl, PlFile),
768 !.
769loadable_file(File, File).
770
771verbose_autoload(PI, Library) :-
772 current_prolog_flag(verbose_autoload, true),
773 !,
774 set_prolog_flag(verbose_autoload, false),
775 print_message(informational, autoload(PI, Library)),
776 set_prolog_flag(verbose_autoload, true).
777verbose_autoload(PI, Library) :-
778 print_message(silent, autoload(PI, Library)).
779
783
784autoload_call(Goal) :-
785 '$pi_head'(PI, Goal),
786 ( current_predicate(PI)
787 -> true
788 ; '$autoload'(PI)
789 ),
790 call(Goal).
791
797
798:- public 799 autoloadable/2. 800
801autoloadable(M:Head, FullFile) :-
802 atom(M),
803 current_module(M),
804 autoload_in(M, explicit),
805 ( callable(Head)
806 -> goal_name_arity(Head, Name, Arity),
807 autoload_from(M:Name/Arity, _, FullFile)
808 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
809 ( '$member'(M:Head-FullFile, Pairs)
810 ; current_autoload(M:File, Ctx, all),
811 library_info(File, Ctx, FullFile, _, Exports),
812 '$member'(PI, Exports),
813 '$pi_head'(PI, Head),
814 \+ memberchk(M:Head-_, Pairs)
815 )
816 ).
817autoloadable(M:Head, FullFile) :-
818 ( var(M)
819 -> autoload_in(any, general)
820 ; autoload_in(M, general)
821 ),
822 ( callable(Head)
823 -> goal_name_arity(Head, Name, Arity),
824 ( '$find_library'(_, Name, Arity, _, FullFile)
825 -> true
826 )
827 ; '$in_library'(Name, Arity, autoload),
828 functor(Head, Name, Arity)
829 ).
830
831
832autoloadable_2(M:Head, FullFile) :-
833 current_autoload(M:File, Ctx, import(Imports)),
834 library_info(File, Ctx, FullFile, _LoadModule, _Exports),
835 '$member'(PI, Imports),
836 '$pi_head'(PI, Head).
837
838goal_name_arity(Head, Name, Arity) :-
839 compound(Head),
840 !,
841 compound_name_arity(Head, Name, Arity).
842goal_name_arity(Head, Head, 0).
843
854
855library_info(Spec, _, FullFile, Module, Exports) :-
856 '$resolved_source_path'(Spec, FullFile, []),
857 !,
858 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread)
859 -> '$current_module'(Module, FullFile),
860 '$module_property'(Module, exports(Exports))
861 ; library_info_from_file(FullFile, _, Module, Exports)
862 ).
863library_info(Spec, Context, FullFile, Module, Exports) :-
864 ( Context = (Path:_Line)
865 -> Extra = [relative_to(Path)]
866 ; Extra = []
867 ),
868 ( absolute_file_name(Spec, AbsFile,
869 [ file_type(prolog),
870 access(read),
871 file_errors(fail)
872 | Extra
873 ])
874 -> library_info_from_file(AbsFile, FullFile, Module, Exports),
875 '$register_resolved_source_path'(Spec, FullFile)
876 ; absolute_file_name(Spec, FullFile,
877 [ file_type(prolog),
878 solutions(all),
879 file_errors(fail)
880 | Extra
881 ]),
882 source_file(FullFile),
883 '$current_module'(Module, FullFile)
884 -> '$module_property'(Module, exports(Exports))
885 ; autoload_error(Context, no_file(Spec)),
886 fail
887 ).
888
889library_info_from_file(QlfFile, PlFile, Module, Exports) :-
890 file_name_extension(_, qlf, QlfFile),
891 !,
892 '$qlf_module'(QlfFile, Info),
893 _{module:Module, exports:Exports, file:PlFile} :< Info.
894library_info_from_file(PlFile, PlFile, Module, Exports) :-
895 setup_call_cleanup(
896 '$set_source_module'(OldModule, system),
897 setup_call_cleanup(
898 '$open_source'(PlFile, In, State, [], []),
899 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
900 [PlFile], []),
901 '$close_source'(State, true)),
902 '$set_source_module'(OldModule)),
903 ( Term = (:- module(Module, Exports))
904 -> !
905 ; nonvar(Term),
906 skip_header(Term)
907 -> fail
908 ; '$domain_error'(module_header, Term)
909 ).
910
(begin_of_file).
912
913
914:- dynamic printed/3. 915:- volatile printed/3. 916
917autoload_error(Context, Error) :-
918 suppress(Context, Error),
919 !.
920autoload_error(Context, Error) :-
921 get_time(Now),
922 assertz(printed(Context, Error, Now)),
923 print_message(warning, error(autoload(Error), autoload(Context))).
924
925suppress(Context, Error) :-
926 printed(Context, Error, Printed),
927 get_time(Now),
928 ( Now - Printed < 1
929 -> true
930 ; retractall(printed(Context, Error, _)),
931 fail
932 ).
933
934
935 938
939:- public
940 set_autoload/1. 941
948
949set_autoload(FlagValue) :-
950 current_prolog_flag(autoload, FlagValue),
951 !.
952set_autoload(FlagValue) :-
953 \+ autoload_in(FlagValue, explicit, any),
954 !,
955 setup_call_cleanup(
956 nb_setval('$autoload_disabling', true),
957 materialize_autoload(Count),
958 nb_delete('$autoload_disabling')),
959 print_message(informational, autoload(disabled(Count))).
960set_autoload(_).
961
962materialize_autoload(Count) :-
963 State = state(0),
964 forall(current_predicate(M:'$autoload'/3),
965 materialize_autoload(M, State)),
966 arg(1, State, Count).
967
968materialize_autoload(M, State) :-
969 ( current_autoload(M:File, Context, Import),
970 library_info(File, Context, PlFile, _LoadModule, _Exports),
971 arg(1, State, N0),
972 N is N0+1,
973 nb_setarg(1, State, N),
974 loadable_file(PlFile, LoadFile),
975 ( Import == all
976 -> verbose_autoload(M:all, PlFile),
977 use_module(M:LoadFile)
978 ; Import = import(Preds)
979 -> verbose_autoload(M:Preds, PlFile),
980 use_module(M:LoadFile, Preds)
981 ),
982 fail
983 ; true
984 ),
985 abolish(M:'$autoload'/3).
986
987
988 991
992autoload(M:File) :-
993 ( \+ autoload_in(M, explicit)
994 ; nb_current('$autoload_disabling', true)
995 ),
996 !,
997 use_module(M:File).
998autoload(M:File) :-
999 '$must_be'(filespec, File),
1000 source_context(Context),
1001 assert_autoload(M, File, Context, all).
1002
1003autoload(M:File, Imports) :-
1004 ( \+ autoload_in(M, explicit)
1005 ; nb_current('$autoload_disabling', true)
1006 ),
1007 !,
1008 use_module(M:File, Imports).
1009autoload(M:File, Imports0) :-
1010 '$must_be'(filespec, File),
1011 valid_imports(Imports0, Imports),
1012 source_context(Context),
1013 register_autoloads(Imports, M, File, Context),
1014 assert_autoload(M, File, Context, import(Imports)).
1015
1016source_context(Path:Line) :-
1017 source_location(Path, Line),
1018 !.
1019source_context(-).
1020
1028
1029assert_autoload(Module, File, _, Imports) :-
1030 current_autoload(Module:File, _, Imports),
1031 !.
1032assert_autoload(Module, File, Context, Imports) :-
1033 set_admin_properties(Module),
1034 Clause = Module:'$autoload'(File, Context, Imports),
1035 '$initialization_context'(Source, Ctx),
1036 '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
1037
1038set_admin_properties(Module) :-
1039 predicate_property(Module:'$autoload'(_,_,_), discontiguous),
1040 !.
1041set_admin_properties(Module) :-
1042 discontiguous(Module:'$autoload'/3).
1043
1044valid_imports(Imports0, Imports) :-
1045 '$must_be'(list, Imports0),
1046 valid_import_list(Imports0, Imports).
1047
1048valid_import_list([], []).
1049valid_import_list([H0|T0], [H|T]) :-
1050 '$pi_head'(H0, Head),
1051 '$pi_head'(H, Head),
1052 valid_import_list(T0, T).
1053
1060
1061register_autoloads([], _, _, _).
1062register_autoloads([PI|T], Module, File, Context) :-
1063 PI = Name/Arity,
1064 functor(Head, Name, Arity),
1065 ( '$get_predicate_attribute'(Module:Head, autoload, 1)
1066 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)),
1067 memberchk(PI, Imports)
1068 -> '$permission_error'(redefine, imported_procedure, PI),
1069 fail
1070 ; Done = true
1071 )
1072 ; '$c_current_predicate'(_, Module:Head), 1073 '$get_predicate_attribute'(Module:Head, imported, From)
1074 -> ( ( '$resolved_source_path'(File, FullFile)
1075 -> true
1076 ; '$resolve_source_path'(File, FullFile, [])
1077 ),
1078 module_property(From, file(FullFile))
1079 -> Done = true
1080 ; print_message(warning,
1081 autoload(already_defined(Module:PI, From))),
1082 Done = true
1083 )
1084 ; true
1085 ),
1086 ( Done == true
1087 -> true
1088 ; '$set_predicate_attribute'(Module:Head, autoload, 1)
1089 ),
1090 register_autoloads(T, Module, File, Context).
1091
1092pi_in_exports(PI, Exports) :-
1093 '$member'(E, Exports),
1094 canonical_pi(E, PI),
1095 !.
1096
1097canonical_pi(Var, _) :-
1098 var(Var), !, fail.
1099canonical_pi(Name/Arity, Name/Arity).
1100canonical_pi(Name//A0, Name/Arity) :-
1101 Arity is A0 + 2.
1102
1103current_autoload(M:File, Context, Term) :-
1104 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
1105 M:'$autoload'(File, Context, Term).
1106
1107 1110
1114
1115warn_autoload(TargetModule, PI) :-
1116 current_prolog_flag(warn_autoload, true),
1117 \+ current_prolog_flag(xref, true),
1118 \+ nb_current('$autoload_warning', true),
1119 \+ nowarn_autoload(TargetModule, PI),
1120 '$pi_head'(PI, Head),
1121 source_file(Head, File),
1122 '$source_defines_expansion'(File),
1123 setup_call_cleanup(
1124 b_setval('$autoload_warning', true),
1125 print_message(warning,
1126 deprecated(autoload(TargetModule, File, PI, expansion))),
1127 nb_delete('$autoload_warning')).
1128warn_autoload(_, _).
1129
1142
1143nowarn_autoload(TargetModule, LoadModule:PI) :-
1144 NoWarn = LoadModule:'$nowarn_autoload'(PI,TargetModule),
1145 '$c_current_predicate'(_, NoWarn),
1146 \+ '$get_predicate_attribute'(NoWarn, imported, _From),
1147 call(NoWarn).
1148
1149
1150 1153
1158
1159require(M:Spec) :-
1160 ( is_list(Spec)
1161 -> List = Spec
1162 ; phrase(comma_list(Spec), List)
1163 ), !,
1164 require(List, M, FromLib),
1165 keysort(FromLib, Sorted),
1166 by_file(Sorted, Autoload),
1167 forall('$member'(File-Import, Autoload),
1168 autoload(M:File, Import)).
1169require(_:Spec) :-
1170 '$type_error'(list, Spec).
1171
1172require([],_, []).
1173require([H|T], M, Needed) :-
1174 '$pi_head'(H, Head),
1175 ( '$get_predicate_attribute'(system:Head, defined, 1)
1176 -> require(T, M, Needed)
1177 ; '$pi_head'(Module:Name/Arity, M:Head),
1178 ( '$find_library'(Module, Name, Arity, LoadModule, Library)
1179 -> ( current_predicate(LoadModule:Name/Arity)
1180 -> Module:import(LoadModule:Name/Arity),
1181 require(T, M, Needed)
1182 ; Needed = [Library-H|More],
1183 require(T, M, More)
1184 )
1185 ; print_message(error, error(existence_error(procedure, Name/Arity), _)),
1186 require(T, M, Needed)
1187 )
1188 ).
1189
1190by_file([], []).
1191by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
1192 on_path(File, Spec),
1193 same_file(T0, File, PIs, T1),
1194 by_file(T1, T).
1195
1196on_path(Library, library(Base)) :-
1197 file_base_name(Library, Base),
1198 findall(Path, plain_source(library(Base), Path), [Library]),
1199 !.
1200on_path(Library, Library).
1201
1202plain_source(Spec, Path) :-
1203 absolute_file_name(Spec, PathExt,
1204 [ file_type(prolog),
1205 access(read),
1206 file_errors(fail),
1207 solutions(all)
1208 ]),
1209 file_name_extension(Path, _, PathExt).
1210
1211same_file([File-PI|T0], File, [PI|PIs], T) :-
1212 !,
1213 same_file(T0, File, PIs, T).
1214same_file(List, _, [], List).
1215
1216comma_list(Var) -->
1217 { var(Var),
1218 !,
1219 '$instantiation_error'(Var)
1220 }.
1221comma_list((A,B)) -->
1222 !,
1223 comma_list(A),
1224 comma_list(B).
1225comma_list(A) -->
1226 [A]