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-2024, 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'/1, % +Options 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.
false
.true
.151'$update_library_index'(Options) :- 152 setof(Dir, writable_indexed_directory(Dir, Options), Dirs), 153 !, 154 setup_call_cleanup( 155 asserta(silent, Ref), 156 guarded_make_library_index(Dirs), 157 erase(Ref)), 158 ( flag('$modified_index', true, false) 159 -> reload_library_index 160 ; true 161 ). 162'$update_library_index'(_). 163 164guarded_make_library_index([]). 165guarded_make_library_index([Dir|Dirs]) :- 166 ( catch(make_library_index(Dir), E, 167 print_message(error, E)) 168 -> true 169 ; print_message(warning, goal_failed(make_library_index(Dir))) 170 ), 171 guarded_make_library_index(Dirs).
178writable_indexed_directory(Dir, Options) :- 179 current_prolog_flag(home, Home), 180 writable_indexed_directory(Dir), 181 ( sub_atom(Dir, 0, _, _, Home) 182 -> '$option'(system(true), Options, false) 183 ; '$option'(user(true), Options, true) 184 ). 185 186writable_indexed_directory(Dir) :- 187 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]), 188 file_directory_name(IndexFile, Dir). 189writable_indexed_directory(Dir) :- 190 absolute_file_name(library('MKINDEX'), 191 [ file_type(prolog), 192 access(read), 193 solutions(all), 194 file_errors(fail) 195 ], MkIndexFile), 196 file_directory_name(MkIndexFile, Dir), 197 plfile_in_dir(Dir, 'INDEX', _, IndexFile), 198 access_file(IndexFile, write). 199 200 201 /******************************** 202 * LOAD INDEX * 203 ********************************/
209reload_library_index :- 210 context_module(M), 211 reload_library_index(M). 212 213reload_library_index(M) :- 214 with_mutex('$autoload', clear_library_index(M)). 215 216clear_library_index(M) :- 217 retractall(M:library_index(_, _, _)), 218 retractall(M:autoload_directories(_)), 219 retractall(M:index_checked_at(_)).
229:- meta_predicate load_library_index( , , ). 230:- public load_library_index/3. 231 232load_library_index(Name, Arity) :- 233 load_library_index(Name, Arity, autoload('INDEX')). 234 235load_library_index(Name, Arity, M:_Spec) :- 236 atom(Name), integer(Arity), 237 functor(Head, Name, Arity), 238 M:library_index(Head, _, _), 239 !. 240load_library_index(_, _, Spec) :- 241 notrace(with_mutex('$autoload', load_library_index_p(Spec))). 242 243load_library_index_p(M:_) :- 244 M:index_checked_at(Time), 245 get_time(Now), 246 Now-Time < 60, 247 !. 248load_library_index_p(M:Spec) :- 249 findall(Index, index_file_name(Index, Spec, [access(read)]), List0), 250 '$list_to_set'(List0, List), 251 retractall(M:index_checked_at(_)), 252 get_time(Now), 253 assert(M:index_checked_at(Now)), 254 ( M:autoload_directories(List) 255 -> true 256 ; retractall(M:library_index(_, _, _)), 257 retractall(M:autoload_directories(_)), 258 read_index(List, M), 259 assert(M:autoload_directories(List)) 260 ).
autoload
.
270index_file_name(IndexFile, FileSpec, Options) :- 271 absolute_file_name(FileSpec, 272 IndexFile, 273 [ file_type(prolog), 274 solutions(all), 275 file_errors(fail) 276 | Options 277 ]). 278 279read_index([], _) :- !. 280read_index([H|T], M) :- 281 !, 282 read_index(H, M), 283 read_index(T, M). 284read_index(Index, M) :- 285 print_message(silent, autoload(read_index(Dir))), 286 file_directory_name(Index, Dir), 287 setup_call_cleanup( 288 '$push_input_context'(autoload_index), 289 setup_call_cleanup( 290 open(Index, read, In), 291 read_index_from_stream(Dir, In, M), 292 close(In)), 293 '$pop_input_context'). 294 295read_index_from_stream(Dir, In, M) :- 296 repeat, 297 read(In, Term), 298 assert_index(Term, Dir, M), 299 !. 300 301assert_index(end_of_file, _, _) :- !. 302assert_index(index(Name, Arity, Module, File), Dir, M) :- 303 !, 304 functor(Head, Name, Arity), 305 atomic_list_concat([Dir, '/', File], Path), 306 assertz(M:library_index(Head, Module, Path)), 307 fail. 308assert_index(Term, Dir, _) :- 309 print_message(error, illegal_autoload_index(Dir, Term)), 310 fail. 311 312 313 /******************************** 314 * CREATE INDEX.pl * 315 ********************************/
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.
328make_library_index(Dir0) :- 329 forall(absolute_file_name(Dir0, Dir, 330 [ expand(true), 331 file_type(directory), 332 file_errors(fail), 333 solutions(all) 334 ]), 335 make_library_index2(Dir)). 336 337make_library_index2(Dir) :- 338 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex), 339 access_file(AbsMkIndex, read), 340 !, 341 load_files(user:AbsMkIndex, [silent(true)]). 342make_library_index2(Dir) :- 343 findall(Pattern, source_file_pattern(Pattern), PatternList), 344 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']).
359make_library_index(Dir0, Patterns) :- 360 forall(absolute_file_name(Dir0, Dir, 361 [ expand(true), 362 file_type(directory), 363 file_errors(fail), 364 solutions(all) 365 ]), 366 make_library_index2(Dir, Patterns)). 367 368make_library_index2(Dir, Patterns) :- 369 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex), 370 ensure_slash(Dir, DirS), 371 pattern_files(Patterns, DirS, Files), 372 ( library_index_out_of_date(Dir, AbsIndex, Files) 373 -> do_make_library_index(AbsIndex, DirS, Files), 374 set_flag('$modified_index', true) 375 ; true 376 ). 377 378ensure_slash(Dir, DirS) :- 379 ( sub_atom(Dir, _, _, 0, /) 380 -> DirS = Dir 381 ; atom_concat(Dir, /, DirS) 382 ). 383 384source_file_pattern(Pattern) :- 385 user:prolog_file_type(PlExt, prolog), 386 PlExt \== qlf, 387 atom_concat('*.', PlExt, Pattern). 388 389plfile_in_dir(Dir, Base, PlBase, File) :- 390 file_name_extension(Base, pl, PlBase), 391 atomic_list_concat([Dir, '/', PlBase], File). 392 393pattern_files([], _, []). 394pattern_files([H|T], DirS, Files) :- 395 atom_concat(DirS, H, P0), 396 expand_file_name(P0, Files0), 397 '$append'(Files0, Rest, Files), 398 pattern_files(T, DirS, Rest). 399 400library_index_out_of_date(_Dir, Index, _Files) :- 401 \+ exists_file(Index), 402 !. 403library_index_out_of_date(Dir, Index, Files) :- 404 time_file(Index, IndexTime), 405 ( time_file(Dir, DotTime), 406 DotTime - IndexTime > 0.001 % compensate for jitter 407 ; '$member'(File, Files), % and rounding 408 time_file(File, FileTime), 409 FileTime - IndexTime > 0.001 410 ), 411 !. 412 413 414do_make_library_index(Index, Dir, Files) :- 415 ensure_slash(Dir, DirS), 416 '$stage_file'(Index, StagedIndex), 417 setup_call_catcher_cleanup( 418 open(StagedIndex, write, Out), 419 ( print_message(informational, make(library_index(Dir))), 420 index_header(Out), 421 index_files(Files, DirS, Out) 422 ), 423 Catcher, 424 install_index(Out, Catcher, StagedIndex, Index)). 425 426install_index(Out, Catcher, StagedIndex, Index) :- 427 catch(close(Out), Error, true), 428 ( silent 429 -> OnError = silent 430 ; OnError = error 431 ), 432 ( var(Error) 433 -> TheCatcher = Catcher 434 ; TheCatcher = exception(Error) 435 ), 436 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
442index_files([], _, _). 443index_files([File|Files], DirS, Fd) :- 444 ( catch(exports(File, Module, Public), E, 445 print_message(warning, E)), 446 nonvar(Module) 447 -> atom_concat(DirS, Local, File), 448 file_name_extension(Base, _, Local), 449 forall(public_predicate(Public, Name/Arity), 450 format(Fd, 'index((~k), ~k, ~k, ~k).~n', 451 [Name, Arity, Module, Base])) 452 ; true 453 ), 454 index_files(Files, DirS, Fd). 455 456public_predicate(Public, PI) :- 457 '$member'(PI0, Public), 458 canonical_pi(PI0, PI). 459 460canonical_pi(Var, _) :- 461 var(Var), !, fail. 462canonical_pi(Name/Arity, Name/Arity). 463canonical_pi(Name//A0, Name/Arity) :- 464 Arity is A0 + 2. 465 466 467index_header(Fd):- 468 format(Fd, '/* Creator: make/0~n~n', []), 469 format(Fd, ' Purpose: Provide index for autoload~n', []), 470 format(Fd, '*/~n~n', []).
476:- public exports/3. % using by library(prolog_deps). 477exports(File, Module, Exports) :- 478 ( current_prolog_flag(xref, Old) 479 -> true 480 ; Old = false 481 ), 482 setup_call_cleanup( 483 set_prolog_flag(xref, true), 484 snapshot(exports_(File, Module, Exports)), 485 set_prolog_flag(xref, Old)). 486 487exports_(File, Module, Exports) :- 488 State = state(true, _, []), 489 ( '$source_term'(File, 490 _Read,_RLayout, 491 Term,_TermLayout, 492 _Stream, 493 [ syntax_errors(quiet) 494 ]), 495 ( Term = (:- module(M,Public)), 496 is_list(Public), 497 arg(1, State, true) 498 -> nb_setarg(1, State, false), 499 nb_setarg(2, State, M), 500 nb_setarg(3, State, Public), 501 fail 502 ; nb_setarg(1, State, false), 503 fail 504 ; Term = (:- export(Export)) 505 -> phrase(export_pi(Export), PIs), 506 arg(3, State, E0), 507 '$append'(E0, PIs, E1), 508 nb_setarg(3, State, E1), 509 fail 510 ; Term = (:- use_foreign_library(Lib)), 511 nonvar(Lib), 512 arg(2, State, M), 513 atom(M) 514 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true), 515 fail 516 ; Term = (:- Directive), 517 nonvar(Directive) 518 -> fail 519 ; Term == [] % Expansion for conditionals 520 -> fail 521 ; ! 522 ) 523 ; true 524 ), 525 arg(2, State, Module), 526 arg(3, State, Exports). 527 528export_pi(Var) --> 529 { var(Var) }, 530 !. 531export_pi((A,B)) --> 532 !, 533 export_pi(A), 534 export_pi(B). 535export_pi(PI) --> 536 { ground(PI) }, 537 [PI]. 538 539 540 /******************************* 541 * EXTENDING * 542 *******************************/
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.
559autoload_path(Alias) :- 560 ( user:file_search_path(autoload, Alias) 561 -> true 562 ; assertz(user:file_search_path(autoload, Alias)), 563 reload_library_index 564 ). 565 566systemterm_expansion((:- autoload_path(Alias)), 567 [ user:file_search_path(autoload, Alias), 568 (:- reload_library_index) 569 ]). 570 571 572 /******************************* 573 * RUNTIME AUTOLOADER * 574 *******************************/
current_prolog_flag(autoload, true)
holds.584'$autoload'(PI) :- 585 source_location(File, _Line), 586 !, 587 setup_call_cleanup( 588 '$start_aux'(File, Context), 589 '$autoload2'(PI), 590 '$end_aux'(File, Context)). 591'$autoload'(PI) :- 592 '$autoload2'(PI). 593 594'$autoload2'(PI) :- 595 setup_call_cleanup( 596 leave_sandbox(Old), 597 '$autoload3'(PI), 598 restore_sandbox(Old)). 599 600leave_sandbox(Sandboxed) :- 601 current_prolog_flag(sandboxed_load, Sandboxed), 602 set_prolog_flag(sandboxed_load, false). 603restore_sandbox(Sandboxed) :- 604 set_prolog_flag(sandboxed_load, Sandboxed). 605 606'$autoload3'(PI) :- 607 autoload_from(PI, LoadModule, FullFile), 608 do_autoload(FullFile, PI, LoadModule).
615autoload_from(Module:PI, LoadModule, FullFile) :- 616 autoload_in(Module, explicit), 617 current_autoload(Module:File, Ctx, import(Imports)), 618 memberchk(PI, Imports), 619 library_info(File, Ctx, FullFile, LoadModule, Exports), 620 ( pi_in_exports(PI, Exports) 621 -> ! 622 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)), 623 fail 624 ). 625autoload_from(Module:Name/Arity, LoadModule, FullFile) :- 626 autoload_in(Module, explicit), 627 PI = Name/Arity, 628 current_autoload(Module:File, Ctx, all), 629 library_info(File, Ctx, FullFile, LoadModule, Exports), 630 pi_in_exports(PI, Exports). 631autoload_from(Module:Name/Arity, LoadModule, Library) :- 632 autoload_in(Module, general), 633 '$find_library'(Module, Name, Arity, LoadModule, Library). 634 635:- public autoload_in/2. % used in syspred 636 637autoload_in(Module, How) :- 638 current_prolog_flag(autoload, AutoLoad), 639 autoload_in(AutoLoad, How, Module), 640 !.
644autoload_in(true, _, _). 645autoload_in(explicit, explicit, _). 646autoload_in(user, _, user). 647autoload_in(user_or_explicit, explicit, _). 648autoload_in(user_or_explicit, _, user).
user
. '$c_current_predicate'/2
verifies the predicate really exists, but doesn't validate
that it is defined.664do_autoload(Library, Module:Name/Arity, LoadModule) :- 665 functor(Head, Name, Arity), 666 '$update_autoload_level'([autoload(true)], Old), 667 verbose_autoload(Module:Name/Arity, Library), 668 '$compilation_mode'(OldComp, database), 669 ( Module == LoadModule 670 -> ensure_loaded(Module:Library) 671 ; ( '$c_current_predicate'(_, LoadModule:Head), 672 '$get_predicate_attribute'(LoadModule:Head, defined, 1), 673 \+ '$loading'(Library) 674 -> Module:import(LoadModule:Name/Arity) 675 ; use_module(Module:Library, [Name/Arity]) 676 ), 677 warn_autoload(Module, LoadModule:Name/Arity) 678 ), 679 '$set_compilation_mode'(OldComp), 680 '$set_autoload_level'(Old), 681 '$c_current_predicate'(_, Module:Head). 682 683verbose_autoload(PI, Library) :- 684 current_prolog_flag(verbose_autoload, true), 685 !, 686 set_prolog_flag(verbose_autoload, false), 687 print_message(informational, autoload(PI, Library)), 688 set_prolog_flag(verbose_autoload, true). 689verbose_autoload(PI, Library) :- 690 print_message(silent, autoload(PI, Library)).
autoload(File)
. The module must be
instantiated.699:- public % used from predicate_property/2 700 autoloadable/2. 701 702autoloadable(M:Head, FullFile) :- 703 atom(M), 704 current_module(M), 705 autoload_in(M, explicit), 706 ( callable(Head) 707 -> goal_name_arity(Head, Name, Arity), 708 autoload_from(M:Name/Arity, _, FullFile) 709 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs), 710 ( '$member'(M:Head-FullFile, Pairs) 711 ; current_autoload(M:File, Ctx, all), 712 library_info(File, Ctx, FullFile, _, Exports), 713 '$member'(PI, Exports), 714 '$pi_head'(PI, Head), 715 \+ memberchk(M:Head-_, Pairs) 716 ) 717 ). 718autoloadable(M:Head, FullFile) :- 719 ( var(M) 720 -> autoload_in(any, general) 721 ; autoload_in(M, general) 722 ), 723 ( callable(Head) 724 -> goal_name_arity(Head, Name, Arity), 725 ( '$find_library'(_, Name, Arity, _, FullFile) 726 -> true 727 ) 728 ; '$in_library'(Name, Arity, autoload), 729 functor(Head, Name, Arity) 730 ). 731 732 733autoloadable_2(M:Head, FullFile) :- 734 current_autoload(M:File, Ctx, import(Imports)), 735 library_info(File, Ctx, FullFile, _LoadModule, _Exports), 736 '$member'(PI, Imports), 737 '$pi_head'(PI, Head). 738 739goal_name_arity(Head, Name, Arity) :- 740 compound(Head), 741 !, 742 compound_name_arity(Head, Name, Arity). 743goal_name_arity(Head, Head, 0).
749library_info(Spec, _, FullFile, Module, Exports) :- 750 '$resolved_source_path'(Spec, FullFile, []), 751 !, 752 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread) 753 -> '$current_module'(Module, FullFile), 754 '$module_property'(Module, exports(Exports)) 755 ; library_info_from_file(FullFile, Module, Exports) 756 ). 757library_info(Spec, Context, FullFile, Module, Exports) :- 758 ( Context = (Path:_Line) 759 -> Extra = [relative_to(Path)] 760 ; Extra = [] 761 ), 762 ( absolute_file_name(Spec, FullFile, 763 [ file_type(prolog), 764 access(read), 765 file_errors(fail) 766 | Extra 767 ]) 768 -> '$register_resolved_source_path'(Spec, FullFile), 769 library_info_from_file(FullFile, Module, Exports) 770 ; autoload_error(Context, no_file(Spec)), 771 fail 772 ). 773 774library_info_from_file(FullFile, Module, Exports) :- 775 setup_call_cleanup( 776 '$set_source_module'(OldModule, system), 777 setup_call_cleanup( 778 '$open_source'(FullFile, In, State, [], []), 779 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream, 780 [FullFile], []), 781 '$close_source'(State, true)), 782 '$set_source_module'(OldModule)), 783 ( Term = (:- module(Module, Exports)) 784 -> ! 785 ; nonvar(Term), 786 skip_header(Term) 787 -> fail 788 ; '$domain_error'(module_header, Term) 789 ). 790 791skip_header(begin_of_file). 792 793 794:- dynamic printed/3. 795:- volatile printed/3. 796 797autoload_error(Context, Error) :- 798 suppress(Context, Error), 799 !. 800autoload_error(Context, Error) :- 801 get_time(Now), 802 assertz(printed(Context, Error, Now)), 803 print_message(warning, error(autoload(Error), autoload(Context))). 804 805suppress(Context, Error) :- 806 printed(Context, Error, Printed), 807 get_time(Now), 808 ( Now - Printed < 1 809 -> true 810 ; retractall(printed(Context, Error, _)), 811 fail 812 ). 813 814 815 /******************************* 816 * CALLBACK * 817 *******************************/ 818 819:- public 820 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.829set_autoload(FlagValue) :- 830 current_prolog_flag(autoload, FlagValue), 831 !. 832set_autoload(FlagValue) :- 833 \+ autoload_in(FlagValue, explicit, any), 834 !, 835 setup_call_cleanup( 836 nb_setval('$autoload_disabling', true), 837 materialize_autoload(Count), 838 nb_delete('$autoload_disabling')), 839 print_message(informational, autoload(disabled(Count))). 840set_autoload(_). 841 842materialize_autoload(Count) :- 843 State = state(0), 844 forall(current_predicate(M:'$autoload'/3), 845 materialize_autoload(M, State)), 846 arg(1, State, Count). 847 848materialize_autoload(M, State) :- 849 ( current_autoload(M:File, Context, Import), 850 library_info(File, Context, FullFile, _LoadModule, _Exports), 851 arg(1, State, N0), 852 N is N0+1, 853 nb_setarg(1, State, N), 854 ( Import == all 855 -> verbose_autoload(M:all, FullFile), 856 use_module(M:FullFile) 857 ; Import = import(Preds) 858 -> verbose_autoload(M:Preds, FullFile), 859 use_module(M:FullFile, Preds) 860 ), 861 fail 862 ; true 863 ), 864 abolish(M:'$autoload'/3). 865 866 867 /******************************* 868 * AUTOLOAD/2 * 869 *******************************/ 870 871autoload(M:File) :- 872 ( \+ autoload_in(M, explicit) 873 ; nb_current('$autoload_disabling', true) 874 ), 875 !, 876 use_module(M:File). 877autoload(M:File) :- 878 '$must_be'(filespec, File), 879 source_context(Context), 880 ( current_autoload(M:File, _, import(all)) 881 -> true 882 ; assert_autoload(M:'$autoload'(File, Context, all)) 883 ). 884 885autoload(M:File, Imports) :- 886 ( \+ autoload_in(M, explicit) 887 ; nb_current('$autoload_disabling', true) 888 ), 889 !, 890 use_module(M:File, Imports). 891autoload(M:File, Imports0) :- 892 '$must_be'(filespec, File), 893 valid_imports(Imports0, Imports), 894 source_context(Context), 895 register_autoloads(Imports, M, File, Context), 896 ( current_autoload(M:File, _, import(Imports)) 897 -> true 898 ; assert_autoload(M:'$autoload'(File, Context, import(Imports))) 899 ). 900 901source_context(Path:Line) :- 902 source_location(Path, Line), 903 !. 904source_context(-). 905 906assert_autoload(Clause) :- 907 '$initialization_context'(Source, Ctx), 908 '$store_admin_clause2'(Clause, _Layout, Source, Ctx). 909 910valid_imports(Imports0, Imports) :- 911 '$must_be'(list, Imports0), 912 valid_import_list(Imports0, Imports). 913 914valid_import_list([], []). 915valid_import_list([H0|T0], [H|T]) :- 916 '$pi_head'(H0, Head), 917 '$pi_head'(H, Head), 918 valid_import_list(T0, T).
autoload
flag on all predicates declared using autoload/2
to prevent duplicates or the user defining the same predicate.925register_autoloads([], _, _, _). 926register_autoloads([PI|T], Module, File, Context) :- 927 PI = Name/Arity, 928 functor(Head, Name, Arity), 929 ( '$get_predicate_attribute'(Module:Head, autoload, 1) 930 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)), 931 memberchk(PI, Imports) 932 -> '$permission_error'(redefine, imported_procedure, PI), 933 fail 934 ; Done = true 935 ) 936 ; '$c_current_predicate'(_, Module:Head), % no auto-import 937 '$get_predicate_attribute'(Module:Head, imported, From) 938 -> ( ( '$resolved_source_path'(File, FullFile) 939 -> true 940 ; '$resolve_source_path'(File, FullFile, []) 941 ), 942 module_property(From, file(FullFile)) 943 -> Done = true 944 ; print_message(warning, 945 autoload(already_defined(Module:PI, From))), 946 Done = true 947 ) 948 ; true 949 ), 950 ( Done == true 951 -> true 952 ; '$set_predicate_attribute'(Module:Head, autoload, 1) 953 ), 954 register_autoloads(T, Module, File, Context). 955 956pi_in_exports(PI, Exports) :- 957 '$member'(E, Exports), 958 canonical_pi(E, PI), 959 !. 960 961current_autoload(M:File, Context, Term) :- 962 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1), 963 M:'$autoload'(File, Context, Term). 964 965 /******************************* 966 * CHECK * 967 *******************************/
973warn_autoload(TargetModule, PI) :- 974 current_prolog_flag(warn_autoload, true), 975 \+ current_prolog_flag(xref, true), 976 \+ nb_current('$autoload_warning', true), 977 \+ nowarn_autoload(TargetModule, PI), 978 '$pi_head'(PI, Head), 979 source_file(Head, File), 980 expansion_hook(P), 981 source_file(P, File), 982 !, 983 setup_call_cleanup( 984 b_setval('$autoload_warning', true), 985 print_message(warning, 986 deprecated(autoload(TargetModule, File, PI, expansion))), 987 nb_delete('$autoload_warning')). 988warn_autoload(_, _). 989 990expansion_hook(user:goal_expansion(_,_)). 991expansion_hook(user:goal_expansion(_,_,_,_)). 992expansion_hook(system:goal_expansion(_,_)). 993expansion_hook(system:goal_expansion(_,_,_,_)).
1008nowarn_autoload(TargetModule, LoadModule:PI) :- 1009 NoWarn = LoadModule:'$nowarn_autoload'(PI,TargetModule), 1010 '$c_current_predicate'(_, NoWarn), 1011 \+ '$get_predicate_attribute'(NoWarn, imported, _From), 1012 call(NoWarn). 1013 1014 1015 /******************************* 1016 * REQUIRE * 1017 *******************************/
1024require(M:Spec) :- 1025 ( is_list(Spec) 1026 -> List = Spec 1027 ; phrase(comma_list(Spec), List) 1028 ), !, 1029 require(List, M, FromLib), 1030 keysort(FromLib, Sorted), 1031 by_file(Sorted, Autoload), 1032 forall('$member'(File-Import, Autoload), 1033 autoload(M:File, Import)). 1034require(_:Spec) :- 1035 '$type_error'(list, Spec). 1036 1037require([],_, []). 1038require([H|T], M, Needed) :- 1039 '$pi_head'(H, Head), 1040 ( '$get_predicate_attribute'(system:Head, defined, 1) 1041 -> require(T, M, Needed) 1042 ; '$pi_head'(Module:Name/Arity, M:Head), 1043 ( '$find_library'(Module, Name, Arity, LoadModule, Library) 1044 -> ( current_predicate(LoadModule:Name/Arity) 1045 -> Module:import(LoadModule:Name/Arity), 1046 require(T, M, Needed) 1047 ; Needed = [Library-H|More], 1048 require(T, M, More) 1049 ) 1050 ; print_message(error, error(existence_error(procedure, Name/Arity), _)), 1051 require(T, M, Needed) 1052 ) 1053 ). 1054 1055by_file([], []). 1056by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :- 1057 on_path(File, Spec), 1058 same_file(T0, File, PIs, T1), 1059 by_file(T1, T). 1060 1061on_path(Library, library(Base)) :- 1062 file_base_name(Library, Base), 1063 findall(Path, plain_source(library(Base), Path), [Library]), 1064 !. 1065on_path(Library, Library). 1066 1067plain_source(Spec, Path) :- 1068 absolute_file_name(Spec, PathExt, 1069 [ file_type(prolog), 1070 access(read), 1071 file_errors(fail), 1072 solutions(all) 1073 ]), 1074 file_name_extension(Path, _, PathExt). 1075 1076same_file([File-PI|T0], File, [PI|PIs], T) :- 1077 !, 1078 same_file(T0, File, PIs, T). 1079same_file(List, _, [], List). 1080 1081comma_list(Var) --> 1082 { var(Var), 1083 !, 1084 '$instantiation_error'(Var) 1085 }. 1086comma_list((A,B)) --> 1087 !, 1088 comma_list(A), 1089 comma_list(B). 1090comma_list(A) --> 1091 [A]