1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 1985-2023, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 SWI-Prolog Solutions b.v. 10 All rights reserved. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in 21 the documentation and/or other materials provided with the 22 distribution. 23 24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 POSSIBILITY OF SUCH DAMAGE. 36*/ 37 38:- module('$autoload', 39 [ '$find_library'/5, 40 '$in_library'/3, 41 '$define_predicate'/1, 42 '$update_library_index'/0, 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, % +File 51 autoload/2, % +File, +Imports 52 53 require/1 % +Predicates 54 ]). 55 56:- meta_predicate 57 '$autoload'( ), 58 autoload( ), 59 autoload( , ), 60 require( ). 61 62:- dynamic 63 library_index/3, % Head x Module x Path 64 autoload_directories/1, % List 65 index_checked_at/1. % Time 66:- volatile 67 library_index/3, 68 autoload_directories/1, 69 index_checked_at/1. 70 71user:file_search_path(autoload, swi(library)). 72user:file_search_path(autoload, pce(prolog/lib)). 73user:file_search_path(autoload, app_config(lib)). 74user:file_search_path(autoload, Dir) :- 75 '$ext_library_directory'(Dir). 76 77:- create_prolog_flag(warn_autoload, false, []).
87'$find_library'(Module, Name, Arity, LoadModule, Library) :-
88 load_library_index(Name, Arity),
89 functor(Head, Name, Arity),
90 ( library_index(Head, Module, Library),
91 LoadModule = Module
92 ; library_index(Head, LoadModule, Library)
93 ),
94 !.
101'$in_library'(Name, Arity, Path) :- 102 atom(Name), integer(Arity), 103 !, 104 load_library_index(Name, Arity), 105 functor(Head, Name, Arity), 106 library_index(Head, _, Path). 107'$in_library'(Name, Arity, Path) :- 108 load_library_index(Name, Arity), 109 library_index(Head, _, Path), 110 functor(Head, Name, Arity).
117:- meta_predicate 118 '$define_predicate'( ). 119 120'$define_predicate'(Head) :- 121 '$defined_predicate'(Head), 122 !. 123'$define_predicate'(Term) :- 124 Term = Module:Head, 125 ( compound(Head) 126 -> compound_name_arity(Head, Name, Arity) 127 ; Name = Head, Arity = 0 128 ), 129 '$undefined_procedure'(Module, Name, Arity, retry). 130 131 132 /******************************** 133 * UPDATE INDEX * 134 ********************************/ 135 136:- thread_local 137 silent/0.
146'$update_library_index' :- 147 setof(Dir, writable_indexed_directory(Dir), Dirs), 148 !, 149 setup_call_cleanup( 150 asserta(silent, Ref), 151 guarded_make_library_index(Dirs), 152 erase(Ref)), 153 ( flag('$modified_index', true, false) 154 -> reload_library_index 155 ; true 156 ). 157'$update_library_index'. 158 159guarded_make_library_index([]). 160guarded_make_library_index([Dir|Dirs]) :- 161 ( catch(make_library_index(Dir), E, 162 print_message(error, E)) 163 -> true 164 ; print_message(warning, goal_failed(make_library_index(Dir))) 165 ), 166 guarded_make_library_index(Dirs).
173writable_indexed_directory(Dir) :- 174 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]), 175 file_directory_name(IndexFile, Dir). 176writable_indexed_directory(Dir) :- 177 absolute_file_name(library('MKINDEX'), 178 [ file_type(prolog), 179 access(read), 180 solutions(all), 181 file_errors(fail) 182 ], MkIndexFile), 183 file_directory_name(MkIndexFile, Dir), 184 plfile_in_dir(Dir, 'INDEX', _, IndexFile), 185 access_file(IndexFile, write). 186 187 188 /******************************** 189 * LOAD INDEX * 190 ********************************/
196reload_library_index :- 197 context_module(M), 198 reload_library_index(M). 199 200reload_library_index(M) :- 201 with_mutex('$autoload', clear_library_index(M)). 202 203clear_library_index(M) :- 204 retractall(M:library_index(_, _, _)), 205 retractall(M:autoload_directories(_)), 206 retractall(M:index_checked_at(_)).
216:- meta_predicate load_library_index( , , ). 217:- public load_library_index/3. 218 219load_library_index(Name, Arity) :- 220 load_library_index(Name, Arity, autoload('INDEX')). 221 222load_library_index(Name, Arity, M:_Spec) :- 223 atom(Name), integer(Arity), 224 functor(Head, Name, Arity), 225 M:library_index(Head, _, _), 226 !. 227load_library_index(_, _, Spec) :- 228 notrace(with_mutex('$autoload', load_library_index_p(Spec))). 229 230load_library_index_p(M:_) :- 231 M:index_checked_at(Time), 232 get_time(Now), 233 Now-Time < 60, 234 !. 235load_library_index_p(M:Spec) :- 236 findall(Index, index_file_name(Index, Spec, [access(read)]), List0), 237 '$list_to_set'(List0, List), 238 retractall(M:index_checked_at(_)), 239 get_time(Now), 240 assert(M:index_checked_at(Now)), 241 ( M:autoload_directories(List) 242 -> true 243 ; retractall(M:library_index(_, _, _)), 244 retractall(M:autoload_directories(_)), 245 read_index(List, M), 246 assert(M:autoload_directories(List)) 247 ).
autoload
.
257index_file_name(IndexFile, FileSpec, Options) :- 258 absolute_file_name(FileSpec, 259 IndexFile, 260 [ file_type(prolog), 261 solutions(all), 262 file_errors(fail) 263 | Options 264 ]). 265 266read_index([], _) :- !. 267read_index([H|T], M) :- 268 !, 269 read_index(H, M), 270 read_index(T, M). 271read_index(Index, M) :- 272 print_message(silent, autoload(read_index(Dir))), 273 file_directory_name(Index, Dir), 274 setup_call_cleanup( 275 '$push_input_context'(autoload_index), 276 setup_call_cleanup( 277 open(Index, read, In), 278 read_index_from_stream(Dir, In, M), 279 close(In)), 280 '$pop_input_context'). 281 282read_index_from_stream(Dir, In, M) :- 283 repeat, 284 read(In, Term), 285 assert_index(Term, Dir, M), 286 !. 287 288assert_index(end_of_file, _, _) :- !. 289assert_index(index(Name, Arity, Module, File), Dir, M) :- 290 !, 291 functor(Head, Name, Arity), 292 atomic_list_concat([Dir, '/', File], Path), 293 assertz(M:library_index(Head, Module, Path)), 294 fail. 295assert_index(Term, Dir, _) :- 296 print_message(error, illegal_autoload_index(Dir, Term)), 297 fail. 298 299 300 /******************************** 301 * CREATE INDEX.pl * 302 ********************************/
INDEX.pl
. In Dir contains a file
MKINDEX.pl
, this file is loaded and we assume that the index is
created by directives that appearin this file. Otherwise, all
source files are scanned for their module-header and all
exported predicates are added to the autoload index.
315make_library_index(Dir0) :- 316 forall(absolute_file_name(Dir0, Dir, 317 [ expand(true), 318 file_type(directory), 319 file_errors(fail), 320 solutions(all) 321 ]), 322 make_library_index2(Dir)). 323 324make_library_index2(Dir) :- 325 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex), 326 access_file(AbsMkIndex, read), 327 !, 328 load_files(user:AbsMkIndex, [silent(true)]). 329make_library_index2(Dir) :- 330 findall(Pattern, source_file_pattern(Pattern), PatternList), 331 make_library_index2(Dir, PatternList).
INDEX.pl
for Dir by scanning all files
that match any of the file-patterns in Patterns. Typically, this
appears as a directive in MKINDEX.pl
. For example:
:- prolog_load_context(directory, Dir), make_library_index(Dir, ['*.pl']).
346make_library_index(Dir0, Patterns) :- 347 forall(absolute_file_name(Dir0, Dir, 348 [ expand(true), 349 file_type(directory), 350 file_errors(fail), 351 solutions(all) 352 ]), 353 make_library_index2(Dir, Patterns)). 354 355make_library_index2(Dir, Patterns) :- 356 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex), 357 ensure_slash(Dir, DirS), 358 pattern_files(Patterns, DirS, Files), 359 ( library_index_out_of_date(Dir, AbsIndex, Files) 360 -> do_make_library_index(AbsIndex, DirS, Files), 361 set_flag('$modified_index', true) 362 ; true 363 ). 364 365ensure_slash(Dir, DirS) :- 366 ( sub_atom(Dir, _, _, 0, /) 367 -> DirS = Dir 368 ; atom_concat(Dir, /, DirS) 369 ). 370 371source_file_pattern(Pattern) :- 372 user:prolog_file_type(PlExt, prolog), 373 PlExt \== qlf, 374 atom_concat('*.', PlExt, Pattern). 375 376plfile_in_dir(Dir, Base, PlBase, File) :- 377 file_name_extension(Base, pl, PlBase), 378 atomic_list_concat([Dir, '/', PlBase], File). 379 380pattern_files([], _, []). 381pattern_files([H|T], DirS, Files) :- 382 atom_concat(DirS, H, P0), 383 expand_file_name(P0, Files0), 384 '$append'(Files0, Rest, Files), 385 pattern_files(T, DirS, Rest). 386 387library_index_out_of_date(_Dir, Index, _Files) :- 388 \+ exists_file(Index), 389 !. 390library_index_out_of_date(Dir, Index, Files) :- 391 time_file(Index, IndexTime), 392 ( time_file(Dir, DotTime), 393 DotTime - IndexTime > 0.001 % compensate for jitter 394 ; '$member'(File, Files), % and rounding 395 time_file(File, FileTime), 396 FileTime - IndexTime > 0.001 397 ), 398 !. 399 400 401do_make_library_index(Index, Dir, Files) :- 402 ensure_slash(Dir, DirS), 403 '$stage_file'(Index, StagedIndex), 404 setup_call_catcher_cleanup( 405 open(StagedIndex, write, Out), 406 ( print_message(informational, make(library_index(Dir))), 407 index_header(Out), 408 index_files(Files, DirS, Out) 409 ), 410 Catcher, 411 install_index(Out, Catcher, StagedIndex, Index)). 412 413install_index(Out, Catcher, StagedIndex, Index) :- 414 catch(close(Out), Error, true), 415 ( silent 416 -> OnError = silent 417 ; OnError = error 418 ), 419 ( var(Error) 420 -> TheCatcher = Catcher 421 ; TheCatcher = exception(Error) 422 ), 423 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
429index_files([], _, _). 430index_files([File|Files], DirS, Fd) :- 431 ( catch(exports(File, Module, Public), E, 432 print_message(warning, E)), 433 nonvar(Module) 434 -> atom_concat(DirS, Local, File), 435 file_name_extension(Base, _, Local), 436 forall(public_predicate(Public, Name/Arity), 437 format(Fd, 'index((~k), ~k, ~k, ~k).~n', 438 [Name, Arity, Module, Base])) 439 ; true 440 ), 441 index_files(Files, DirS, Fd). 442 443public_predicate(Public, PI) :- 444 '$member'(PI0, Public), 445 canonical_pi(PI0, PI). 446 447canonical_pi(Var, _) :- 448 var(Var), !, fail. 449canonical_pi(Name/Arity, Name/Arity). 450canonical_pi(Name//A0, Name/Arity) :- 451 Arity is A0 + 2. 452 453 454index_header(Fd):- 455 format(Fd, '/* Creator: make/0~n~n', []), 456 format(Fd, ' Purpose: Provide index for autoload~n', []), 457 format(Fd, '*/~n~n', []).
463:- public exports/3. % using by library(prolog_deps). 464exports(File, Module, Exports) :- 465 ( current_prolog_flag(xref, Old) 466 -> true 467 ; Old = false 468 ), 469 setup_call_cleanup( 470 set_prolog_flag(xref, true), 471 snapshot(exports_(File, Module, Exports)), 472 set_prolog_flag(xref, Old)). 473 474exports_(File, Module, Exports) :- 475 State = state(true, _, []), 476 ( '$source_term'(File, 477 _Read,_RLayout, 478 Term,_TermLayout, 479 _Stream, 480 [ syntax_errors(quiet) 481 ]), 482 ( Term = (:- module(M,Public)), 483 is_list(Public), 484 arg(1, State, true) 485 -> nb_setarg(1, State, false), 486 nb_setarg(2, State, M), 487 nb_setarg(3, State, Public), 488 fail 489 ; nb_setarg(1, State, false), 490 fail 491 ; Term = (:- export(PI)), 492 ground(PI) 493 -> arg(3, State, E0), 494 '$append'(E0, [PI], E1), 495 nb_setarg(3, State, E1), 496 fail 497 ; Term = (:- use_foreign_library(Lib)), 498 nonvar(Lib), 499 arg(2, State, M), 500 atom(M) 501 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true), 502 fail 503 ; Term = (:- Directive), 504 nonvar(Directive) 505 -> fail 506 ; ! 507 ) 508 ; true 509 ), 510 arg(2, State, Module), 511 arg(3, State, Exports). 512 513 514 /******************************* 515 * EXTENDING * 516 *******************************/
autoload
and reloads the library
index. For example:
:- autoload_path(library(http)).
If this call appears as a directive, it is term-expanded into a clause for file_search_path/2 and a directive calling reload_library_index/0. This keeps source information and allows for removing this directive.
533autoload_path(Alias) :- 534 ( user:file_search_path(autoload, Alias) 535 -> true 536 ; assertz(user:file_search_path(autoload, Alias)), 537 reload_library_index 538 ). 539 540systemterm_expansion((:- autoload_path(Alias)), 541 [ user:file_search_path(autoload, Alias), 542 (:- reload_library_index) 543 ]). 544 545 546 /******************************* 547 * RUNTIME AUTOLOADER * 548 *******************************/
current_prolog_flag(autoload, true)
holds.558'$autoload'(PI) :- 559 source_location(File, _Line), 560 !, 561 setup_call_cleanup( 562 '$start_aux'(File, Context), 563 '$autoload2'(PI), 564 '$end_aux'(File, Context)). 565'$autoload'(PI) :- 566 '$autoload2'(PI). 567 568'$autoload2'(PI) :- 569 setup_call_cleanup( 570 leave_sandbox(Old), 571 '$autoload3'(PI), 572 restore_sandbox(Old)). 573 574leave_sandbox(Sandboxed) :- 575 current_prolog_flag(sandboxed_load, Sandboxed), 576 set_prolog_flag(sandboxed_load, false). 577restore_sandbox(Sandboxed) :- 578 set_prolog_flag(sandboxed_load, Sandboxed). 579 580'$autoload3'(PI) :- 581 autoload_from(PI, LoadModule, FullFile), 582 do_autoload(FullFile, PI, LoadModule).
589autoload_from(Module:PI, LoadModule, FullFile) :- 590 autoload_in(Module, explicit), 591 current_autoload(Module:File, Ctx, import(Imports)), 592 memberchk(PI, Imports), 593 library_info(File, Ctx, FullFile, LoadModule, Exports), 594 ( pi_in_exports(PI, Exports) 595 -> ! 596 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)), 597 fail 598 ). 599autoload_from(Module:Name/Arity, LoadModule, FullFile) :- 600 autoload_in(Module, explicit), 601 PI = Name/Arity, 602 current_autoload(Module:File, Ctx, all), 603 library_info(File, Ctx, FullFile, LoadModule, Exports), 604 pi_in_exports(PI, Exports). 605autoload_from(Module:Name/Arity, LoadModule, Library) :- 606 autoload_in(Module, general), 607 '$find_library'(Module, Name, Arity, LoadModule, Library). 608 609:- public autoload_in/2. % used in syspred 610 611autoload_in(Module, How) :- 612 current_prolog_flag(autoload, AutoLoad), 613 autoload_in(AutoLoad, How, Module), 614 !.
618autoload_in(true, _, _). 619autoload_in(explicit, explicit, _). 620autoload_in(user, _, user). 621autoload_in(user_or_explicit, explicit, _). 622autoload_in(user_or_explicit, _, user).
user
. '$c_current_predicate'/2
verifies the predicate really exists, but doesn't validate
that it is defined.638do_autoload(Library, Module:Name/Arity, LoadModule) :- 639 functor(Head, Name, Arity), 640 '$update_autoload_level'([autoload(true)], Old), 641 verbose_autoload(Module:Name/Arity, Library), 642 '$compilation_mode'(OldComp, database), 643 ( Module == LoadModule 644 -> ensure_loaded(Module:Library) 645 ; ( '$c_current_predicate'(_, LoadModule:Head), 646 '$get_predicate_attribute'(LoadModule:Head, defined, 1), 647 \+ '$loading'(Library) 648 -> Module:import(LoadModule:Name/Arity) 649 ; use_module(Module:Library, [Name/Arity]) 650 ), 651 warn_autoload(Module, LoadModule:Name/Arity) 652 ), 653 '$set_compilation_mode'(OldComp), 654 '$set_autoload_level'(Old), 655 '$c_current_predicate'(_, Module:Head). 656 657verbose_autoload(PI, Library) :- 658 current_prolog_flag(verbose_autoload, true), 659 !, 660 set_prolog_flag(verbose_autoload, false), 661 print_message(informational, autoload(PI, Library)), 662 set_prolog_flag(verbose_autoload, true). 663verbose_autoload(PI, Library) :- 664 print_message(silent, autoload(PI, Library)).
autoload(File)
. The module must be
instantiated.673:- public % used from predicate_property/2 674 autoloadable/2. 675 676autoloadable(M:Head, FullFile) :- 677 atom(M), 678 current_module(M), 679 autoload_in(M, explicit), 680 ( callable(Head) 681 -> goal_name_arity(Head, Name, Arity), 682 autoload_from(M:Name/Arity, _, FullFile) 683 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs), 684 ( '$member'(M:Head-FullFile, Pairs) 685 ; current_autoload(M:File, Ctx, all), 686 library_info(File, Ctx, FullFile, _, Exports), 687 '$member'(PI, Exports), 688 '$pi_head'(PI, Head), 689 \+ memberchk(M:Head-_, Pairs) 690 ) 691 ). 692autoloadable(M:Head, FullFile) :- 693 ( var(M) 694 -> autoload_in(any, general) 695 ; autoload_in(M, general) 696 ), 697 ( callable(Head) 698 -> goal_name_arity(Head, Name, Arity), 699 ( '$find_library'(_, Name, Arity, _, FullFile) 700 -> true 701 ) 702 ; '$in_library'(Name, Arity, autoload), 703 functor(Head, Name, Arity) 704 ). 705 706 707autoloadable_2(M:Head, FullFile) :- 708 current_autoload(M:File, Ctx, import(Imports)), 709 library_info(File, Ctx, FullFile, _LoadModule, _Exports), 710 '$member'(PI, Imports), 711 '$pi_head'(PI, Head). 712 713goal_name_arity(Head, Name, Arity) :- 714 compound(Head), 715 !, 716 compound_name_arity(Head, Name, Arity). 717goal_name_arity(Head, Head, 0).
723library_info(Spec, _, FullFile, Module, Exports) :- 724 '$resolved_source_path'(Spec, FullFile, []), 725 !, 726 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread) 727 -> '$current_module'(Module, FullFile), 728 '$module_property'(Module, exports(Exports)) 729 ; library_info_from_file(FullFile, Module, Exports) 730 ). 731library_info(Spec, Context, FullFile, Module, Exports) :- 732 ( Context = (Path:_Line) 733 -> Extra = [relative_to(Path)] 734 ; Extra = [] 735 ), 736 ( absolute_file_name(Spec, FullFile, 737 [ file_type(prolog), 738 access(read), 739 file_errors(fail) 740 | Extra 741 ]) 742 -> '$register_resolved_source_path'(Spec, FullFile), 743 library_info_from_file(FullFile, Module, Exports) 744 ; autoload_error(Context, no_file(Spec)), 745 fail 746 ). 747 748library_info_from_file(FullFile, Module, Exports) :- 749 setup_call_cleanup( 750 '$set_source_module'(OldModule, system), 751 setup_call_cleanup( 752 '$open_source'(FullFile, In, State, [], []), 753 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream, 754 [FullFile], []), 755 '$close_source'(State, true)), 756 '$set_source_module'(OldModule)), 757 ( Term = (:- module(Module, Exports)) 758 -> ! 759 ; nonvar(Term), 760 skip_header(Term) 761 -> fail 762 ; '$domain_error'(module_header, Term) 763 ). 764 765skip_header(begin_of_file). 766 767 768:- dynamic printed/3. 769:- volatile printed/3. 770 771autoload_error(Context, Error) :- 772 suppress(Context, Error), 773 !. 774autoload_error(Context, Error) :- 775 get_time(Now), 776 assertz(printed(Context, Error, Now)), 777 print_message(warning, error(autoload(Error), autoload(Context))). 778 779suppress(Context, Error) :- 780 printed(Context, Error, Printed), 781 get_time(Now), 782 ( Now - Printed < 1 783 -> true 784 ; retractall(printed(Context, Error, _)), 785 fail 786 ). 787 788 789 /******************************* 790 * CALLBACK * 791 *******************************/ 792 793:- public 794 set_autoload/1.
false
we should materialize all registered
requests for autoloading. We must do so before disabling autoloading
as loading the files may require autoloading.803set_autoload(FlagValue) :- 804 current_prolog_flag(autoload, FlagValue), 805 !. 806set_autoload(FlagValue) :- 807 \+ autoload_in(FlagValue, explicit, any), 808 !, 809 setup_call_cleanup( 810 nb_setval('$autoload_disabling', true), 811 materialize_autoload(Count), 812 nb_delete('$autoload_disabling')), 813 print_message(informational, autoload(disabled(Count))). 814set_autoload(_). 815 816materialize_autoload(Count) :- 817 State = state(0), 818 forall(current_predicate(M:'$autoload'/3), 819 materialize_autoload(M, State)), 820 arg(1, State, Count). 821 822materialize_autoload(M, State) :- 823 ( current_autoload(M:File, Context, Import), 824 library_info(File, Context, FullFile, _LoadModule, _Exports), 825 arg(1, State, N0), 826 N is N0+1, 827 nb_setarg(1, State, N), 828 ( Import == all 829 -> verbose_autoload(M:all, FullFile), 830 use_module(M:FullFile) 831 ; Import = import(Preds) 832 -> verbose_autoload(M:Preds, FullFile), 833 use_module(M:FullFile, Preds) 834 ), 835 fail 836 ; true 837 ), 838 abolish(M:'$autoload'/3). 839 840 841 /******************************* 842 * AUTOLOAD/2 * 843 *******************************/ 844 845autoload(M:File) :- 846 ( \+ autoload_in(M, explicit) 847 ; nb_current('$autoload_disabling', true) 848 ), 849 !, 850 use_module(M:File). 851autoload(M:File) :- 852 '$must_be'(filespec, File), 853 source_context(Context), 854 ( current_autoload(M:File, _, import(all)) 855 -> true 856 ; assert_autoload(M:'$autoload'(File, Context, all)) 857 ). 858 859autoload(M:File, Imports) :- 860 ( \+ autoload_in(M, explicit) 861 ; nb_current('$autoload_disabling', true) 862 ), 863 !, 864 use_module(M:File, Imports). 865autoload(M:File, Imports0) :- 866 '$must_be'(filespec, File), 867 valid_imports(Imports0, Imports), 868 source_context(Context), 869 register_autoloads(Imports, M, File, Context), 870 ( current_autoload(M:File, _, import(Imports)) 871 -> true 872 ; assert_autoload(M:'$autoload'(File, Context, import(Imports))) 873 ). 874 875source_context(Path:Line) :- 876 source_location(Path, Line), 877 !. 878source_context(-). 879 880assert_autoload(Clause) :- 881 '$initialization_context'(Source, Ctx), 882 '$store_admin_clause2'(Clause, _Layout, Source, Ctx). 883 884valid_imports(Imports0, Imports) :- 885 '$must_be'(list, Imports0), 886 valid_import_list(Imports0, Imports). 887 888valid_import_list([], []). 889valid_import_list([H0|T0], [H|T]) :- 890 '$pi_head'(H0, Head), 891 '$pi_head'(H, Head), 892 valid_import_list(T0, T).
autoload
flag on all predicates declared using autoload/2
to prevent duplicates or the user defining the same predicate.899register_autoloads([], _, _, _). 900register_autoloads([PI|T], Module, File, Context) :- 901 PI = Name/Arity, 902 functor(Head, Name, Arity), 903 ( '$get_predicate_attribute'(Module:Head, autoload, 1) 904 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)), 905 memberchk(PI, Imports) 906 -> '$permission_error'(redefine, imported_procedure, PI), 907 fail 908 ; Done = true 909 ) 910 ; '$c_current_predicate'(_, Module:Head), % no auto-import 911 '$get_predicate_attribute'(Module:Head, imported, From) 912 -> ( ( '$resolved_source_path'(File, FullFile) 913 -> true 914 ; '$resolve_source_path'(File, FullFile, []) 915 ), 916 module_property(From, file(FullFile)) 917 -> Done = true 918 ; print_message(warning, 919 autoload(already_defined(Module:PI, From))), 920 Done = true 921 ) 922 ; true 923 ), 924 ( Done == true 925 -> true 926 ; '$set_predicate_attribute'(Module:Head, autoload, 1) 927 ), 928 register_autoloads(T, Module, File, Context). 929 930pi_in_exports(PI, Exports) :- 931 '$member'(E, Exports), 932 canonical_pi(E, PI), 933 !. 934 935current_autoload(M:File, Context, Term) :- 936 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1), 937 M:'$autoload'(File, Context, Term). 938 939 /******************************* 940 * CHECK * 941 *******************************/ 942 943warn_autoload(TargetModule, PI) :- 944 current_prolog_flag(warn_autoload, true), 945 \+ current_prolog_flag(xref, true), 946 \+ nb_current('$autoload_warning', true), 947 '$pi_head'(PI, Head), 948 source_file(Head, File), 949 expansion_hook(P), 950 source_file(P, File), 951 !, 952 setup_call_cleanup( 953 b_setval('$autoload_warning', true), 954 print_message(warning, 955 deprecated(autoload(TargetModule, File, PI, expansion))), 956 nb_delete('$autoload_warning')). 957warn_autoload(_, _). 958 959expansion_hook(user:goal_expansion(_,_)). 960expansion_hook(user:goal_expansion(_,_,_,_)). 961expansion_hook(system:goal_expansion(_,_)). 962expansion_hook(system:goal_expansion(_,_,_,_)). 963 964 965 /******************************* 966 * REQUIRE * 967 *******************************/
974require(M:Spec) :- 975 ( is_list(Spec) 976 -> List = Spec 977 ; phrase(comma_list(Spec), List) 978 ), !, 979 require(List, M, FromLib), 980 keysort(FromLib, Sorted), 981 by_file(Sorted, Autoload), 982 forall('$member'(File-Import, Autoload), 983 autoload(M:File, Import)). 984require(_:Spec) :- 985 '$type_error'(list, Spec). 986 987require([],_, []). 988require([H|T], M, Needed) :- 989 '$pi_head'(H, Head), 990 ( '$get_predicate_attribute'(system:Head, defined, 1) 991 -> require(T, M, Needed) 992 ; '$pi_head'(Module:Name/Arity, M:Head), 993 ( '$find_library'(Module, Name, Arity, LoadModule, Library) 994 -> ( current_predicate(LoadModule:Name/Arity) 995 -> Module:import(LoadModule:Name/Arity), 996 require(T, M, Needed) 997 ; Needed = [Library-H|More], 998 require(T, M, More) 999 ) 1000 ; print_message(error, error(existence_error(procedure, Name/Arity), _)), 1001 require(T, M, Needed) 1002 ) 1003 ). 1004 1005by_file([], []). 1006by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :- 1007 on_path(File, Spec), 1008 same_file(T0, File, PIs, T1), 1009 by_file(T1, T). 1010 1011on_path(Library, library(Base)) :- 1012 file_base_name(Library, Base), 1013 findall(Path, plain_source(library(Base), Path), [Library]), 1014 !. 1015on_path(Library, Library). 1016 1017plain_source(Spec, Path) :- 1018 absolute_file_name(Spec, PathExt, 1019 [ file_type(prolog), 1020 access(read), 1021 file_errors(fail), 1022 solutions(all) 1023 ]), 1024 file_name_extension(Path, _, PathExt). 1025 1026same_file([File-PI|T0], File, [PI|PIs], T) :- 1027 !, 1028 same_file(T0, File, PIs, T). 1029same_file(List, _, [], List). 1030 1031comma_list(Var) --> 1032 { var(Var), 1033 !, 1034 '$instantiation_error'(Var) 1035 }. 1036comma_list((A,B)) --> 1037 !, 1038 comma_list(A), 1039 comma_list(B). 1040comma_list(A) --> 1041 [A]