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-2020, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module('$autoload', 38 [ '$find_library'/5, 39 '$in_library'/3, 40 '$define_predicate'/1, 41 '$update_library_index'/0, 42 '$autoload'/1, 43 44 make_library_index/1, 45 make_library_index/2, 46 reload_library_index/0, 47 autoload_path/1, 48 49 autoload/1, % +File 50 autoload/2, % +File, +Imports 51 52 require/1 % +Predicates 53 ]). 54 55:- meta_predicate 56 '$autoload'( ), 57 autoload( ), 58 autoload( , ), 59 require( ). 60 61:- dynamic 62 library_index/3, % Head x Module x Path 63 autoload_directories/1, % List 64 index_checked_at/1. % Time 65:- volatile 66 library_index/3, 67 autoload_directories/1, 68 index_checked_at/1. 69 70user:file_search_path(autoload, swi(library)). 71user:file_search_path(autoload, pce(prolog/lib)). 72user:file_search_path(autoload, app_config(lib)).
83'$find_library'(Module, Name, Arity, LoadModule, Library) :-
84 load_library_index(Name, Arity),
85 functor(Head, Name, Arity),
86 ( library_index(Head, Module, Library),
87 LoadModule = Module
88 ; library_index(Head, LoadModule, Library)
89 ),
90 !.
97'$in_library'(Name, Arity, Path) :- 98 atom(Name), integer(Arity), 99 !, 100 load_library_index(Name, Arity), 101 functor(Head, Name, Arity), 102 library_index(Head, _, Path). 103'$in_library'(Name, Arity, Path) :- 104 load_library_index(Name, Arity), 105 library_index(Head, _, Path), 106 functor(Head, Name, Arity).
113:- meta_predicate 114 '$define_predicate'( ). 115 116'$define_predicate'(Head) :- 117 '$defined_predicate'(Head), 118 !. 119'$define_predicate'(Term) :- 120 Term = Module:Head, 121 ( compound(Head) 122 -> compound_name_arity(Head, Name, Arity) 123 ; Name = Head, Arity = 0 124 ), 125 '$undefined_procedure'(Module, Name, Arity, retry). 126 127 128 /******************************** 129 * UPDATE INDEX * 130 ********************************/ 131 132:- thread_local 133 silent/0.
142'$update_library_index' :- 143 setof(Dir, writable_indexed_directory(Dir), Dirs), 144 !, 145 setup_call_cleanup( 146 asserta(silent, Ref), 147 guarded_make_library_index(Dirs), 148 erase(Ref)), 149 ( flag('$modified_index', true, false) 150 -> reload_library_index 151 ; true 152 ). 153'$update_library_index'. 154 155guarded_make_library_index([]). 156guarded_make_library_index([Dir|Dirs]) :- 157 ( catch(make_library_index(Dir), E, 158 print_message(error, E)) 159 -> true 160 ; print_message(warning, goal_failed(make_library_index(Dir))) 161 ), 162 guarded_make_library_index(Dirs).
169writable_indexed_directory(Dir) :- 170 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]), 171 file_directory_name(IndexFile, Dir). 172writable_indexed_directory(Dir) :- 173 absolute_file_name(library('MKINDEX'), 174 [ file_type(prolog), 175 access(read), 176 solutions(all), 177 file_errors(fail) 178 ], MkIndexFile), 179 file_directory_name(MkIndexFile, Dir), 180 plfile_in_dir(Dir, 'INDEX', _, IndexFile), 181 access_file(IndexFile, write). 182 183 184 /******************************** 185 * LOAD INDEX * 186 ********************************/
192reload_library_index :- 193 context_module(M), 194 reload_library_index(M). 195 196reload_library_index(M) :- 197 with_mutex('$autoload', clear_library_index(M)). 198 199clear_library_index(M) :- 200 retractall(M:library_index(_, _, _)), 201 retractall(M:autoload_directories(_)), 202 retractall(M:index_checked_at(_)).
212:- meta_predicate load_library_index( , , ). 213:- public load_library_index/3. 214 215load_library_index(Name, Arity) :- 216 load_library_index(Name, Arity, autoload('INDEX')). 217 218load_library_index(Name, Arity, M:_Spec) :- 219 atom(Name), integer(Arity), 220 functor(Head, Name, Arity), 221 M:library_index(Head, _, _), 222 !. 223load_library_index(_, _, Spec) :- 224 notrace(with_mutex('$autoload', load_library_index_p(Spec))). 225 226load_library_index_p(M:_) :- 227 M:index_checked_at(Time), 228 get_time(Now), 229 Now-Time < 60, 230 !. 231load_library_index_p(M:Spec) :- 232 findall(Index, index_file_name(Index, Spec, [access(read)]), List0), 233 '$list_to_set'(List0, List), 234 retractall(M:index_checked_at(_)), 235 get_time(Now), 236 assert(M:index_checked_at(Now)), 237 ( M:autoload_directories(List) 238 -> true 239 ; retractall(M:library_index(_, _, _)), 240 retractall(M:autoload_directories(_)), 241 read_index(List, M), 242 assert(M:autoload_directories(List)) 243 ).
autoload
.
253index_file_name(IndexFile, FileSpec, Options) :- 254 absolute_file_name(FileSpec, 255 IndexFile, 256 [ file_type(prolog), 257 solutions(all), 258 file_errors(fail) 259 | Options 260 ]). 261 262read_index([], _) :- !. 263read_index([H|T], M) :- 264 !, 265 read_index(H, M), 266 read_index(T, M). 267read_index(Index, M) :- 268 print_message(silent, autoload(read_index(Dir))), 269 file_directory_name(Index, Dir), 270 setup_call_cleanup( 271 '$push_input_context'(autoload_index), 272 setup_call_cleanup( 273 open(Index, read, In), 274 read_index_from_stream(Dir, In, M), 275 close(In)), 276 '$pop_input_context'). 277 278read_index_from_stream(Dir, In, M) :- 279 repeat, 280 read(In, Term), 281 assert_index(Term, Dir, M), 282 !. 283 284assert_index(end_of_file, _, _) :- !. 285assert_index(index(Name, Arity, Module, File), Dir, M) :- 286 !, 287 functor(Head, Name, Arity), 288 atomic_list_concat([Dir, '/', File], Path), 289 assertz(M:library_index(Head, Module, Path)), 290 fail. 291assert_index(Term, Dir, _) :- 292 print_message(error, illegal_autoload_index(Dir, Term)), 293 fail. 294 295 296 /******************************** 297 * CREATE INDEX.pl * 298 ********************************/
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.
311make_library_index(Dir0) :- 312 forall(absolute_file_name(Dir0, Dir, 313 [ expand(true), 314 file_type(directory), 315 file_errors(fail), 316 solutions(all) 317 ]), 318 make_library_index2(Dir)). 319 320make_library_index2(Dir) :- 321 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex), 322 access_file(AbsMkIndex, read), 323 !, 324 load_files(user:AbsMkIndex, [silent(true)]). 325make_library_index2(Dir) :- 326 findall(Pattern, source_file_pattern(Pattern), PatternList), 327 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']).
342make_library_index(Dir0, Patterns) :- 343 forall(absolute_file_name(Dir0, Dir, 344 [ expand(true), 345 file_type(directory), 346 file_errors(fail), 347 solutions(all) 348 ]), 349 make_library_index2(Dir, Patterns)). 350 351make_library_index2(Dir, Patterns) :- 352 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex), 353 ensure_slash(Dir, DirS), 354 pattern_files(Patterns, DirS, Files), 355 ( library_index_out_of_date(Dir, AbsIndex, Files) 356 -> do_make_library_index(AbsIndex, DirS, Files), 357 flag('$modified_index', _, true) 358 ; true 359 ). 360 361ensure_slash(Dir, DirS) :- 362 ( sub_atom(Dir, _, _, 0, /) 363 -> DirS = Dir 364 ; atom_concat(Dir, /, DirS) 365 ). 366 367source_file_pattern(Pattern) :- 368 user:prolog_file_type(PlExt, prolog), 369 PlExt \== qlf, 370 atom_concat('*.', PlExt, Pattern). 371 372plfile_in_dir(Dir, Base, PlBase, File) :- 373 file_name_extension(Base, pl, PlBase), 374 atomic_list_concat([Dir, '/', PlBase], File). 375 376pattern_files([], _, []). 377pattern_files([H|T], DirS, Files) :- 378 atom_concat(DirS, H, P0), 379 expand_file_name(P0, Files0), 380 '$append'(Files0, Rest, Files), 381 pattern_files(T, DirS, Rest). 382 383library_index_out_of_date(_Dir, Index, _Files) :- 384 \+ exists_file(Index), 385 !. 386library_index_out_of_date(Dir, Index, Files) :- 387 time_file(Index, IndexTime), 388 ( time_file(Dir, DotTime), 389 DotTime > IndexTime 390 ; '$member'(File, Files), 391 time_file(File, FileTime), 392 FileTime > IndexTime 393 ), 394 !. 395 396 397do_make_library_index(Index, Dir, Files) :- 398 ensure_slash(Dir, DirS), 399 '$stage_file'(Index, StagedIndex), 400 setup_call_catcher_cleanup( 401 open(StagedIndex, write, Out), 402 ( print_message(informational, make(library_index(Dir))), 403 index_header(Out), 404 index_files(Files, DirS, Out) 405 ), 406 Catcher, 407 install_index(Out, Catcher, StagedIndex, Index)). 408 409install_index(Out, Catcher, StagedIndex, Index) :- 410 catch(close(Out), Error, true), 411 ( silent 412 -> OnError = silent 413 ; OnError = error 414 ), 415 ( var(Error) 416 -> TheCatcher = Catcher 417 ; TheCatcher = exception(Error) 418 ), 419 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
425index_files([], _, _). 426index_files([File|Files], DirS, Fd) :- 427 catch(setup_call_cleanup( 428 open(File, read, In), 429 read(In, Term), 430 close(In)), 431 E, print_message(warning, E)), 432 ( Term = (:- module(Module, Public)), 433 is_list(Public) 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', []). 458 459 460 /******************************* 461 * EXTENDING * 462 *******************************/
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.
479autoload_path(Alias) :- 480 ( user:file_search_path(autoload, Alias) 481 -> true 482 ; assertz(user:file_search_path(autoload, Alias)), 483 reload_library_index 484 ). 485 486systemterm_expansion((:- autoload_path(Alias)), 487 [ user:file_search_path(autoload, Alias), 488 (:- reload_library_index) 489 ]). 490 491 492 /******************************* 493 * RUNTIME AUTOLOADER * 494 *******************************/
current_prolog_flag(autoload, true)
holds.504'$autoload'(PI) :- 505 source_location(File, _Line), 506 !, 507 setup_call_cleanup( 508 '$start_aux'(File, Context), 509 '$autoload2'(PI), 510 '$end_aux'(File, Context)). 511'$autoload'(PI) :- 512 '$autoload2'(PI). 513 514'$autoload2'(PI) :- 515 setup_call_cleanup( 516 leave_sandbox(Old), 517 '$autoload3'(PI), 518 restore_sandbox(Old)). 519 520leave_sandbox(Sandboxed) :- 521 current_prolog_flag(sandboxed_load, Sandboxed), 522 set_prolog_flag(sandboxed_load, false). 523restore_sandbox(Sandboxed) :- 524 set_prolog_flag(sandboxed_load, Sandboxed). 525 526'$autoload3'(PI) :- 527 autoload_from(PI, LoadModule, FullFile), 528 do_autoload(FullFile, PI, LoadModule).
535autoload_from(Module:PI, LoadModule, FullFile) :- 536 autoload_in(Module, explicit), 537 current_autoload(Module:File, Ctx, import(Imports)), 538 memberchk(PI, Imports), 539 library_info(File, Ctx, FullFile, LoadModule, Exports), 540 ( pi_in_exports(PI, Exports) 541 -> ! 542 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)), 543 fail 544 ). 545autoload_from(Module:Name/Arity, LoadModule, FullFile) :- 546 autoload_in(Module, explicit), 547 PI = Name/Arity, 548 current_autoload(Module:File, Ctx, all), 549 library_info(File, Ctx, FullFile, LoadModule, Exports), 550 pi_in_exports(PI, Exports). 551autoload_from(Module:Name/Arity, LoadModule, Library) :- 552 autoload_in(Module, general), 553 '$find_library'(Module, Name, Arity, LoadModule, Library). 554 555:- public autoload_in/2. % used in syspred 556 557autoload_in(Module, How) :- 558 current_prolog_flag(autoload, AutoLoad), 559 autoload_in(AutoLoad, How, Module), 560 !.
564autoload_in(true, _, _). 565autoload_in(explicit, explicit, _). 566autoload_in(explicit_or_user, explicit, _). 567autoload_in(user, explicit, user). 568autoload_in(explicit_or_user, explicit, _). 569autoload_in(user, _, user). 570autoload_in(explicit_or_user, general, user).
user
. '$c_current_predicate'/2
verifies the predicate really exists, but doesn't validate
that it is defined.586do_autoload(Library, Module:Name/Arity, LoadModule) :- 587 functor(Head, Name, Arity), 588 '$update_autoload_level'([autoload(true)], Old), 589 verbose_autoload(Module:Name/Arity, Library), 590 '$compilation_mode'(OldComp, database), 591 ( Module == LoadModule 592 -> ensure_loaded(Module:Library) 593 ; ( '$c_current_predicate'(_, LoadModule:Head), 594 '$get_predicate_attribute'(LoadModule:Head, defined, 1), 595 \+ '$loading'(Library) 596 -> Module:import(LoadModule:Name/Arity) 597 ; use_module(Module:Library, [Name/Arity]) 598 ) 599 ), 600 '$set_compilation_mode'(OldComp), 601 '$set_autoload_level'(Old), 602 '$c_current_predicate'(_, Module:Head). 603 604verbose_autoload(PI, Library) :- 605 current_prolog_flag(verbose_autoload, true), 606 !, 607 set_prolog_flag(verbose_autoload, false), 608 print_message(informational, autoload(PI, Library)), 609 set_prolog_flag(verbose_autoload, true). 610verbose_autoload(PI, Library) :- 611 print_message(silent, autoload(PI, Library)).
autoload(File)
. The module muse be
instantiated.620:- public % used from predicate_property/2 621 autoloadable/2. 622 623autoloadable(M:Head, FullFile) :- 624 atom(M), 625 current_module(M), 626 autoload_in(M, explicit), 627 ( callable(Head) 628 -> goal_name_arity(Head, Name, Arity), 629 autoload_from(M:Name/Arity, _, FullFile) 630 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs), 631 ( '$member'(M:Head-FullFile, Pairs) 632 ; current_autoload(M:File, Ctx, all), 633 library_info(File, Ctx, FullFile, _, Exports), 634 '$member'(PI, Exports), 635 '$pi_head'(PI, Head), 636 \+ memberchk(M:Head-_, Pairs) 637 ) 638 ). 639autoloadable(M:Head, FullFile) :- 640 ( var(M) 641 -> autoload_in(any, general) 642 ; autoload_in(M, general) 643 ), 644 ( callable(Head) 645 -> goal_name_arity(Head, Name, Arity), 646 ( '$find_library'(_, Name, Arity, _, FullFile) 647 -> true 648 ) 649 ; '$in_library'(Name, Arity, autoload), 650 functor(Head, Name, Arity) 651 ). 652 653 654autoloadable_2(M:Head, FullFile) :- 655 current_autoload(M:File, Ctx, import(Imports)), 656 library_info(File, Ctx, FullFile, _LoadModule, _Exports), 657 '$member'(PI, Imports), 658 '$pi_head'(PI, Head). 659 660goal_name_arity(Head, Name, Arity) :- 661 compound(Head), 662 !, 663 compound_name_arity(Head, Name, Arity). 664goal_name_arity(Head, Head, 0).
670library_info(Spec, _, FullFile, Module, Exports) :- 671 '$resolved_source_path'(Spec, FullFile, []), 672 !, 673 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread) 674 -> '$current_module'(Module, FullFile), 675 '$module_property'(Module, exports(Exports)) 676 ; library_info_from_file(FullFile, Module, Exports) 677 ). 678library_info(Spec, Context, FullFile, Module, Exports) :- 679 ( Context = (Path:_Line) 680 -> Extra = [relative_to(Path)] 681 ; Extra = [] 682 ), 683 ( absolute_file_name(Spec, FullFile, 684 [ file_type(prolog), 685 access(read), 686 file_errors(fail) 687 | Extra 688 ]) 689 -> '$register_resolved_source_path'(Spec, FullFile), 690 library_info_from_file(FullFile, Module, Exports) 691 ; autoload_error(Context, no_file(Spec)), 692 fail 693 ). 694 695 696library_info_from_file(FullFile, Module, Exports) :- 697 setup_call_cleanup( 698 '$open_source'(FullFile, In, State, [], []), 699 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream, 700 [FullFile], []), 701 '$close_source'(State, true)), 702 ( Term = (:- module(Module, Exports)) 703 -> ! 704 ; nonvar(Term), 705 skip_header(Term) 706 -> fail 707 ; '$domain_error'(module_header, Term) 708 ). 709 710skip_header(begin_of_file). 711 712 713:- dynamic printed/3. 714:- volatile printed/3. 715 716autoload_error(Context, Error) :- 717 suppress(Context, Error), 718 !. 719autoload_error(Context, Error) :- 720 get_time(Now), 721 assertz(printed(Context, Error, Now)), 722 print_message(warning, error(autoload(Error), autoload(Context))). 723 724suppress(Context, Error) :- 725 printed(Context, Error, Printed), 726 get_time(Now), 727 ( Now - Printed < 1 728 -> true 729 ; retractall(printed(Context, Error, _)), 730 fail 731 ). 732 733 734 /******************************* 735 * CALLBACK * 736 *******************************/ 737 738:- public 739 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.748set_autoload(FlagValue) :- 749 current_prolog_flag(autoload, FlagValue), 750 !. 751set_autoload(FlagValue) :- 752 \+ autoload_in(FlagValue, explicit, any), 753 !, 754 setup_call_cleanup( 755 nb_setval('$autoload_disabling', true), 756 materialize_autoload(Count), 757 nb_delete('$autoload_disabling')), 758 print_message(informational, autoload(disabled(Count))). 759set_autoload(_). 760 761materialize_autoload(Count) :- 762 State = state(0), 763 forall(current_predicate(M:'$autoload'/3), 764 materialize_autoload(M, State)), 765 arg(1, State, Count). 766 767materialize_autoload(M, State) :- 768 ( current_autoload(M:File, Context, Import), 769 library_info(File, Context, FullFile, _LoadModule, _Exports), 770 arg(1, State, N0), 771 N is N0+1, 772 nb_setarg(1, State, N), 773 ( Import == all 774 -> verbose_autoload(M:all, FullFile), 775 use_module(M:FullFile) 776 ; Import = import(Preds) 777 -> verbose_autoload(M:Preds, FullFile), 778 use_module(M:FullFile, Preds) 779 ), 780 fail 781 ; true 782 ), 783 abolish(M:'$autoload'/3). 784 785 786 /******************************* 787 * AUTOLOAD/2 * 788 *******************************/ 789 790autoload(M:File) :- 791 ( \+ autoload_in(M, explicit) 792 ; nb_current('$autoload_disabling', true) 793 ), 794 !, 795 use_module(M:File). 796autoload(M:File) :- 797 '$must_be'(filespec, File), 798 source_context(Context), 799 retractall(M:'$autoload'(File, _, _)), 800 assert_autoload(M:'$autoload'(File, Context, all)). 801 802autoload(M:File, Imports) :- 803 ( \+ autoload_in(M, explicit) 804 ; nb_current('$autoload_disabling', true) 805 ), 806 !, 807 use_module(M:File, Imports). 808autoload(M:File, Imports0) :- 809 '$must_be'(filespec, File), 810 valid_imports(Imports0, Imports), 811 source_context(Context), 812 register_autoloads(Imports, M, File, Context), 813 ( current_autoload(M:File, _, import(Imports)) 814 -> true 815 ; assert_autoload(M:'$autoload'(File, Context, import(Imports))) 816 ). 817 818source_context(Path:Line) :- 819 source_location(Path, Line), 820 !. 821source_context(-). 822 823assert_autoload(Clause) :- 824 '$initialization_context'(Source, Ctx), 825 '$store_admin_clause2'(Clause, _Layout, Source, Ctx). 826 827valid_imports(Imports0, Imports) :- 828 '$must_be'(list, Imports0), 829 valid_import_list(Imports0, Imports). 830 831valid_import_list([], []). 832valid_import_list([H0|T0], [H|T]) :- 833 '$pi_head'(H0, Head), 834 '$pi_head'(H, Head), 835 valid_import_list(T0, T).
autoload
flag on all predicates declared using autoload/2
to prevent duplicates or the user defining the same predicate.842register_autoloads([], _, _, _). 843register_autoloads([PI|T], Module, File, Context) :- 844 PI = Name/Arity, 845 functor(Head, Name, Arity), 846 ( '$get_predicate_attribute'(Module:Head, autoload, 1) 847 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)), 848 memberchk(PI, Imports) 849 -> '$permission_error'(redefine, imported_procedure, PI), 850 fail 851 ; Done = true 852 ) 853 ; '$c_current_predicate'(_, Module:Head), % no auto-import 854 '$get_predicate_attribute'(Module:Head, imported, From) 855 -> ( ( '$resolved_source_path'(File, FullFile) 856 -> true 857 ; '$resolve_source_path'(File, FullFile, []) 858 ), 859 module_property(From, file(FullFile)) 860 -> Done = true 861 ; print_message(warning, 862 autoload(already_defined(Module:PI, From))), 863 Done = true 864 ) 865 ; true 866 ), 867 ( Done == true 868 -> true 869 ; '$set_predicate_attribute'(Module:Head, autoload, 1) 870 ), 871 register_autoloads(T, Module, File, Context). 872 873pi_in_exports(PI, Exports) :- 874 '$member'(E, Exports), 875 canonical_pi(E, PI), 876 !. 877 878current_autoload(M:File, Context, Term) :- 879 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1), 880 M:'$autoload'(File, Context, Term). 881 882 /******************************* 883 * REQUIRE * 884 *******************************/
891require(M:Spec) :- 892 ( is_list(Spec) 893 -> List = Spec 894 ; phrase(comma_list(Spec), List) 895 ), !, 896 require(List, M, FromLib), 897 keysort(FromLib, Sorted), 898 by_file(Sorted, Autoload), 899 forall('$member'(File-Import, Autoload), 900 autoload(M:File, Import)). 901require(_:Spec) :- 902 '$type_error'(list, Spec). 903 904require([],_, []). 905require([H|T], M, Needed) :- 906 '$pi_head'(H, Head), 907 ( '$get_predicate_attribute'(system:Head, defined, 1) 908 -> require(T, M, Needed) 909 ; '$pi_head'(Module:Name/Arity, M:Head), 910 ( '$find_library'(Module, Name, Arity, _LoadModule, Library) 911 -> Needed = [Library-H|More], 912 require(T, M, More) 913 ; print_message(error, error(existence_error(procedure, Name/Arity), _)), 914 require(T, M, Needed) 915 ) 916 ). 917 918by_file([], []). 919by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :- 920 on_path(File, Spec), 921 same_file(T0, File, PIs, T1), 922 by_file(T1, T). 923 924on_path(Library, library(Base)) :- 925 file_base_name(Library, Base), 926 findall(Path, plain_source(library(Base), Path), [Library]), 927 !. 928on_path(Library, Library). 929 930plain_source(Spec, Path) :- 931 absolute_file_name(Spec, PathExt, 932 [ file_type(prolog), 933 access(read), 934 file_errors(fail), 935 solutions(all) 936 ]), 937 file_name_extension(Path, _, PathExt). 938 939same_file([File-PI|T0], File, [PI|PIs], T) :- 940 !, 941 same_file(T0, File, PIs, T). 942same_file(List, _, [], List). 943 944comma_list(Var) --> 945 { var(Var), 946 !, 947 '$instantiation_error'(Var) 948 }. 949comma_list((A,B)) --> 950 !, 951 comma_list(A), 952 comma_list(B). 953comma_list(A) --> 954 [A]