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/* 38Consult, derivates and basic things. This module is loaded by the 39C-written bootstrap compiler. 40 41The $:- directive is executed by the bootstrap compiler, but not 42inserted in the intermediate code file. Used to print diagnostic 43messages and start the Prolog defined compiler for the remaining boot 44modules. 45 46If you want to debug this module, put a '$:-'(trace). directive 47somewhere. The tracer will work properly under boot compilation as it 48will use the C defined write predicate to print goals and does not 49attempt to call the Prolog defined trace interceptor. 50*/ 51 52 /******************************** 53 * LOAD INTO MODULE SYSTEM * 54 ********************************/ 55 56:- '$set_source_module'(system). 57 58'$boot_message'(_Format, _Args) :- 59 current_prolog_flag(verbose, silent), 60 !. 61'$boot_message'(Format, Args) :- 62 format(Format, Args), 63 !. 64 65'$:-'('$boot_message'('Loading boot file ...~n', [])). 66 67 68 /******************************** 69 * DIRECTIVES * 70 *********************************/ 71 72:- meta_predicate 73 dynamic(:), 74 multifile(:), 75 public(:), 76 module_transparent(:), 77 discontiguous(:), 78 volatile(:), 79 thread_local(:), 80 noprofile(:), 81 non_terminal(:), 82 '$clausable'(:), 83 '$iso'(:), 84 '$hide'(:). 85 86%! dynamic(+Spec) is det. 87%! multifile(+Spec) is det. 88%! module_transparent(+Spec) is det. 89%! discontiguous(+Spec) is det. 90%! volatile(+Spec) is det. 91%! thread_local(+Spec) is det. 92%! noprofile(+Spec) is det. 93%! public(+Spec) is det. 94%! non_terminal(+Spec) is det. 95% 96% Predicate versions of standard directives that set predicate 97% attributes. These predicates bail out with an error on the first 98% failure (typically permission errors). 99 100%! '$iso'(+Spec) is det. 101% 102% Set the ISO flag. This defines that the predicate cannot be 103% redefined inside a module. 104 105%! '$clausable'(+Spec) is det. 106% 107% Specify that we can run clause/2 on a predicate, even if it is 108% static. ISO specifies that `public` also plays this role. in SWI, 109% `public` means that the predicate can be called, even if we cannot 110% find a reference to it. 111 112%! '$hide'(+Spec) is det. 113% 114% Specify that the predicate cannot be seen in the debugger. 115 116dynamic(Spec) :- '$set_pattr'(Spec, pred, dynamic(true)). 117multifile(Spec) :- '$set_pattr'(Spec, pred, multifile(true)). 118module_transparent(Spec) :- '$set_pattr'(Spec, pred, transparent(true)). 119discontiguous(Spec) :- '$set_pattr'(Spec, pred, discontiguous(true)). 120volatile(Spec) :- '$set_pattr'(Spec, pred, volatile(true)). 121thread_local(Spec) :- '$set_pattr'(Spec, pred, thread_local(true)). 122noprofile(Spec) :- '$set_pattr'(Spec, pred, noprofile(true)). 123public(Spec) :- '$set_pattr'(Spec, pred, public(true)). 124non_terminal(Spec) :- '$set_pattr'(Spec, pred, non_terminal(true)). 125'$iso'(Spec) :- '$set_pattr'(Spec, pred, iso(true)). 126'$clausable'(Spec) :- '$set_pattr'(Spec, pred, clausable(true)). 127'$hide'(Spec) :- '$set_pattr'(Spec, pred, trace(false)). 128 129'$set_pattr'(M:Pred, How, Attr) :- 130 '$set_pattr'(Pred, M, How, Attr). 131 132%! '$set_pattr'(+Spec, +Module, +From, +Attr) 133% 134% Set predicate attributes. From is one of `pred` or `directive`. 135 136'$set_pattr'(X, _, _, _) :- 137 var(X), 138 '$uninstantiation_error'(X). 139'$set_pattr'(as(Spec,Options), M, How, Attr0) :- 140 !, 141 '$attr_options'(Options, Attr0, Attr), 142 '$set_pattr'(Spec, M, How, Attr). 143'$set_pattr'([], _, _, _) :- !. 144'$set_pattr'([H|T], M, How, Attr) :- % ISO 145 !, 146 '$set_pattr'(H, M, How, Attr), 147 '$set_pattr'(T, M, How, Attr). 148'$set_pattr'((A,B), M, How, Attr) :- % ISO and traditional 149 !, 150 '$set_pattr'(A, M, How, Attr), 151 '$set_pattr'(B, M, How, Attr). 152'$set_pattr'(M:T, _, How, Attr) :- 153 !, 154 '$set_pattr'(T, M, How, Attr). 155'$set_pattr'(PI, M, _, []) :- 156 !, 157 '$pi_head'(M:PI, Pred), 158 ( '$get_predicate_attribute'(Pred, incremental, 1) 159 -> '$wrap_incremental'(Pred) 160 ; '$unwrap_incremental'(Pred) 161 ). 162'$set_pattr'(A, M, How, [O|OT]) :- 163 !, 164 '$set_pattr'(A, M, How, O), 165 '$set_pattr'(A, M, How, OT). 166'$set_pattr'(A, M, pred, Attr) :- 167 !, 168 Attr =.. [Name,Val], 169 '$set_pi_attr'(M:A, Name, Val). 170'$set_pattr'(A, M, directive, Attr) :- 171 !, 172 Attr =.. [Name,Val], 173 catch('$set_pi_attr'(M:A, Name, Val), 174 error(E, _), 175 print_message(error, error(E, context((Name)/1,_)))). 176 177'$set_pi_attr'(PI, Name, Val) :- 178 '$pi_head'(PI, Head), 179 '$set_predicate_attribute'(Head, Name, Val). 180 181'$attr_options'(Var, _, _) :- 182 var(Var), 183 !, 184 '$uninstantiation_error'(Var). 185'$attr_options'((A,B), Attr0, Attr) :- 186 !, 187 '$attr_options'(A, Attr0, Attr1), 188 '$attr_options'(B, Attr1, Attr). 189'$attr_options'(Opt, Attr0, Attrs) :- 190 '$must_be'(ground, Opt), 191 ( '$attr_option'(Opt, AttrX) 192 -> ( is_list(Attr0) 193 -> '$join_attrs'(AttrX, Attr0, Attrs) 194 ; '$join_attrs'(AttrX, [Attr0], Attrs) 195 ) 196 ; '$domain_error'(predicate_option, Opt) 197 ). 198 199'$join_attrs'(Attr, Attrs, Attrs) :- 200 memberchk(Attr, Attrs), 201 !. 202'$join_attrs'(Attr, Attrs, Attrs) :- 203 Attr =.. [Name,Value], 204 Gen =.. [Name,Existing], 205 memberchk(Gen, Attrs), 206 !, 207 throw(error(conflict_error(Name, Value, Existing), _)). 208'$join_attrs'(Attr, Attrs0, Attrs) :- 209 '$append'(Attrs0, [Attr], Attrs). 210 211'$attr_option'(incremental, incremental(true)). 212'$attr_option'(opaque, incremental(false)). 213'$attr_option'(abstract(Level0), abstract(Level)) :- 214 '$table_option'(Level0, Level). 215'$attr_option'(subgoal_abstract(Level0), subgoal_abstract(Level)) :- 216 '$table_option'(Level0, Level). 217'$attr_option'(answer_abstract(Level0), answer_abstract(Level)) :- 218 '$table_option'(Level0, Level). 219'$attr_option'(max_answers(Level0), max_answers(Level)) :- 220 '$table_option'(Level0, Level). 221'$attr_option'(volatile, volatile(true)). 222'$attr_option'(multifile, multifile(true)). 223'$attr_option'(discontiguous, discontiguous(true)). 224'$attr_option'(shared, thread_local(false)). 225'$attr_option'(local, thread_local(true)). 226'$attr_option'(private, thread_local(true)). 227 228'$table_option'(Value0, _Value) :- 229 var(Value0), 230 !, 231 '$instantiation_error'(Value0). 232'$table_option'(Value0, Value) :- 233 integer(Value0), 234 Value0 >= 0, 235 !, 236 Value = Value0. 237'$table_option'(off, -1) :- 238 !. 239'$table_option'(false, -1) :- 240 !. 241'$table_option'(infinite, -1) :- 242 !. 243'$table_option'(Value, _) :- 244 '$domain_error'(nonneg_or_false, Value). 245 246 247%! '$pattr_directive'(+Spec, +Module) is det. 248% 249% This implements the directive version of dynamic/1, multifile/1, 250% etc. This version catches and prints errors. If the directive 251% specifies multiple predicates, processing after an error 252% continues with the remaining predicates. 253 254'$pattr_directive'(dynamic(Spec), M) :- 255 '$set_pattr'(Spec, M, directive, dynamic(true)). 256'$pattr_directive'(multifile(Spec), M) :- 257 '$set_pattr'(Spec, M, directive, multifile(true)). 258'$pattr_directive'(module_transparent(Spec), M) :- 259 '$set_pattr'(Spec, M, directive, transparent(true)). 260'$pattr_directive'(discontiguous(Spec), M) :- 261 '$set_pattr'(Spec, M, directive, discontiguous(true)). 262'$pattr_directive'(volatile(Spec), M) :- 263 '$set_pattr'(Spec, M, directive, volatile(true)). 264'$pattr_directive'(thread_local(Spec), M) :- 265 '$set_pattr'(Spec, M, directive, thread_local(true)). 266'$pattr_directive'(noprofile(Spec), M) :- 267 '$set_pattr'(Spec, M, directive, noprofile(true)). 268'$pattr_directive'(public(Spec), M) :- 269 '$set_pattr'(Spec, M, directive, public(true)). 270 271%! '$pi_head'(?PI, ?Head) 272 273'$pi_head'(PI, Head) :- 274 var(PI), 275 var(Head), 276 '$instantiation_error'([PI,Head]). 277'$pi_head'(M:PI, M:Head) :- 278 !, 279 '$pi_head'(PI, Head). 280'$pi_head'(Name/Arity, Head) :- 281 !, 282 '$head_name_arity'(Head, Name, Arity). 283'$pi_head'(Name//DCGArity, Head) :- 284 !, 285 ( nonvar(DCGArity) 286 -> Arity is DCGArity+2, 287 '$head_name_arity'(Head, Name, Arity) 288 ; '$head_name_arity'(Head, Name, Arity), 289 DCGArity is Arity - 2 290 ). 291'$pi_head'(PI, _) :- 292 '$type_error'(predicate_indicator, PI). 293 294%! '$head_name_arity'(+Goal, -Name, -Arity). 295%! '$head_name_arity'(-Goal, +Name, +Arity). 296 297'$head_name_arity'(Goal, Name, Arity) :- 298 ( atom(Goal) 299 -> Name = Goal, Arity = 0 300 ; compound(Goal) 301 -> compound_name_arity(Goal, Name, Arity) 302 ; var(Goal) 303 -> ( Arity == 0 304 -> ( atom(Name) 305 -> Goal = Name 306 ; blob(Name, closure) 307 -> Goal = Name 308 ; '$type_error'(atom, Name) 309 ) 310 ; compound_name_arity(Goal, Name, Arity) 311 ) 312 ; '$type_error'(callable, Goal) 313 ). 314 315:- '$iso'(((dynamic)/1, (multifile)/1, (discontiguous)/1)). 316 317 318 /******************************** 319 * CALLING, CONTROL * 320 *********************************/ 321 322:- noprofile((call/1, 323 catch/3, 324 once/1, 325 ignore/1, 326 call_cleanup/2, 327 call_cleanup/3, 328 setup_call_cleanup/3, 329 setup_call_catcher_cleanup/4)). 330 331:- meta_predicate 332 ';'(0,0), 333 ','(0,0), 334 @(0,+), 335 call(0), 336 call(1,?), 337 call(2,?,?), 338 call(3,?,?,?), 339 call(4,?,?,?,?), 340 call(5,?,?,?,?,?), 341 call(6,?,?,?,?,?,?), 342 call(7,?,?,?,?,?,?,?), 343 not(0), 344 \+(0), 345 '->'(0,0), 346 '*->'(0,0), 347 once(0), 348 ignore(0), 349 catch(0,?,0), 350 reset(0,?,-), 351 setup_call_cleanup(0,0,0), 352 setup_call_catcher_cleanup(0,0,?,0), 353 call_cleanup(0,0), 354 call_cleanup(0,?,0), 355 catch_with_backtrace(0,?,0), 356 '$meta_call'(0). 357 358:- '$iso'((call/1, (\+)/1, once/1, (;)/2, (',')/2, (->)/2, catch/3)). 359 360% The control structures are always compiled, both if they appear in a 361% clause body and if they are handed to call/1. The only way to call 362% these predicates is by means of call/2.. In that case, we call the 363% hole control structure again to get it compiled by call/1 and properly 364% deal with !, etc. Another reason for having these things as 365% predicates is to be able to define properties for them, helping code 366% analyzers. 367 368(M0:If ; M0:Then) :- !, call(M0:(If ; Then)). 369(M1:If ; M2:Then) :- call(M1:(If ; M2:Then)). 370(G1 , G2) :- call((G1 , G2)). 371(If -> Then) :- call((If -> Then)). 372(If *-> Then) :- call((If *-> Then)). 373@(Goal,Module) :- @(Goal,Module). 374 375%! '$meta_call'(:Goal) 376% 377% Interpreted meta-call implementation. By default, call/1 378% compiles its argument into a temporary clause. This realises 379% better performance if the (complex) goal does a lot of 380% backtracking because this interpreted version needs to 381% re-interpret the remainder of the goal after backtracking. 382% 383% This implementation is used by reset/3 because the continuation 384% cannot be captured if it contains a such a compiled temporary 385% clause. 386 387'$meta_call'(M:G) :- 388 prolog_current_choice(Ch), 389 '$meta_call'(G, M, Ch). 390 391'$meta_call'(Var, _, _) :- 392 var(Var), 393 !, 394 '$instantiation_error'(Var). 395'$meta_call'((A,B), M, Ch) :- 396 !, 397 '$meta_call'(A, M, Ch), 398 '$meta_call'(B, M, Ch). 399'$meta_call'((I->T;E), M, Ch) :- 400 !, 401 ( prolog_current_choice(Ch2), 402 '$meta_call'(I, M, Ch2) 403 -> '$meta_call'(T, M, Ch) 404 ; '$meta_call'(E, M, Ch) 405 ). 406'$meta_call'((I*->T;E), M, Ch) :- 407 !, 408 ( prolog_current_choice(Ch2), 409 '$meta_call'(I, M, Ch2) 410 *-> '$meta_call'(T, M, Ch) 411 ; '$meta_call'(E, M, Ch) 412 ). 413'$meta_call'((I->T), M, Ch) :- 414 !, 415 ( prolog_current_choice(Ch2), 416 '$meta_call'(I, M, Ch2) 417 -> '$meta_call'(T, M, Ch) 418 ). 419'$meta_call'((I*->T), M, Ch) :- 420 !, 421 prolog_current_choice(Ch2), 422 '$meta_call'(I, M, Ch2), 423 '$meta_call'(T, M, Ch). 424'$meta_call'((A;B), M, Ch) :- 425 !, 426 ( '$meta_call'(A, M, Ch) 427 ; '$meta_call'(B, M, Ch) 428 ). 429'$meta_call'(\+(G), M, _) :- 430 !, 431 prolog_current_choice(Ch), 432 \+ '$meta_call'(G, M, Ch). 433'$meta_call'(call(G), M, _) :- 434 !, 435 prolog_current_choice(Ch), 436 '$meta_call'(G, M, Ch). 437'$meta_call'(M:G, _, Ch) :- 438 !, 439 '$meta_call'(G, M, Ch). 440'$meta_call'(!, _, Ch) :- 441 prolog_cut_to(Ch). 442'$meta_call'(G, M, _Ch) :- 443 call(M:G). 444 445%! call(:Closure, ?A). 446%! call(:Closure, ?A1, ?A2). 447%! call(:Closure, ?A1, ?A2, ?A3). 448%! call(:Closure, ?A1, ?A2, ?A3, ?A4). 449%! call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5). 450%! call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5, ?A6). 451%! call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5, ?A6, ?A7). 452% 453% Arity 2..8 is demanded by the ISO standard. Higher arities are 454% supported, but handled by the compiler. This implies they are 455% not backed up by predicates and analyzers thus cannot ask for 456% their properties. Analyzers should hard-code handling of 457% call/2.. 458 459:- '$iso'((call/2, 460 call/3, 461 call/4, 462 call/5, 463 call/6, 464 call/7, 465 call/8)). 466 467call(Goal) :- % make these available as predicates 468 Goal. 469call(Goal, A) :- 470 call(Goal, A). 471call(Goal, A, B) :- 472 call(Goal, A, B). 473call(Goal, A, B, C) :- 474 call(Goal, A, B, C). 475call(Goal, A, B, C, D) :- 476 call(Goal, A, B, C, D). 477call(Goal, A, B, C, D, E) :- 478 call(Goal, A, B, C, D, E). 479call(Goal, A, B, C, D, E, F) :- 480 call(Goal, A, B, C, D, E, F). 481call(Goal, A, B, C, D, E, F, G) :- 482 call(Goal, A, B, C, D, E, F, G). 483 484%! not(:Goal) is semidet. 485% 486% Pre-ISO version of \+/1. Note that some systems define not/1 as 487% a logically more sound version of \+/1. 488 489not(Goal) :- 490 \+ Goal. 491 492%! \+(:Goal) is semidet. 493% 494% Predicate version that allows for meta-calling. 495 496\+ Goal :- 497 \+ Goal. 498 499%! once(:Goal) is semidet. 500% 501% ISO predicate, acting as call((Goal, !)). 502 503once(Goal) :- 504 Goal, 505 !. 506 507%! ignore(:Goal) is det. 508% 509% Call Goal, cut choice-points on success and succeed on failure. 510% intended for calling side-effects and proceed on failure. 511 512ignore(Goal) :- 513 Goal, 514 !. 515ignore(_Goal). 516 517:- '$iso'((false/0)). 518 519%! false. 520% 521% Synonym for fail/0, providing a declarative reading. 522 523false :- 524 fail. 525 526%! catch(:Goal, +Catcher, :Recover) 527% 528% ISO compliant exception handling. 529 530catch(_Goal, _Catcher, _Recover) :- 531 '$catch'. % Maps to I_CATCH, I_EXITCATCH 532 533%! prolog_cut_to(+Choice) 534% 535% Cut all choice points after Choice 536 537prolog_cut_to(_Choice) :- 538 '$cut'. % Maps to I_CUTCHP 539 540%! reset(:Goal, ?Ball, -Continue) 541% 542% Delimited continuation support. 543 544reset(_Goal, _Ball, _Cont) :- 545 '$reset'. 546 547%! shift(+Ball) 548% 549% Shift control back to the enclosing reset/3 550 551shift(Ball) :- 552 '$shift'(Ball). 553 554%! call_continuation(+Continuation:list) 555% 556% Call a continuation as created by shift/1. The continuation is a 557% list of '$cont$'(Clause, PC, EnvironmentArg, ...) structures. The 558% predicate '$call_one_tail_body'/1 creates a frame from the 559% continuation and calls this. 560% 561% Note that we can technically also push the entire continuation onto 562% the environment and call it. Doing it incrementally as below 563% exploits last-call optimization and therefore possible quadratic 564% expansion of the continuation. 565 566call_continuation([]). 567call_continuation([TB|Rest]) :- 568 ( Rest == [] 569 -> '$call_continuation'(TB) 570 ; '$call_continuation'(TB), 571 call_continuation(Rest) 572 ). 573 574%! catch_with_backtrace(:Goal, ?Ball, :Recover) 575% 576% As catch/3, but tell library(prolog_stack) to record a backtrace in 577% case of an exception. 578 579catch_with_backtrace(Goal, Ball, Recover) :- 580 catch(Goal, Ball, Recover), 581 '$no_lco'. 582 583'$no_lco'. 584 585%! '$recover_and_rethrow'(:Goal, +Term) 586% 587% This goal is used to wrap the catch/3 recover handler if the 588% exception is not supposed to be `catchable'. An example of an 589% uncachable exception is '$aborted', used by abort/0. Note that 590% we cut to ensure that the exception is not delayed forever 591% because the recover handler leaves a choicepoint. 592 593:- public '$recover_and_rethrow'/2. 594 595'$recover_and_rethrow'(Goal, Exception) :- 596 call_cleanup(Goal, throw(Exception)), 597 !. 598 599 600%! setup_call_cleanup(:Setup, :Goal, :Cleanup). 601%! setup_call_catcher_cleanup(:Setup, :Goal, +Catcher, :Cleanup). 602%! call_cleanup(:Goal, :Cleanup). 603%! call_cleanup(:Goal, +Catcher, :Cleanup). 604% 605% Call Cleanup once after Goal is finished (deterministic success, 606% failure, exception or cut). The call to '$call_cleanup' is 607% translated to I_CALLCLEANUP. This instruction relies on the 608% exact stack layout left by setup_call_catcher_cleanup/4. Also 609% the predicate name is used by the kernel cleanup mechanism and 610% can only be changed together with the kernel. 611 612setup_call_catcher_cleanup(Setup, _Goal, _Catcher, _Cleanup) :- 613 '$sig_atomic'(Setup), 614 '$call_cleanup'. 615 616setup_call_cleanup(Setup, Goal, Cleanup) :- 617 setup_call_catcher_cleanup(Setup, Goal, _Catcher, Cleanup). 618 619call_cleanup(Goal, Cleanup) :- 620 setup_call_catcher_cleanup(true, Goal, _Catcher, Cleanup). 621 622call_cleanup(Goal, Catcher, Cleanup) :- 623 setup_call_catcher_cleanup(true, Goal, Catcher, Cleanup). 624 625 /******************************* 626 * INITIALIZATION * 627 *******************************/ 628 629:- meta_predicate 630 initialization(0, +). 631 632:- multifile '$init_goal'/3. 633:- dynamic '$init_goal'/3. 634 635%! initialization(:Goal, +When) 636% 637% Register Goal to be executed if a saved state is restored. In 638% addition, the goal is executed depending on When: 639% 640% * now 641% Execute immediately 642% * after_load 643% Execute after loading the file in which it appears. This 644% is initialization/1. 645% * restore_state 646% Do not execute immediately, but only when restoring the 647% state. Not allowed in a sandboxed environment. 648% * prepare_state 649% Called before saving a state. Can be used to clean the 650% environment (see also volatile/1) or eagerly execute 651% goals that are normally executed lazily. 652% * program 653% Works as =|-g goal|= goals. 654% * main 655% Starts the application. Only last declaration is used. 656% 657% Note that all goals are executed when a program is restored. 658 659initialization(Goal, When) :- 660 '$must_be'(oneof(atom, initialization_type, 661 [ now, 662 after_load, 663 restore, 664 restore_state, 665 prepare_state, 666 program, 667 main 668 ]), When), 669 '$initialization_context'(Source, Ctx), 670 '$initialization'(When, Goal, Source, Ctx). 671 672'$initialization'(now, Goal, _Source, Ctx) :- 673 '$run_init_goal'(Goal, Ctx), 674 '$compile_init_goal'(-, Goal, Ctx). 675'$initialization'(after_load, Goal, Source, Ctx) :- 676 ( Source \== (-) 677 -> '$compile_init_goal'(Source, Goal, Ctx) 678 ; throw(error(context_error(nodirective, 679 initialization(Goal, after_load)), 680 _)) 681 ). 682'$initialization'(restore, Goal, Source, Ctx) :- % deprecated 683 '$initialization'(restore_state, Goal, Source, Ctx). 684'$initialization'(restore_state, Goal, _Source, Ctx) :- 685 ( \+ current_prolog_flag(sandboxed_load, true) 686 -> '$compile_init_goal'(-, Goal, Ctx) 687 ; '$permission_error'(register, initialization(restore), Goal) 688 ). 689'$initialization'(prepare_state, Goal, _Source, Ctx) :- 690 ( \+ current_prolog_flag(sandboxed_load, true) 691 -> '$compile_init_goal'(when(prepare_state), Goal, Ctx) 692 ; '$permission_error'(register, initialization(restore), Goal) 693 ). 694'$initialization'(program, Goal, _Source, Ctx) :- 695 ( \+ current_prolog_flag(sandboxed_load, true) 696 -> '$compile_init_goal'(when(program), Goal, Ctx) 697 ; '$permission_error'(register, initialization(restore), Goal) 698 ). 699'$initialization'(main, Goal, _Source, Ctx) :- 700 ( \+ current_prolog_flag(sandboxed_load, true) 701 -> '$compile_init_goal'(when(main), Goal, Ctx) 702 ; '$permission_error'(register, initialization(restore), Goal) 703 ). 704 705 706'$compile_init_goal'(Source, Goal, Ctx) :- 707 atom(Source), 708 Source \== (-), 709 !, 710 '$store_admin_clause'(system:'$init_goal'(Source, Goal, Ctx), 711 _Layout, Source, Ctx). 712'$compile_init_goal'(Source, Goal, Ctx) :- 713 assertz('$init_goal'(Source, Goal, Ctx)). 714 715 716%! '$run_initialization'(?File, +Options) is det. 717%! '$run_initialization'(?File, +Action, +Options) is det. 718% 719% Run initialization directives for all files if File is unbound, 720% or for a specified file. Note that '$run_initialization'/2 is 721% called from runInitialization() in pl-wic.c for .qlf files. The 722% '$run_initialization'/3 is called with Action set to `loaded` 723% when called for a QLF file. 724 725'$run_initialization'(_, loaded, _) :- !. 726'$run_initialization'(File, _Action, Options) :- 727 '$run_initialization'(File, Options). 728 729'$run_initialization'(File, Options) :- 730 setup_call_cleanup( 731 '$start_run_initialization'(Options, Restore), 732 '$run_initialization_2'(File), 733 '$end_run_initialization'(Restore)). 734 735'$start_run_initialization'(Options, OldSandBoxed) :- 736 '$push_input_context'(initialization), 737 '$set_sandboxed_load'(Options, OldSandBoxed). 738'$end_run_initialization'(OldSandBoxed) :- 739 set_prolog_flag(sandboxed_load, OldSandBoxed), 740 '$pop_input_context'. 741 742'$run_initialization_2'(File) :- 743 ( '$init_goal'(File, Goal, Ctx), 744 File \= when(_), 745 '$run_init_goal'(Goal, Ctx), 746 fail 747 ; true 748 ). 749 750'$run_init_goal'(Goal, Ctx) :- 751 ( catch_with_backtrace('$run_init_goal'(Goal), E, 752 '$initialization_error'(E, Goal, Ctx)) 753 -> true 754 ; '$initialization_failure'(Goal, Ctx) 755 ). 756 757:- multifile prolog:sandbox_allowed_goal/1. 758 759'$run_init_goal'(Goal) :- 760 current_prolog_flag(sandboxed_load, false), 761 !, 762 call(Goal). 763'$run_init_goal'(Goal) :- 764 prolog:sandbox_allowed_goal(Goal), 765 call(Goal). 766 767'$initialization_context'(Source, Ctx) :- 768 ( source_location(File, Line) 769 -> Ctx = File:Line, 770 '$input_context'(Context), 771 '$top_file'(Context, File, Source) 772 ; Ctx = (-), 773 File = (-) 774 ). 775 776'$top_file'([input(include, F1, _, _)|T], _, F) :- 777 !, 778 '$top_file'(T, F1, F). 779'$top_file'(_, F, F). 780 781 782'$initialization_error'(E, Goal, Ctx) :- 783 print_message(error, initialization_error(Goal, E, Ctx)). 784 785'$initialization_failure'(Goal, Ctx) :- 786 print_message(warning, initialization_failure(Goal, Ctx)). 787 788%! '$clear_source_admin'(+File) is det. 789% 790% Removes source adminstration related to File 791% 792% @see Called from destroySourceFile() in pl-proc.c 793 794:- public '$clear_source_admin'/1. 795 796'$clear_source_admin'(File) :- 797 retractall('$init_goal'(_, _, File:_)), 798 retractall('$load_context_module'(File, _, _)), 799 retractall('$resolved_source_path'(_, File)). 800 801 802 /******************************* 803 * STREAM * 804 *******************************/ 805 806:- '$iso'(stream_property/2). 807stream_property(Stream, Property) :- 808 nonvar(Stream), 809 nonvar(Property), 810 !, 811 '$stream_property'(Stream, Property). 812stream_property(Stream, Property) :- 813 nonvar(Stream), 814 !, 815 '$stream_properties'(Stream, Properties), 816 '$member'(Property, Properties). 817stream_property(Stream, Property) :- 818 nonvar(Property), 819 !, 820 ( Property = alias(Alias), 821 atom(Alias) 822 -> '$alias_stream'(Alias, Stream) 823 ; '$streams_properties'(Property, Pairs), 824 '$member'(Stream-Property, Pairs) 825 ). 826stream_property(Stream, Property) :- 827 '$streams_properties'(Property, Pairs), 828 '$member'(Stream-Properties, Pairs), 829 '$member'(Property, Properties). 830 831 832 /******************************** 833 * MODULES * 834 *********************************/ 835 836% '$prefix_module'(+Module, +Context, +Term, -Prefixed) 837% Tags `Term' with `Module:' if `Module' is not the context module. 838 839'$prefix_module'(Module, Module, Head, Head) :- !. 840'$prefix_module'(Module, _, Head, Module:Head). 841 842%! default_module(+Me, -Super) is multi. 843% 844% Is true if `Super' is `Me' or a super (auto import) module of `Me'. 845 846default_module(Me, Super) :- 847 ( atom(Me) 848 -> ( var(Super) 849 -> '$default_module'(Me, Super) 850 ; '$default_module'(Me, Super), ! 851 ) 852 ; '$type_error'(module, Me) 853 ). 854 855'$default_module'(Me, Me). 856'$default_module'(Me, Super) :- 857 import_module(Me, S), 858 '$default_module'(S, Super). 859 860 861 /******************************** 862 * TRACE AND EXCEPTIONS * 863 *********************************/ 864 865:- dynamic user:exception/3. 866:- multifile user:exception/3. 867 868%! '$undefined_procedure'(+Module, +Name, +Arity, -Action) is det. 869% 870% This predicate is called from C on undefined predicates. First 871% allows the user to take care of it using exception/3. Else try 872% to give a DWIM warning. Otherwise fail. C will print an error 873% message. 874 875:- public 876 '$undefined_procedure'/4. 877 878'$undefined_procedure'(Module, Name, Arity, Action) :- 879 '$prefix_module'(Module, user, Name/Arity, Pred), 880 user:exception(undefined_predicate, Pred, Action0), 881 !, 882 Action = Action0. 883'$undefined_procedure'(Module, Name, Arity, Action) :- 884 \+ current_prolog_flag(autoload, false), 885 '$autoload'(Module:Name/Arity), 886 !, 887 Action = retry. 888'$undefined_procedure'(_, _, _, error). 889 890 891%! '$loading'(+Library) 892% 893% True if the library is being loaded. Just testing that the 894% predicate is defined is not good enough as the file may be 895% partly loaded. Calling use_module/2 at any time has two 896% drawbacks: it queries the filesystem, causing slowdown and it 897% stops libraries being autoloaded from a saved state where the 898% library is already loaded, but the source may not be accessible. 899 900'$loading'(Library) :- 901 current_prolog_flag(threads, true), 902 '$loading_file'(FullFile, _Queue, _LoadThread), 903 file_name_extension(Library, _, FullFile), 904 !. 905 906% handle debugger 'w', 'p' and <N> depth options. 907 908'$set_debugger_write_options'(write) :- 909 !, 910 create_prolog_flag(debugger_write_options, 911 [ quoted(true), 912 attributes(dots), 913 spacing(next_argument) 914 ], []). 915'$set_debugger_write_options'(print) :- 916 !, 917 create_prolog_flag(debugger_write_options, 918 [ quoted(true), 919 portray(true), 920 max_depth(10), 921 attributes(portray), 922 spacing(next_argument) 923 ], []). 924'$set_debugger_write_options'(Depth) :- 925 current_prolog_flag(debugger_write_options, Options0), 926 ( '$select'(max_depth(_), Options0, Options) 927 -> true 928 ; Options = Options0 929 ), 930 create_prolog_flag(debugger_write_options, 931 [max_depth(Depth)|Options], []). 932 933 934 /******************************** 935 * SYSTEM MESSAGES * 936 *********************************/ 937 938%! '$confirm'(Spec) 939% 940% Ask the user to confirm a question. Spec is a term as used for 941% print_message/2. 942 943'$confirm'(Spec) :- 944 print_message(query, Spec), 945 between(0, 5, _), 946 get_single_char(Answer), 947 ( '$in_reply'(Answer, 'yYjJ \n') 948 -> !, 949 print_message(query, if_tty([yes-[]])) 950 ; '$in_reply'(Answer, 'nN') 951 -> !, 952 print_message(query, if_tty([no-[]])), 953 fail 954 ; print_message(help, query(confirm)), 955 fail 956 ). 957 958'$in_reply'(Code, Atom) :- 959 char_code(Char, Code), 960 sub_atom(Atom, _, _, _, Char), 961 !. 962 963:- dynamic 964 user:portray/1. 965:- multifile 966 user:portray/1. 967 968 969 /******************************* 970 * FILE_SEARCH_PATH * 971 *******************************/ 972 973:- dynamic 974 user:file_search_path/2, 975 user:library_directory/1. 976:- multifile 977 user:file_search_path/2, 978 user:library_directory/1. 979 980user:(file_search_path(library, Dir) :- 981 library_directory(Dir)). 982user:file_search_path(swi, Home) :- 983 current_prolog_flag(home, Home). 984user:file_search_path(swi, Home) :- 985 current_prolog_flag(shared_home, Home). 986user:file_search_path(library, app_config(lib)). 987user:file_search_path(library, swi(library)). 988user:file_search_path(library, swi(library/clp)). 989user:file_search_path(foreign, swi(ArchLib)) :- 990 \+ current_prolog_flag(windows, true), 991 current_prolog_flag(arch, Arch), 992 atom_concat('lib/', Arch, ArchLib). 993user:file_search_path(foreign, swi(SoLib)) :- 994 ( current_prolog_flag(windows, true) 995 -> SoLib = bin 996 ; SoLib = lib 997 ). 998user:file_search_path(path, Dir) :- 999 getenv('PATH', Path), 1000 ( current_prolog_flag(windows, true) 1001 -> atomic_list_concat(Dirs, (;), Path) 1002 ; atomic_list_concat(Dirs, :, Path) 1003 ), 1004 '$member'(Dir, Dirs). 1005user:file_search_path(user_app_data, Dir) :- 1006 '$xdg_prolog_directory'(data, Dir). 1007user:file_search_path(common_app_data, Dir) :- 1008 '$xdg_prolog_directory'(common_data, Dir). 1009user:file_search_path(user_app_config, Dir) :- 1010 '$xdg_prolog_directory'(config, Dir). 1011user:file_search_path(common_app_config, Dir) :- 1012 '$xdg_prolog_directory'(common_config, Dir). 1013user:file_search_path(app_data, user_app_data('.')). 1014user:file_search_path(app_data, common_app_data('.')). 1015user:file_search_path(app_config, user_app_config('.')). 1016user:file_search_path(app_config, common_app_config('.')). 1017% backward compatibility 1018user:file_search_path(app_preferences, user_app_config('.')). 1019user:file_search_path(user_profile, app_preferences('.')). 1020 1021'$xdg_prolog_directory'(Which, Dir) :- 1022 '$xdg_directory'(Which, XDGDir), 1023 '$make_config_dir'(XDGDir), 1024 '$ensure_slash'(XDGDir, XDGDirS), 1025 atom_concat(XDGDirS, 'swi-prolog', Dir), 1026 '$make_config_dir'(Dir). 1027 1028% config 1029'$xdg_directory'(config, Home) :- 1030 current_prolog_flag(windows, true), 1031 catch(win_folder(appdata, Home), _, fail), 1032 !. 1033'$xdg_directory'(config, Home) :- 1034 getenv('XDG_CONFIG_HOME', Home). 1035'$xdg_directory'(config, Home) :- 1036 expand_file_name('~/.config', [Home]). 1037% data 1038'$xdg_directory'(data, Home) :- 1039 current_prolog_flag(windows, true), 1040 catch(win_folder(local_appdata, Home), _, fail), 1041 !. 1042'$xdg_directory'(data, Home) :- 1043 getenv('XDG_DATA_HOME', Home). 1044'$xdg_directory'(data, Home) :- 1045 expand_file_name('~/.local', [Local]), 1046 '$make_config_dir'(Local), 1047 atom_concat(Local, '/share', Home), 1048 '$make_config_dir'(Home). 1049% common data 1050'$xdg_directory'(common_data, Dir) :- 1051 current_prolog_flag(windows, true), 1052 catch(win_folder(common_appdata, Dir), _, fail), 1053 !. 1054'$xdg_directory'(common_data, Dir) :- 1055 '$existing_dir_from_env_path'('XDG_DATA_DIRS', 1056 [ '/usr/local/share', 1057 '/usr/share' 1058 ], 1059 Dir). 1060% common config 1061'$xdg_directory'(common_config, Dir) :- 1062 current_prolog_flag(windows, true), 1063 catch(win_folder(common_appdata, Dir), _, fail), 1064 !. 1065'$xdg_directory'(common_config, Dir) :- 1066 '$existing_dir_from_env_path'('XDG_CONFIG_DIRS', ['/etc/xdg'], Dir). 1067 1068'$existing_dir_from_env_path'(Env, Defaults, Dir) :- 1069 ( getenv(Env, Path) 1070 -> '$path_sep'(Sep), 1071 atomic_list_concat(Dirs, Sep, Path) 1072 ; Dirs = Defaults 1073 ), 1074 '$member'(Dir, Dirs), 1075 exists_directory(Dir). 1076 1077'$path_sep'(Char) :- 1078 ( current_prolog_flag(windows, true) 1079 -> Char = ';' 1080 ; Char = ':' 1081 ). 1082 1083'$make_config_dir'(Dir) :- 1084 exists_directory(Dir), 1085 !. 1086'$make_config_dir'(Dir) :- 1087 file_directory_name(Dir, Parent), 1088 '$my_file'(Parent), 1089 catch(make_directory(Dir), _, fail). 1090 1091'$ensure_slash'(Dir, DirS) :- 1092 ( sub_atom(Dir, _, _, 0, /) 1093 -> DirS = Dir 1094 ; atom_concat(Dir, /, DirS) 1095 ). 1096 1097 1098%! expand_file_search_path(+Spec, -Expanded) is nondet. 1099% 1100% Expand a search path. The system uses depth-first search upto a 1101% specified depth. If this depth is exceeded an exception is raised. 1102% TBD: bread-first search? 1103 1104expand_file_search_path(Spec, Expanded) :- 1105 catch('$expand_file_search_path'(Spec, Expanded, 0, []), 1106 loop(Used), 1107 throw(error(loop_error(Spec), file_search(Used)))). 1108 1109'$expand_file_search_path'(Spec, Expanded, N, Used) :- 1110 functor(Spec, Alias, 1), 1111 !, 1112 user:file_search_path(Alias, Exp0), 1113 NN is N + 1, 1114 ( NN > 16 1115 -> throw(loop(Used)) 1116 ; true 1117 ), 1118 '$expand_file_search_path'(Exp0, Exp1, NN, [Alias=Exp0|Used]), 1119 arg(1, Spec, Segments), 1120 '$segments_to_atom'(Segments, File), 1121 '$make_path'(Exp1, File, Expanded). 1122'$expand_file_search_path'(Spec, Path, _, _) :- 1123 '$segments_to_atom'(Spec, Path). 1124 1125'$make_path'(Dir, '.', Path) :- 1126 !, 1127 Path = Dir. 1128'$make_path'(Dir, File, Path) :- 1129 sub_atom(Dir, _, _, 0, /), 1130 !, 1131 atom_concat(Dir, File, Path). 1132'$make_path'(Dir, File, Path) :- 1133 atomic_list_concat([Dir, /, File], Path). 1134 1135 1136 /******************************** 1137 * FILE CHECKING * 1138 *********************************/ 1139 1140%! absolute_file_name(+Term, -AbsoluteFile, +Options) is nondet. 1141% 1142% Translate path-specifier into a full path-name. This predicate 1143% originates from Quintus was introduced in SWI-Prolog very early 1144% and has re-appeared in SICStus 3.9.0, where they changed 1145% argument order and added some options. We addopted the SICStus 1146% argument order, but still accept the original argument order for 1147% compatibility reasons. 1148 1149absolute_file_name(Spec, Options, Path) :- 1150 '$is_options'(Options), 1151 \+ '$is_options'(Path), 1152 !, 1153 absolute_file_name(Spec, Path, Options). 1154absolute_file_name(Spec, Path, Options) :- 1155 '$must_be'(options, Options), 1156 % get the valid extensions 1157 ( '$select_option'(extensions(Exts), Options, Options1) 1158 -> '$must_be'(list, Exts) 1159 ; '$option'(file_type(Type), Options) 1160 -> '$must_be'(atom, Type), 1161 '$file_type_extensions'(Type, Exts), 1162 Options1 = Options 1163 ; Options1 = Options, 1164 Exts = [''] 1165 ), 1166 '$canonicalise_extensions'(Exts, Extensions), 1167 % unless specified otherwise, ask regular file 1168 ( nonvar(Type) 1169 -> Options2 = Options1 1170 ; '$merge_options'(_{file_type:regular}, Options1, Options2) 1171 ), 1172 % Det or nondet? 1173 ( '$select_option'(solutions(Sols), Options2, Options3) 1174 -> '$must_be'(oneof(atom, solutions, [first,all]), Sols) 1175 ; Sols = first, 1176 Options3 = Options2 1177 ), 1178 % Errors or not? 1179 ( '$select_option'(file_errors(FileErrors), Options3, Options4) 1180 -> '$must_be'(oneof(atom, file_errors, [error,fail]), FileErrors) 1181 ; FileErrors = error, 1182 Options4 = Options3 1183 ), 1184 % Expand shell patterns? 1185 ( atomic(Spec), 1186 '$select_option'(expand(Expand), Options4, Options5), 1187 '$must_be'(boolean, Expand) 1188 -> expand_file_name(Spec, List), 1189 '$member'(Spec1, List) 1190 ; Spec1 = Spec, 1191 Options5 = Options4 1192 ), 1193 % Search for files 1194 ( Sols == first 1195 -> ( '$chk_file'(Spec1, Extensions, Options5, true, Path) 1196 -> ! % also kill choice point of expand_file_name/2 1197 ; ( FileErrors == fail 1198 -> fail 1199 ; '$current_module'('$bags', _File), 1200 findall(P, 1201 '$chk_file'(Spec1, Extensions, [access(exist)], 1202 false, P), 1203 Candidates), 1204 '$abs_file_error'(Spec, Candidates, Options5) 1205 ) 1206 ) 1207 ; '$chk_file'(Spec1, Extensions, Options5, false, Path) 1208 ). 1209 1210'$abs_file_error'(Spec, Candidates, Conditions) :- 1211 '$member'(F, Candidates), 1212 '$member'(C, Conditions), 1213 '$file_condition'(C), 1214 '$file_error'(C, Spec, F, E, Comment), 1215 !, 1216 throw(error(E, context(_, Comment))). 1217'$abs_file_error'(Spec, _, _) :- 1218 '$existence_error'(source_sink, Spec). 1219 1220'$file_error'(file_type(directory), Spec, File, Error, Comment) :- 1221 \+ exists_directory(File), 1222 !, 1223 Error = existence_error(directory, Spec), 1224 Comment = not_a_directory(File). 1225'$file_error'(file_type(_), Spec, File, Error, Comment) :- 1226 exists_directory(File), 1227 !, 1228 Error = existence_error(file, Spec), 1229 Comment = directory(File). 1230'$file_error'(access(OneOrList), Spec, File, Error, _) :- 1231 '$one_or_member'(Access, OneOrList), 1232 \+ access_file(File, Access), 1233 Error = permission_error(Access, source_sink, Spec). 1234 1235'$one_or_member'(Elem, List) :- 1236 is_list(List), 1237 !, 1238 '$member'(Elem, List). 1239'$one_or_member'(Elem, Elem). 1240 1241 1242'$file_type_extensions'(source, Exts) :- % SICStus 3.9 compatibility 1243 !, 1244 '$file_type_extensions'(prolog, Exts). 1245'$file_type_extensions'(Type, Exts) :- 1246 '$current_module'('$bags', _File), 1247 !, 1248 findall(Ext, user:prolog_file_type(Ext, Type), Exts0), 1249 ( Exts0 == [], 1250 \+ '$ft_no_ext'(Type) 1251 -> '$domain_error'(file_type, Type) 1252 ; true 1253 ), 1254 '$append'(Exts0, [''], Exts). 1255'$file_type_extensions'(prolog, [pl, '']). % findall is not yet defined ... 1256 1257'$ft_no_ext'(txt). 1258'$ft_no_ext'(executable). 1259'$ft_no_ext'(directory). 1260 1261%! user:prolog_file_type(?Extension, ?Type) 1262% 1263% Define type of file based on the extension. This is used by 1264% absolute_file_name/3 and may be used to extend the list of 1265% extensions used for some type. 1266% 1267% Note that =qlf= must be last when searching for Prolog files. 1268% Otherwise use_module/1 will consider the file as not-loaded 1269% because the .qlf file is not the loaded file. Must be fixed 1270% elsewhere. 1271 1272:- multifile(user:prolog_file_type/2). 1273:- dynamic(user:prolog_file_type/2). 1274 1275user:prolog_file_type(pl, prolog). 1276user:prolog_file_type(prolog, prolog). 1277user:prolog_file_type(qlf, prolog). 1278user:prolog_file_type(qlf, qlf). 1279user:prolog_file_type(Ext, executable) :- 1280 current_prolog_flag(shared_object_extension, Ext). 1281user:prolog_file_type(dylib, executable) :- 1282 current_prolog_flag(apple, true). 1283 1284%! '$chk_file'(+Spec, +Extensions, +Cond, +UseCache, -FullName) 1285% 1286% File is a specification of a Prolog source file. Return the full 1287% path of the file. 1288 1289'$chk_file'(Spec, _Extensions, _Cond, _Cache, _FullName) :- 1290 \+ ground(Spec), 1291 !, 1292 '$instantiation_error'(Spec). 1293'$chk_file'(Spec, Extensions, Cond, Cache, FullName) :- 1294 compound(Spec), 1295 functor(Spec, _, 1), 1296 !, 1297 '$relative_to'(Cond, cwd, CWD), 1298 '$chk_alias_file'(Spec, Extensions, Cond, Cache, CWD, FullName). 1299'$chk_file'(Segments, Ext, Cond, Cache, FullName) :- % allow a/b/... 1300 \+ atomic(Segments), 1301 !, 1302 '$segments_to_atom'(Segments, Atom), 1303 '$chk_file'(Atom, Ext, Cond, Cache, FullName). 1304'$chk_file'(File, Exts, Cond, _, FullName) :- 1305 is_absolute_file_name(File), 1306 !, 1307 '$extend_file'(File, Exts, Extended), 1308 '$file_conditions'(Cond, Extended), 1309 '$absolute_file_name'(Extended, FullName). 1310'$chk_file'(File, Exts, Cond, _, FullName) :- 1311 '$relative_to'(Cond, source, Dir), 1312 atomic_list_concat([Dir, /, File], AbsFile), 1313 '$extend_file'(AbsFile, Exts, Extended), 1314 '$file_conditions'(Cond, Extended), 1315 !, 1316 '$absolute_file_name'(Extended, FullName). 1317'$chk_file'(File, Exts, Cond, _, FullName) :- 1318 '$extend_file'(File, Exts, Extended), 1319 '$file_conditions'(Cond, Extended), 1320 '$absolute_file_name'(Extended, FullName). 1321 1322'$segments_to_atom'(Atom, Atom) :- 1323 atomic(Atom), 1324 !. 1325'$segments_to_atom'(Segments, Atom) :- 1326 '$segments_to_list'(Segments, List, []), 1327 !, 1328 atomic_list_concat(List, /, Atom). 1329 1330'$segments_to_list'(A/B, H, T) :- 1331 '$segments_to_list'(A, H, T0), 1332 '$segments_to_list'(B, T0, T). 1333'$segments_to_list'(A, [A|T], T) :- 1334 atomic(A). 1335 1336 1337%! '$relative_to'(+Condition, +Default, -Dir) 1338% 1339% Determine the directory to work from. This can be specified 1340% explicitely using one or more relative_to(FileOrDir) options 1341% or implicitely relative to the working directory or current 1342% source-file. 1343 1344'$relative_to'(Conditions, Default, Dir) :- 1345 ( '$option'(relative_to(FileOrDir), Conditions) 1346 *-> ( exists_directory(FileOrDir) 1347 -> Dir = FileOrDir 1348 ; atom_concat(Dir, /, FileOrDir) 1349 -> true 1350 ; file_directory_name(FileOrDir, Dir) 1351 ) 1352 ; Default == cwd 1353 -> '$cwd'(Dir) 1354 ; Default == source 1355 -> source_location(ContextFile, _Line), 1356 file_directory_name(ContextFile, Dir) 1357 ). 1358 1359%! '$chk_alias_file'(+Spec, +Exts, +Cond, +Cache, +CWD, 1360%! -FullFile) is nondet. 1361 1362:- dynamic 1363 '$search_path_file_cache'/3, % SHA1, Time, Path 1364 '$search_path_gc_time'/1. % Time 1365:- volatile 1366 '$search_path_file_cache'/3, 1367 '$search_path_gc_time'/1. 1368 1369:- create_prolog_flag(file_search_cache_time, 10, []). 1370 1371'$chk_alias_file'(Spec, Exts, Cond, true, CWD, FullFile) :- 1372 !, 1373 findall(Exp, expand_file_search_path(Spec, Exp), Expansions), 1374 Cache = cache(Exts, Cond, CWD, Expansions), 1375 variant_sha1(Spec+Cache, SHA1), 1376 get_time(Now), 1377 current_prolog_flag(file_search_cache_time, TimeOut), 1378 ( '$search_path_file_cache'(SHA1, CachedTime, FullFile), 1379 CachedTime > Now - TimeOut, 1380 '$file_conditions'(Cond, FullFile) 1381 -> '$search_message'(file_search(cache(Spec, Cond), FullFile)) 1382 ; '$member'(Expanded, Expansions), 1383 '$extend_file'(Expanded, Exts, LibFile), 1384 ( '$file_conditions'(Cond, LibFile), 1385 '$absolute_file_name'(LibFile, FullFile), 1386 '$cache_file_found'(SHA1, Now, TimeOut, FullFile) 1387 -> '$search_message'(file_search(found(Spec, Cond), FullFile)) 1388 ; '$search_message'(file_search(tried(Spec, Cond), LibFile)), 1389 fail 1390 ) 1391 ). 1392'$chk_alias_file'(Spec, Exts, Cond, false, _CWD, FullFile) :- 1393 expand_file_search_path(Spec, Expanded), 1394 '$extend_file'(Expanded, Exts, LibFile), 1395 '$file_conditions'(Cond, LibFile), 1396 '$absolute_file_name'(LibFile, FullFile). 1397 1398'$cache_file_found'(_, _, TimeOut, _) :- 1399 TimeOut =:= 0, 1400 !. 1401'$cache_file_found'(SHA1, Now, TimeOut, FullFile) :- 1402 '$search_path_file_cache'(SHA1, Saved, FullFile), 1403 !, 1404 ( Now - Saved < TimeOut/2 1405 -> true 1406 ; retractall('$search_path_file_cache'(SHA1, _, _)), 1407 asserta('$search_path_file_cache'(SHA1, Now, FullFile)) 1408 ). 1409'$cache_file_found'(SHA1, Now, TimeOut, FullFile) :- 1410 'gc_file_search_cache'(TimeOut), 1411 asserta('$search_path_file_cache'(SHA1, Now, FullFile)). 1412 1413'gc_file_search_cache'(TimeOut) :- 1414 get_time(Now), 1415 '$search_path_gc_time'(Last), 1416 Now-Last < TimeOut/2, 1417 !. 1418'gc_file_search_cache'(TimeOut) :- 1419 get_time(Now), 1420 retractall('$search_path_gc_time'(_)), 1421 assertz('$search_path_gc_time'(Now)), 1422 Before is Now - TimeOut, 1423 ( '$search_path_file_cache'(SHA1, Cached, FullFile), 1424 Cached < Before, 1425 retractall('$search_path_file_cache'(SHA1, Cached, FullFile)), 1426 fail 1427 ; true 1428 ). 1429 1430 1431'$search_message'(Term) :- 1432 current_prolog_flag(verbose_file_search, true), 1433 !, 1434 print_message(informational, Term). 1435'$search_message'(_). 1436 1437 1438%! '$file_conditions'(+Condition, +Path) 1439% 1440% Verify Path satisfies Condition. 1441 1442'$file_conditions'(List, File) :- 1443 is_list(List), 1444 !, 1445 \+ ( '$member'(C, List), 1446 '$file_condition'(C), 1447 \+ '$file_condition'(C, File) 1448 ). 1449'$file_conditions'(Map, File) :- 1450 \+ ( get_dict(Key, Map, Value), 1451 C =.. [Key,Value], 1452 '$file_condition'(C), 1453 \+ '$file_condition'(C, File) 1454 ). 1455 1456'$file_condition'(file_type(directory), File) :- 1457 !, 1458 exists_directory(File). 1459'$file_condition'(file_type(_), File) :- 1460 !, 1461 \+ exists_directory(File). 1462'$file_condition'(access(Accesses), File) :- 1463 !, 1464 \+ ( '$one_or_member'(Access, Accesses), 1465 \+ access_file(File, Access) 1466 ). 1467 1468'$file_condition'(exists). 1469'$file_condition'(file_type(_)). 1470'$file_condition'(access(_)). 1471 1472'$extend_file'(File, Exts, FileEx) :- 1473 '$ensure_extensions'(Exts, File, Fs), 1474 '$list_to_set'(Fs, FsSet), 1475 '$member'(FileEx, FsSet). 1476 1477'$ensure_extensions'([], _, []). 1478'$ensure_extensions'([E|E0], F, [FE|E1]) :- 1479 file_name_extension(F, E, FE), 1480 '$ensure_extensions'(E0, F, E1). 1481 1482%! '$list_to_set'(+List, -Set) is det. 1483% 1484% Turn list into a set, keeping the left-most copy of duplicate 1485% elements. Note that library(lists) provides an O(N*log(N)) 1486% version, but sets of file name extensions should be short enough 1487% for this not to matter. 1488 1489'$list_to_set'(List, Set) :- 1490 '$list_to_set'(List, [], Set). 1491 1492'$list_to_set'([], _, []). 1493'$list_to_set'([H|T], Seen, R) :- 1494 memberchk(H, Seen), 1495 !, 1496 '$list_to_set'(T, R). 1497'$list_to_set'([H|T], Seen, [H|R]) :- 1498 '$list_to_set'(T, [H|Seen], R). 1499 1500/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1501Canonicalise the extension list. Old SWI-Prolog require `.pl', etc, which 1502the Quintus compatibility requests `pl'. This layer canonicalises all 1503extensions to .ext 1504- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 1505 1506'$canonicalise_extensions'([], []) :- !. 1507'$canonicalise_extensions'([H|T], [CH|CT]) :- 1508 !, 1509 '$must_be'(atom, H), 1510 '$canonicalise_extension'(H, CH), 1511 '$canonicalise_extensions'(T, CT). 1512'$canonicalise_extensions'(E, [CE]) :- 1513 '$canonicalise_extension'(E, CE). 1514 1515'$canonicalise_extension'('', '') :- !. 1516'$canonicalise_extension'(DotAtom, DotAtom) :- 1517 sub_atom(DotAtom, 0, _, _, '.'), 1518 !. 1519'$canonicalise_extension'(Atom, DotAtom) :- 1520 atom_concat('.', Atom, DotAtom). 1521 1522 1523 /******************************** 1524 * CONSULT * 1525 *********************************/ 1526 1527:- dynamic 1528 user:library_directory/1, 1529 user:prolog_load_file/2. 1530:- multifile 1531 user:library_directory/1, 1532 user:prolog_load_file/2. 1533 1534:- prompt(_, '|: '). 1535 1536:- thread_local 1537 '$compilation_mode_store'/1, % database, wic, qlf 1538 '$directive_mode_store'/1. % database, wic, qlf 1539:- volatile 1540 '$compilation_mode_store'/1, 1541 '$directive_mode_store'/1. 1542 1543'$compilation_mode'(Mode) :- 1544 ( '$compilation_mode_store'(Val) 1545 -> Mode = Val 1546 ; Mode = database 1547 ). 1548 1549'$set_compilation_mode'(Mode) :- 1550 retractall('$compilation_mode_store'(_)), 1551 assertz('$compilation_mode_store'(Mode)). 1552 1553'$compilation_mode'(Old, New) :- 1554 '$compilation_mode'(Old), 1555 ( New == Old 1556 -> true 1557 ; '$set_compilation_mode'(New) 1558 ). 1559 1560'$directive_mode'(Mode) :- 1561 ( '$directive_mode_store'(Val) 1562 -> Mode = Val 1563 ; Mode = database 1564 ). 1565 1566'$directive_mode'(Old, New) :- 1567 '$directive_mode'(Old), 1568 ( New == Old 1569 -> true 1570 ; '$set_directive_mode'(New) 1571 ). 1572 1573'$set_directive_mode'(Mode) :- 1574 retractall('$directive_mode_store'(_)), 1575 assertz('$directive_mode_store'(Mode)). 1576 1577 1578%! '$compilation_level'(-Level) is det. 1579% 1580% True when Level reflects the nesting in files compiling other 1581% files. 0 if no files are being loaded. 1582 1583'$compilation_level'(Level) :- 1584 '$input_context'(Stack), 1585 '$compilation_level'(Stack, Level). 1586 1587'$compilation_level'([], 0). 1588'$compilation_level'([Input|T], Level) :- 1589 ( arg(1, Input, see) 1590 -> '$compilation_level'(T, Level) 1591 ; '$compilation_level'(T, Level0), 1592 Level is Level0+1 1593 ). 1594 1595 1596%! compiling 1597% 1598% Is true if SWI-Prolog is generating a state or qlf file or 1599% executes a `call' directive while doing this. 1600 1601compiling :- 1602 \+ ( '$compilation_mode'(database), 1603 '$directive_mode'(database) 1604 ). 1605 1606:- meta_predicate 1607 '$ifcompiling'(0). 1608 1609'$ifcompiling'(G) :- 1610 ( '$compilation_mode'(database) 1611 -> true 1612 ; call(G) 1613 ). 1614 1615 /******************************** 1616 * READ SOURCE * 1617 *********************************/ 1618 1619%! '$load_msg_level'(+Action, +NestingLevel, -StartVerbose, -EndVerbose) 1620 1621'$load_msg_level'(Action, Nesting, Start, Done) :- 1622 '$update_autoload_level'([], 0), 1623 !, 1624 current_prolog_flag(verbose_load, Type0), 1625 '$load_msg_compat'(Type0, Type), 1626 ( '$load_msg_level'(Action, Nesting, Type, Start, Done) 1627 -> true 1628 ). 1629'$load_msg_level'(_, _, silent, silent). 1630 1631'$load_msg_compat'(true, normal) :- !. 1632'$load_msg_compat'(false, silent) :- !. 1633'$load_msg_compat'(X, X). 1634 1635'$load_msg_level'(load_file, _, full, informational, informational). 1636'$load_msg_level'(include_file, _, full, informational, informational). 1637'$load_msg_level'(load_file, _, normal, silent, informational). 1638'$load_msg_level'(include_file, _, normal, silent, silent). 1639'$load_msg_level'(load_file, 0, brief, silent, informational). 1640'$load_msg_level'(load_file, _, brief, silent, silent). 1641'$load_msg_level'(include_file, _, brief, silent, silent). 1642'$load_msg_level'(load_file, _, silent, silent, silent). 1643'$load_msg_level'(include_file, _, silent, silent, silent). 1644 1645%! '$source_term'(+From, -Read, -RLayout, -Term, -TLayout, 1646%! -Stream, +Options) is nondet. 1647% 1648% Read Prolog terms from the input From. Terms are returned on 1649% backtracking. Associated resources (i.e., streams) are closed 1650% due to setup_call_cleanup/3. 1651% 1652% @param From is either a term stream(Id, Stream) or a file 1653% specification. 1654% @param Read is the raw term as read from the input. 1655% @param Term is the term after term-expansion. If a term is 1656% expanded into the empty list, this is returned too. This 1657% is required to be able to return the raw term in Read 1658% @param Stream is the stream from which Read is read 1659% @param Options provides additional options: 1660% * encoding(Enc) 1661% Encoding used to open From 1662% * syntax_errors(+ErrorMode) 1663% * process_comments(+Boolean) 1664% * term_position(-Pos) 1665 1666'$source_term'(From, Read, RLayout, Term, TLayout, Stream, Options) :- 1667 '$source_term'(From, Read, RLayout, Term, TLayout, Stream, [], Options), 1668 ( Term == end_of_file 1669 -> !, fail 1670 ; Term \== begin_of_file 1671 ). 1672 1673'$source_term'(Input, _,_,_,_,_,_,_) :- 1674 \+ ground(Input), 1675 !, 1676 '$instantiation_error'(Input). 1677'$source_term'(stream(Id, In, Opts), 1678 Read, RLayout, Term, TLayout, Stream, Parents, Options) :- 1679 !, 1680 '$record_included'(Parents, Id, Id, 0.0, Message), 1681 setup_call_cleanup( 1682 '$open_source'(stream(Id, In, Opts), In, State, Parents, Options), 1683 '$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, 1684 [Id|Parents], Options), 1685 '$close_source'(State, Message)). 1686'$source_term'(File, 1687 Read, RLayout, Term, TLayout, Stream, Parents, Options) :- 1688 absolute_file_name(File, Path, 1689 [ file_type(prolog), 1690 access(read) 1691 ]), 1692 time_file(Path, Time), 1693 '$record_included'(Parents, File, Path, Time, Message), 1694 setup_call_cleanup( 1695 '$open_source'(Path, In, State, Parents, Options), 1696 '$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, 1697 [Path|Parents], Options), 1698 '$close_source'(State, Message)). 1699 1700:- thread_local 1701 '$load_input'/2. 1702:- volatile 1703 '$load_input'/2. 1704 1705'$open_source'(stream(Id, In, Opts), In, 1706 restore(In, StreamState, Id, Ref, Opts), Parents, _Options) :- 1707 !, 1708 '$context_type'(Parents, ContextType), 1709 '$push_input_context'(ContextType), 1710 '$prepare_load_stream'(In, Id, StreamState), 1711 asserta('$load_input'(stream(Id), In), Ref). 1712'$open_source'(Path, In, close(In, Path, Ref), Parents, Options) :- 1713 '$context_type'(Parents, ContextType), 1714 '$push_input_context'(ContextType), 1715 '$open_source'(Path, In, Options), 1716 '$set_encoding'(In, Options), 1717 asserta('$load_input'(Path, In), Ref). 1718 1719'$context_type'([], load_file) :- !. 1720'$context_type'(_, include). 1721 1722:- multifile prolog:open_source_hook/3. 1723 1724'$open_source'(Path, In, Options) :- 1725 prolog:open_source_hook(Path, In, Options), 1726 !. 1727'$open_source'(Path, In, _Options) :- 1728 open(Path, read, In). 1729 1730'$close_source'(close(In, _Id, Ref), Message) :- 1731 erase(Ref), 1732 call_cleanup( 1733 close(In), 1734 '$pop_input_context'), 1735 '$close_message'(Message). 1736'$close_source'(restore(In, StreamState, _Id, Ref, Opts), Message) :- 1737 erase(Ref), 1738 call_cleanup( 1739 '$restore_load_stream'(In, StreamState, Opts), 1740 '$pop_input_context'), 1741 '$close_message'(Message). 1742 1743'$close_message'(message(Level, Msg)) :- 1744 !, 1745 '$print_message'(Level, Msg). 1746'$close_message'(_). 1747 1748 1749%! '$term_in_file'(+In, -Read, -RLayout, -Term, -TLayout, 1750%! -Stream, +Parents, +Options) is multi. 1751% 1752% True when Term is an expanded term from In. Read is a raw term 1753% (before term-expansion). Stream is the actual stream, which 1754% starts at In, but may change due to processing included files. 1755% 1756% @see '$source_term'/8 for details. 1757 1758'$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, Parents, Options) :- 1759 Parents \= [_,_|_], 1760 ( '$load_input'(_, Input) 1761 -> stream_property(Input, file_name(File)) 1762 ), 1763 '$set_source_location'(File, 0), 1764 '$expanded_term'(In, 1765 begin_of_file, 0-0, Read, RLayout, Term, TLayout, 1766 Stream, Parents, Options). 1767'$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, Parents, Options) :- 1768 '$skip_script_line'(In, Options), 1769 '$read_clause_options'(Options, ReadOptions), 1770 repeat, 1771 read_clause(In, Raw, 1772 [ variable_names(Bindings), 1773 term_position(Pos), 1774 subterm_positions(RawLayout) 1775 | ReadOptions 1776 ]), 1777 b_setval('$term_position', Pos), 1778 b_setval('$variable_names', Bindings), 1779 ( Raw == end_of_file 1780 -> !, 1781 ( Parents = [_,_|_] % Included file 1782 -> fail 1783 ; '$expanded_term'(In, 1784 Raw, RawLayout, Read, RLayout, Term, TLayout, 1785 Stream, Parents, Options) 1786 ) 1787 ; '$expanded_term'(In, Raw, RawLayout, Read, RLayout, Term, TLayout, 1788 Stream, Parents, Options) 1789 ). 1790 1791'$read_clause_options'([], []). 1792'$read_clause_options'([H|T0], List) :- 1793 ( '$read_clause_option'(H) 1794 -> List = [H|T] 1795 ; List = T 1796 ), 1797 '$read_clause_options'(T0, T). 1798 1799'$read_clause_option'(syntax_errors(_)). 1800'$read_clause_option'(term_position(_)). 1801'$read_clause_option'(process_comment(_)). 1802 1803'$expanded_term'(In, Raw, RawLayout, Read, RLayout, Term, TLayout, 1804 Stream, Parents, Options) :- 1805 E = error(_,_), 1806 catch('$expand_term'(Raw, RawLayout, Expanded, ExpandedLayout), E, 1807 '$print_message_fail'(E)), 1808 ( Expanded \== [] 1809 -> '$expansion_member'(Expanded, ExpandedLayout, Term1, Layout1) 1810 ; Term1 = Expanded, 1811 Layout1 = ExpandedLayout 1812 ), 1813 ( nonvar(Term1), Term1 = (:-Directive), nonvar(Directive) 1814 -> ( Directive = include(File), 1815 '$current_source_module'(Module), 1816 '$valid_directive'(Module:include(File)) 1817 -> stream_property(In, encoding(Enc)), 1818 '$add_encoding'(Enc, Options, Options1), 1819 '$source_term'(File, Read, RLayout, Term, TLayout, 1820 Stream, Parents, Options1) 1821 ; Directive = encoding(Enc) 1822 -> set_stream(In, encoding(Enc)), 1823 fail 1824 ; Term = Term1, 1825 Stream = In, 1826 Read = Raw 1827 ) 1828 ; Term = Term1, 1829 TLayout = Layout1, 1830 Stream = In, 1831 Read = Raw, 1832 RLayout = RawLayout 1833 ). 1834 1835'$expansion_member'(Var, Layout, Var, Layout) :- 1836 var(Var), 1837 !. 1838'$expansion_member'([], _, _, _) :- !, fail. 1839'$expansion_member'(List, ListLayout, Term, Layout) :- 1840 is_list(List), 1841 !, 1842 ( var(ListLayout) 1843 -> '$member'(Term, List) 1844 ; is_list(ListLayout) 1845 -> '$member_rep2'(Term, Layout, List, ListLayout) 1846 ; Layout = ListLayout, 1847 '$member'(Term, List) 1848 ). 1849'$expansion_member'(X, Layout, X, Layout). 1850 1851% pairwise member, repeating last element of the second 1852% list. 1853 1854'$member_rep2'(H1, H2, [H1|_], [H2|_]). 1855'$member_rep2'(H1, H2, [_|T1], [T2]) :- 1856 !, 1857 '$member_rep2'(H1, H2, T1, [T2]). 1858'$member_rep2'(H1, H2, [_|T1], [_|T2]) :- 1859 '$member_rep2'(H1, H2, T1, T2). 1860 1861%! '$add_encoding'(+Enc, +Options0, -Options) 1862 1863'$add_encoding'(Enc, Options0, Options) :- 1864 ( Options0 = [encoding(Enc)|_] 1865 -> Options = Options0 1866 ; Options = [encoding(Enc)|Options0] 1867 ). 1868 1869 1870:- multifile 1871 '$included'/4. % Into, Line, File, LastModified 1872:- dynamic 1873 '$included'/4. 1874 1875%! '$record_included'(+Parents, +File, +Path, +Time, -Message) is det. 1876% 1877% Record that we included File into the head of Parents. This is 1878% troublesome when creating a QLF file because this may happen 1879% before we opened the QLF file (and we do not yet know how to 1880% open the file because we do not yet know whether this is a 1881% module file or not). 1882% 1883% I think that the only sensible solution is to have a special 1884% statement for this, that may appear both inside and outside QLF 1885% `parts'. 1886 1887'$record_included'([Parent|Parents], File, Path, Time, 1888 message(DoneMsgLevel, 1889 include_file(done(Level, file(File, Path))))) :- 1890 source_location(SrcFile, Line), 1891 !, 1892 '$compilation_level'(Level), 1893 '$load_msg_level'(include_file, Level, StartMsgLevel, DoneMsgLevel), 1894 '$print_message'(StartMsgLevel, 1895 include_file(start(Level, 1896 file(File, Path)))), 1897 '$last'([Parent|Parents], Owner), 1898 ( ( '$compilation_mode'(database) 1899 ; '$qlf_current_source'(Owner) 1900 ) 1901 -> '$store_admin_clause'( 1902 system:'$included'(Parent, Line, Path, Time), 1903 _, Owner, SrcFile:Line) 1904 ; '$qlf_include'(Owner, Parent, Line, Path, Time) 1905 ). 1906'$record_included'(_, _, _, _, true). 1907 1908%! '$master_file'(+File, -MasterFile) 1909% 1910% Find the primary load file from included files. 1911 1912'$master_file'(File, MasterFile) :- 1913 '$included'(MasterFile0, _Line, File, _Time), 1914 !, 1915 '$master_file'(MasterFile0, MasterFile). 1916'$master_file'(File, File). 1917 1918 1919'$skip_script_line'(_In, Options) :- 1920 '$option'(check_script(false), Options), 1921 !. 1922'$skip_script_line'(In, _Options) :- 1923 ( peek_char(In, #) 1924 -> skip(In, 10) 1925 ; true 1926 ). 1927 1928'$set_encoding'(Stream, Options) :- 1929 '$option'(encoding(Enc), Options), 1930 !, 1931 Enc \== default, 1932 set_stream(Stream, encoding(Enc)). 1933'$set_encoding'(_, _). 1934 1935 1936'$prepare_load_stream'(In, Id, state(HasName,HasPos)) :- 1937 ( stream_property(In, file_name(_)) 1938 -> HasName = true, 1939 ( stream_property(In, position(_)) 1940 -> HasPos = true 1941 ; HasPos = false, 1942 set_stream(In, record_position(true)) 1943 ) 1944 ; HasName = false, 1945 set_stream(In, file_name(Id)), 1946 ( stream_property(In, position(_)) 1947 -> HasPos = true 1948 ; HasPos = false, 1949 set_stream(In, record_position(true)) 1950 ) 1951 ). 1952 1953'$restore_load_stream'(In, _State, Options) :- 1954 memberchk(close(true), Options), 1955 !, 1956 close(In). 1957'$restore_load_stream'(In, state(HasName, HasPos), _Options) :- 1958 ( HasName == false 1959 -> set_stream(In, file_name('')) 1960 ; true 1961 ), 1962 ( HasPos == false 1963 -> set_stream(In, record_position(false)) 1964 ; true 1965 ). 1966 1967 1968 /******************************* 1969 * DERIVED FILES * 1970 *******************************/ 1971 1972:- dynamic 1973 '$derived_source_db'/3. % Loaded, DerivedFrom, Time 1974 1975'$register_derived_source'(_, '-') :- !. 1976'$register_derived_source'(Loaded, DerivedFrom) :- 1977 retractall('$derived_source_db'(Loaded, _, _)), 1978 time_file(DerivedFrom, Time), 1979 assert('$derived_source_db'(Loaded, DerivedFrom, Time)). 1980 1981% Auto-importing dynamic predicates is not very elegant and 1982% leads to problems with qsave_program/[1,2] 1983 1984'$derived_source'(Loaded, DerivedFrom, Time) :- 1985 '$derived_source_db'(Loaded, DerivedFrom, Time). 1986 1987 1988 /******************************** 1989 * LOAD PREDICATES * 1990 *********************************/ 1991 1992:- meta_predicate 1993 ensure_loaded(:), 1994 [:|+], 1995 consult(:), 1996 use_module(:), 1997 use_module(:, +), 1998 reexport(:), 1999 reexport(:, +), 2000 load_files(:), 2001 load_files(:, +). 2002 2003%! ensure_loaded(+FileOrListOfFiles) 2004% 2005% Load specified files, provided they where not loaded before. If the 2006% file is a module file import the public predicates into the context 2007% module. 2008 2009ensure_loaded(Files) :- 2010 load_files(Files, [if(not_loaded)]). 2011 2012%! use_module(+FileOrListOfFiles) 2013% 2014% Very similar to ensure_loaded/1, but insists on the loaded file to 2015% be a module file. If the file is already imported, but the public 2016% predicates are not yet imported into the context module, then do 2017% so. 2018 2019use_module(Files) :- 2020 load_files(Files, [ if(not_loaded), 2021 must_be_module(true) 2022 ]). 2023 2024%! use_module(+File, +ImportList) 2025% 2026% As use_module/1, but takes only one file argument and imports only 2027% the specified predicates rather than all public predicates. 2028 2029use_module(File, Import) :- 2030 load_files(File, [ if(not_loaded), 2031 must_be_module(true), 2032 imports(Import) 2033 ]). 2034 2035%! reexport(+Files) 2036% 2037% As use_module/1, exporting all imported predicates. 2038 2039reexport(Files) :- 2040 load_files(Files, [ if(not_loaded), 2041 must_be_module(true), 2042 reexport(true) 2043 ]). 2044 2045%! reexport(+File, +ImportList) 2046% 2047% As use_module/1, re-exporting all imported predicates. 2048 2049reexport(File, Import) :- 2050 load_files(File, [ if(not_loaded), 2051 must_be_module(true), 2052 imports(Import), 2053 reexport(true) 2054 ]). 2055 2056 2057[X] :- 2058 !, 2059 consult(X). 2060[M:F|R] :- 2061 consult(M:[F|R]). 2062 2063consult(M:X) :- 2064 X == user, 2065 !, 2066 flag('$user_consult', N, N+1), 2067 NN is N + 1, 2068 atom_concat('user://', NN, Id), 2069 load_files(M:Id, [stream(user_input), check_script(false), silent(false)]). 2070consult(List) :- 2071 load_files(List, [expand(true)]). 2072 2073%! load_files(:File, +Options) 2074% 2075% Common entry for all the consult derivates. File is the raw user 2076% specified file specification, possibly tagged with the module. 2077 2078load_files(Files) :- 2079 load_files(Files, []). 2080load_files(Module:Files, Options) :- 2081 '$must_be'(list, Options), 2082 '$load_files'(Files, Module, Options). 2083 2084'$load_files'(X, _, _) :- 2085 var(X), 2086 !, 2087 '$instantiation_error'(X). 2088'$load_files'([], _, _) :- !. 2089'$load_files'(Id, Module, Options) :- % load_files(foo, [stream(In)]) 2090 '$option'(stream(_), Options), 2091 !, 2092 ( atom(Id) 2093 -> '$load_file'(Id, Module, Options) 2094 ; throw(error(type_error(atom, Id), _)) 2095 ). 2096'$load_files'(List, Module, Options) :- 2097 List = [_|_], 2098 !, 2099 '$must_be'(list, List), 2100 '$load_file_list'(List, Module, Options). 2101'$load_files'(File, Module, Options) :- 2102 '$load_one_file'(File, Module, Options). 2103 2104'$load_file_list'([], _, _). 2105'$load_file_list'([File|Rest], Module, Options) :- 2106 E = error(_,_), 2107 catch('$load_one_file'(File, Module, Options), E, 2108 '$print_message'(error, E)), 2109 '$load_file_list'(Rest, Module, Options). 2110 2111 2112'$load_one_file'(Spec, Module, Options) :- 2113 atomic(Spec), 2114 '$option'(expand(Expand), Options, false), 2115 Expand == true, 2116 !, 2117 expand_file_name(Spec, Expanded), 2118 ( Expanded = [Load] 2119 -> true 2120 ; Load = Expanded 2121 ), 2122 '$load_files'(Load, Module, [expand(false)|Options]). 2123'$load_one_file'(File, Module, Options) :- 2124 strip_module(Module:File, Into, PlainFile), 2125 '$load_file'(PlainFile, Into, Options). 2126 2127 2128%! '$noload'(+Condition, +FullFile, +Options) is semidet. 2129% 2130% True of FullFile should _not_ be loaded. 2131 2132'$noload'(true, _, _) :- 2133 !, 2134 fail. 2135'$noload'(_, FullFile, _Options) :- 2136 '$time_source_file'(FullFile, Time, system), 2137 Time > 0.0, 2138 !. 2139'$noload'(not_loaded, FullFile, _) :- 2140 source_file(FullFile), 2141 !. 2142'$noload'(changed, Derived, _) :- 2143 '$derived_source'(_FullFile, Derived, LoadTime), 2144 time_file(Derived, Modified), 2145 Modified @=< LoadTime, 2146 !. 2147'$noload'(changed, FullFile, Options) :- 2148 '$time_source_file'(FullFile, LoadTime, user), 2149 '$modified_id'(FullFile, Modified, Options), 2150 Modified @=< LoadTime, 2151 !. 2152 2153%! '$qlf_file'(+Spec, +PlFile, -LoadFile, -Mode, +Options) is det. 2154% 2155% Determine how to load the source. LoadFile is the file to be loaded, 2156% Mode is how to load it. Mode is one of 2157% 2158% - compile 2159% Normal source compilation 2160% - qcompile 2161% Compile from source, creating a QLF file in the process 2162% - qload 2163% Load from QLF file. 2164% - stream 2165% Load from a stream. Content can be a source or QLF file. 2166% 2167% @arg Spec is the original search specification 2168% @arg PlFile is the resolved absolute path to the Prolog file. 2169 2170'$qlf_file'(Spec, _, Spec, stream, Options) :- 2171 '$option'(stream(_), Options), % stream: no choice 2172 !. 2173'$qlf_file'(Spec, FullFile, FullFile, compile, _) :- 2174 '$spec_extension'(Spec, Ext), % user explicitly specified 2175 user:prolog_file_type(Ext, prolog), 2176 !. 2177'$qlf_file'(Spec, FullFile, LoadFile, Mode, Options) :- 2178 '$compilation_mode'(database), 2179 file_name_extension(Base, PlExt, FullFile), 2180 user:prolog_file_type(PlExt, prolog), 2181 user:prolog_file_type(QlfExt, qlf), 2182 file_name_extension(Base, QlfExt, QlfFile), 2183 ( access_file(QlfFile, read), 2184 ( '$qlf_out_of_date'(FullFile, QlfFile, Why) 2185 -> ( access_file(QlfFile, write) 2186 -> print_message(informational, 2187 qlf(recompile(Spec, FullFile, QlfFile, Why))), 2188 Mode = qcompile, 2189 LoadFile = FullFile 2190 ; Why == old, 2191 current_prolog_flag(home, PlHome), 2192 sub_atom(FullFile, 0, _, _, PlHome) 2193 -> print_message(silent, 2194 qlf(system_lib_out_of_date(Spec, QlfFile))), 2195 Mode = qload, 2196 LoadFile = QlfFile 2197 ; print_message(warning, 2198 qlf(can_not_recompile(Spec, QlfFile, Why))), 2199 Mode = compile, 2200 LoadFile = FullFile 2201 ) 2202 ; Mode = qload, 2203 LoadFile = QlfFile 2204 ) 2205 -> ! 2206 ; '$qlf_auto'(FullFile, QlfFile, Options) 2207 -> !, Mode = qcompile, 2208 LoadFile = FullFile 2209 ). 2210'$qlf_file'(_, FullFile, FullFile, compile, _). 2211 2212 2213%! '$qlf_out_of_date'(+PlFile, +QlfFile, -Why) is semidet. 2214% 2215% True if the QlfFile file is out-of-date because of Why. This 2216% predicate is the negation such that we can return the reason. 2217 2218'$qlf_out_of_date'(PlFile, QlfFile, Why) :- 2219 ( access_file(PlFile, read) 2220 -> time_file(PlFile, PlTime), 2221 time_file(QlfFile, QlfTime), 2222 ( PlTime > QlfTime 2223 -> Why = old % PlFile is newer 2224 ; Error = error(Formal,_), 2225 catch('$qlf_sources'(QlfFile, _Files), Error, true), 2226 nonvar(Formal) % QlfFile is incompatible 2227 -> Why = Error 2228 ; fail % QlfFile is up-to-date and ok 2229 ) 2230 ; fail % can not read .pl; try .qlf 2231 ). 2232 2233%! '$qlf_auto'(+PlFile, +QlfFile, +Options) is semidet. 2234% 2235% True if we create QlfFile using qcompile/2. This is determined 2236% by the option qcompile(QlfMode) or, if this is not present, by 2237% the prolog_flag qcompile. 2238 2239:- create_prolog_flag(qcompile, false, [type(atom)]). 2240 2241'$qlf_auto'(PlFile, QlfFile, Options) :- 2242 ( memberchk(qcompile(QlfMode), Options) 2243 -> true 2244 ; current_prolog_flag(qcompile, QlfMode), 2245 \+ '$in_system_dir'(PlFile) 2246 ), 2247 ( QlfMode == auto 2248 -> true 2249 ; QlfMode == large, 2250 size_file(PlFile, Size), 2251 Size > 100000 2252 ), 2253 access_file(QlfFile, write). 2254 2255'$in_system_dir'(PlFile) :- 2256 current_prolog_flag(home, Home), 2257 sub_atom(PlFile, 0, _, _, Home). 2258 2259'$spec_extension'(File, Ext) :- 2260 atom(File), 2261 file_name_extension(_, Ext, File). 2262'$spec_extension'(Spec, Ext) :- 2263 compound(Spec), 2264 arg(1, Spec, Arg), 2265 '$spec_extension'(Arg, Ext). 2266 2267 2268%! '$load_file'(+Spec, +ContextModule, +Options) is det. 2269% 2270% Load the file Spec into ContextModule controlled by Options. 2271% This wrapper deals with two cases before proceeding to the real 2272% loader: 2273% 2274% * User hooks based on prolog_load_file/2 2275% * The file is already loaded. 2276 2277:- dynamic 2278 '$resolved_source_path'/2. % ?Spec, ?Path 2279 2280'$load_file'(File, Module, Options) :- 2281 \+ memberchk(stream(_), Options), 2282 user:prolog_load_file(Module:File, Options), 2283 !. 2284'$load_file'(File, Module, Options) :- 2285 memberchk(stream(_), Options), 2286 !, 2287 '$assert_load_context_module'(File, Module, Options), 2288 '$qdo_load_file'(File, File, Module, Options). 2289'$load_file'(File, Module, Options) :- 2290 ( '$resolved_source_path'(File, FullFile, Options) 2291 -> true 2292 ; '$resolve_source_path'(File, FullFile, Options) 2293 ), 2294 '$mt_load_file'(File, FullFile, Module, Options). 2295 2296%! '$resolved_source_path'(+File, -FullFile, +Options) is semidet. 2297% 2298% True when File has already been resolved to an absolute path. 2299 2300'$resolved_source_path'(File, FullFile, Options) :- 2301 '$resolved_source_path'(File, FullFile), 2302 ( '$source_file_property'(FullFile, from_state, true) 2303 ; '$source_file_property'(FullFile, resource, true) 2304 ; '$option'(if(If), Options, true), 2305 '$noload'(If, FullFile, Options) 2306 ), 2307 !. 2308 2309%! '$resolve_source_path'(+File, -FullFile, Options) is det. 2310% 2311% Resolve a source file specification to an absolute path. May throw 2312% existence and other errors. 2313 2314'$resolve_source_path'(File, FullFile, _Options) :- 2315 absolute_file_name(File, FullFile, 2316 [ file_type(prolog), 2317 access(read) 2318 ]), 2319 '$register_resolved_source_path'(File, FullFile). 2320 2321 2322'$register_resolved_source_path'(File, FullFile) :- 2323 '$resolved_source_path'(File, FullFile), 2324 !. 2325'$register_resolved_source_path'(File, FullFile) :- 2326 compound(File), 2327 !, 2328 asserta('$resolved_source_path'(File, FullFile)). 2329'$register_resolved_source_path'(_, _). 2330 2331%! '$translated_source'(+Old, +New) is det. 2332% 2333% Called from loading a QLF state when source files are being renamed. 2334 2335:- public '$translated_source'/2. 2336'$translated_source'(Old, New) :- 2337 forall(retract('$resolved_source_path'(File, Old)), 2338 assertz('$resolved_source_path'(File, New))). 2339 2340%! '$register_resource_file'(+FullFile) is det. 2341% 2342% If we load a file from a resource we lock it, so we never have to 2343% check the modification again. 2344 2345'$register_resource_file'(FullFile) :- 2346 ( sub_atom(FullFile, 0, _, _, 'res://') 2347 -> '$set_source_file'(FullFile, resource, true) 2348 ; true 2349 ). 2350 2351%! '$already_loaded'(+File, +FullFile, +Module, +Options) is det. 2352% 2353% Called if File is already loaded. If this is a module-file, the 2354% module must be imported into the context Module. If it is not a 2355% module file, it must be reloaded. 2356% 2357% @bug A file may be associated with multiple modules. How 2358% do we find the `main export module'? Currently there 2359% is no good way to find out which module is associated 2360% to the file as a result of the first :- module/2 term. 2361 2362'$already_loaded'(_File, FullFile, Module, Options) :- 2363 '$assert_load_context_module'(FullFile, Module, Options), 2364 '$current_module'(LoadModules, FullFile), 2365 !, 2366 ( atom(LoadModules) 2367 -> LoadModule = LoadModules 2368 ; LoadModules = [LoadModule|_] 2369 ), 2370 '$import_from_loaded_module'(LoadModule, Module, Options). 2371'$already_loaded'(_, _, user, _) :- !. 2372'$already_loaded'(File, FullFile, Module, Options) :- 2373 ( '$load_context_module'(FullFile, Module, CtxOptions), 2374 '$load_ctx_options'(Options, CtxOptions) 2375 -> true 2376 ; '$load_file'(File, Module, [if(true)|Options]) 2377 ). 2378 2379%! '$mt_load_file'(+File, +FullFile, +Module, +Options) is det. 2380% 2381% Deal with multi-threaded loading of files. The thread that 2382% wishes to load the thread first will do so, while other threads 2383% will wait until the leader finished and than act as if the file 2384% is already loaded. 2385% 2386% Synchronisation is handled using a message queue that exists 2387% while the file is being loaded. This synchronisation relies on 2388% the fact that thread_get_message/1 throws an existence_error if 2389% the message queue is destroyed. This is hacky. Events or 2390% condition variables would have made a cleaner design. 2391 2392:- dynamic 2393 '$loading_file'/3. % File, Queue, Thread 2394:- volatile 2395 '$loading_file'/3. 2396 2397'$mt_load_file'(File, FullFile, Module, Options) :- 2398 current_prolog_flag(threads, true), 2399 !, 2400 setup_call_cleanup( 2401 with_mutex('$load_file', 2402 '$mt_start_load'(FullFile, Loading, Options)), 2403 '$mt_do_load'(Loading, File, FullFile, Module, Options), 2404 '$mt_end_load'(Loading)). 2405'$mt_load_file'(File, FullFile, Module, Options) :- 2406 '$option'(if(If), Options, true), 2407 '$noload'(If, FullFile, Options), 2408 !, 2409 '$already_loaded'(File, FullFile, Module, Options). 2410'$mt_load_file'(File, FullFile, Module, Options) :- 2411 '$qdo_load_file'(File, FullFile, Module, Options). 2412 2413'$mt_start_load'(FullFile, queue(Queue), _) :- 2414 '$loading_file'(FullFile, Queue, LoadThread), 2415 \+ thread_self(LoadThread), 2416 !. 2417'$mt_start_load'(FullFile, already_loaded, Options) :- 2418 '$option'(if(If), Options, true), 2419 '$noload'(If, FullFile, Options), 2420 !. 2421'$mt_start_load'(FullFile, Ref, _) :- 2422 thread_self(Me), 2423 message_queue_create(Queue), 2424 assertz('$loading_file'(FullFile, Queue, Me), Ref). 2425 2426'$mt_do_load'(queue(Queue), File, FullFile, Module, Options) :- 2427 !, 2428 catch(thread_get_message(Queue, _), error(_,_), true), 2429 '$already_loaded'(File, FullFile, Module, Options). 2430'$mt_do_load'(already_loaded, File, FullFile, Module, Options) :- 2431 !, 2432 '$already_loaded'(File, FullFile, Module, Options). 2433'$mt_do_load'(_Ref, File, FullFile, Module, Options) :- 2434 '$assert_load_context_module'(FullFile, Module, Options), 2435 '$qdo_load_file'(File, FullFile, Module, Options). 2436 2437'$mt_end_load'(queue(_)) :- !. 2438'$mt_end_load'(already_loaded) :- !. 2439'$mt_end_load'(Ref) :- 2440 clause('$loading_file'(_, Queue, _), _, Ref), 2441 erase(Ref), 2442 thread_send_message(Queue, done), 2443 message_queue_destroy(Queue). 2444 2445 2446%! '$qdo_load_file'(+Spec, +FullFile, +ContextModule, +Options) is det. 2447% 2448% Switch to qcompile mode if requested by the option '$qlf'(+Out) 2449 2450'$qdo_load_file'(File, FullFile, Module, Options) :- 2451 '$qdo_load_file2'(File, FullFile, Module, Action, Options), 2452 '$register_resource_file'(FullFile), 2453 '$run_initialization'(FullFile, Action, Options). 2454 2455'$qdo_load_file2'(File, FullFile, Module, Action, Options) :- 2456 memberchk('$qlf'(QlfOut), Options), 2457 '$stage_file'(QlfOut, StageQlf), 2458 !, 2459 setup_call_catcher_cleanup( 2460 '$qstart'(StageQlf, Module, State), 2461 '$do_load_file'(File, FullFile, Module, Action, Options), 2462 Catcher, 2463 '$qend'(State, Catcher, StageQlf, QlfOut)). 2464'$qdo_load_file2'(File, FullFile, Module, Action, Options) :- 2465 '$do_load_file'(File, FullFile, Module, Action, Options). 2466 2467'$qstart'(Qlf, Module, state(OldMode, OldModule)) :- 2468 '$qlf_open'(Qlf), 2469 '$compilation_mode'(OldMode, qlf), 2470 '$set_source_module'(OldModule, Module). 2471 2472'$qend'(state(OldMode, OldModule), Catcher, StageQlf, QlfOut) :- 2473 '$set_source_module'(_, OldModule), 2474 '$set_compilation_mode'(OldMode), 2475 '$qlf_close', 2476 '$install_staged_file'(Catcher, StageQlf, QlfOut, warn). 2477 2478'$set_source_module'(OldModule, Module) :- 2479 '$current_source_module'(OldModule), 2480 '$set_source_module'(Module). 2481 2482%! '$do_load_file'(+Spec, +FullFile, +ContextModule, 2483%! -Action, +Options) is det. 2484% 2485% Perform the actual loading. 2486 2487'$do_load_file'(File, FullFile, Module, Action, Options) :- 2488 '$option'(derived_from(DerivedFrom), Options, -), 2489 '$register_derived_source'(FullFile, DerivedFrom), 2490 '$qlf_file'(File, FullFile, Absolute, Mode, Options), 2491 ( Mode == qcompile 2492 -> qcompile(Module:File, Options) 2493 ; '$do_load_file_2'(File, Absolute, Module, Action, Options) 2494 ). 2495 2496'$do_load_file_2'(File, Absolute, Module, Action, Options) :- 2497 '$source_file_property'(Absolute, number_of_clauses, OldClauses), 2498 statistics(cputime, OldTime), 2499 2500 '$setup_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef, 2501 Options), 2502 2503 '$compilation_level'(Level), 2504 '$load_msg_level'(load_file, Level, StartMsgLevel, DoneMsgLevel), 2505 '$print_message'(StartMsgLevel, 2506 load_file(start(Level, 2507 file(File, Absolute)))), 2508 2509 ( memberchk(stream(FromStream), Options) 2510 -> Input = stream 2511 ; Input = source 2512 ), 2513 2514 ( Input == stream, 2515 ( '$option'(format(qlf), Options, source) 2516 -> set_stream(FromStream, file_name(Absolute)), 2517 '$qload_stream'(FromStream, Module, Action, LM, Options) 2518 ; '$consult_file'(stream(Absolute, FromStream, []), 2519 Module, Action, LM, Options) 2520 ) 2521 -> true 2522 ; Input == source, 2523 file_name_extension(_, Ext, Absolute), 2524 ( user:prolog_file_type(Ext, qlf), 2525 E = error(_,_), 2526 catch('$qload_file'(Absolute, Module, Action, LM, Options), 2527 E, 2528 print_message(warning, E)) 2529 -> true 2530 ; '$consult_file'(Absolute, Module, Action, LM, Options) 2531 ) 2532 -> true 2533 ; '$print_message'(error, load_file(failed(File))), 2534 fail 2535 ), 2536 2537 '$import_from_loaded_module'(LM, Module, Options), 2538 2539 '$source_file_property'(Absolute, number_of_clauses, NewClauses), 2540 statistics(cputime, Time), 2541 ClausesCreated is NewClauses - OldClauses, 2542 TimeUsed is Time - OldTime, 2543 2544 '$print_message'(DoneMsgLevel, 2545 load_file(done(Level, 2546 file(File, Absolute), 2547 Action, 2548 LM, 2549 TimeUsed, 2550 ClausesCreated))), 2551 2552 '$restore_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef). 2553 2554'$setup_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef, 2555 Options) :- 2556 '$save_file_scoped_flags'(ScopedFlags), 2557 '$set_sandboxed_load'(Options, OldSandBoxed), 2558 '$set_verbose_load'(Options, OldVerbose), 2559 '$set_optimise_load'(Options), 2560 '$update_autoload_level'(Options, OldAutoLevel), 2561 '$set_no_xref'(OldXRef). 2562 2563'$restore_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef) :- 2564 '$set_autoload_level'(OldAutoLevel), 2565 set_prolog_flag(xref, OldXRef), 2566 set_prolog_flag(verbose_load, OldVerbose), 2567 set_prolog_flag(sandboxed_load, OldSandBoxed), 2568 '$restore_file_scoped_flags'(ScopedFlags). 2569 2570 2571%! '$save_file_scoped_flags'(-State) is det. 2572%! '$restore_file_scoped_flags'(-State) is det. 2573% 2574% Save/restore flags that are scoped to a compilation unit. 2575 2576'$save_file_scoped_flags'(State) :- 2577 current_predicate(findall/3), % Not when doing boot compile 2578 !, 2579 findall(SavedFlag, '$save_file_scoped_flag'(SavedFlag), State). 2580'$save_file_scoped_flags'([]). 2581 2582'$save_file_scoped_flag'(Flag-Value) :- 2583 '$file_scoped_flag'(Flag, Default), 2584 ( current_prolog_flag(Flag, Value) 2585 -> true 2586 ; Value = Default 2587 ). 2588 2589'$file_scoped_flag'(generate_debug_info, true). 2590'$file_scoped_flag'(optimise, false). 2591'$file_scoped_flag'(xref, false). 2592 2593'$restore_file_scoped_flags'([]). 2594'$restore_file_scoped_flags'([Flag-Value|T]) :- 2595 set_prolog_flag(Flag, Value), 2596 '$restore_file_scoped_flags'(T). 2597 2598 2599%! '$import_from_loaded_module'(LoadedModule, Module, Options) is det. 2600% 2601% Import public predicates from LoadedModule into Module 2602 2603'$import_from_loaded_module'(LoadedModule, Module, Options) :- 2604 LoadedModule \== Module, 2605 atom(LoadedModule), 2606 !, 2607 '$option'(imports(Import), Options, all), 2608 '$option'(reexport(Reexport), Options, false), 2609 '$import_list'(Module, LoadedModule, Import, Reexport). 2610'$import_from_loaded_module'(_, _, _). 2611 2612 2613%! '$set_verbose_load'(+Options, -Old) is det. 2614% 2615% Set the =verbose_load= flag according to Options and unify Old 2616% with the old value. 2617 2618'$set_verbose_load'(Options, Old) :- 2619 current_prolog_flag(verbose_load, Old), 2620 ( memberchk(silent(Silent), Options) 2621 -> ( '$negate'(Silent, Level0) 2622 -> '$load_msg_compat'(Level0, Level) 2623 ; Level = Silent 2624 ), 2625 set_prolog_flag(verbose_load, Level) 2626 ; true 2627 ). 2628 2629'$negate'(true, false). 2630'$negate'(false, true). 2631 2632%! '$set_sandboxed_load'(+Options, -Old) is det. 2633% 2634% Update the Prolog flag =sandboxed_load= from Options. Old is 2635% unified with the old flag. 2636% 2637% @error permission_error(leave, sandbox, -) 2638 2639'$set_sandboxed_load'(Options, Old) :- 2640 current_prolog_flag(sandboxed_load, Old), 2641 ( memberchk(sandboxed(SandBoxed), Options), 2642 '$enter_sandboxed'(Old, SandBoxed, New), 2643 New \== Old 2644 -> set_prolog_flag(sandboxed_load, New) 2645 ; true 2646 ). 2647 2648'$enter_sandboxed'(Old, New, SandBoxed) :- 2649 ( Old == false, New == true 2650 -> SandBoxed = true, 2651 '$ensure_loaded_library_sandbox' 2652 ; Old == true, New == false 2653 -> throw(error(permission_error(leave, sandbox, -), _)) 2654 ; SandBoxed = Old 2655 ). 2656'$enter_sandboxed'(false, true, true). 2657 2658'$ensure_loaded_library_sandbox' :- 2659 source_file_property(library(sandbox), module(sandbox)), 2660 !. 2661'$ensure_loaded_library_sandbox' :- 2662 load_files(library(sandbox), [if(not_loaded), silent(true)]). 2663 2664'$set_optimise_load'(Options) :- 2665 ( '$option'(optimise(Optimise), Options) 2666 -> set_prolog_flag(optimise, Optimise) 2667 ; true 2668 ). 2669 2670'$set_no_xref'(OldXRef) :- 2671 ( current_prolog_flag(xref, OldXRef) 2672 -> true 2673 ; OldXRef = false 2674 ), 2675 set_prolog_flag(xref, false). 2676 2677 2678%! '$update_autoload_level'(+Options, -OldLevel) 2679% 2680% Update the '$autoload_nesting' and return the old value. 2681 2682:- thread_local 2683 '$autoload_nesting'/1. 2684 2685'$update_autoload_level'(Options, AutoLevel) :- 2686 '$option'(autoload(Autoload), Options, false), 2687 ( '$autoload_nesting'(CurrentLevel) 2688 -> AutoLevel = CurrentLevel 2689 ; AutoLevel = 0 2690 ), 2691 ( Autoload == false 2692 -> true 2693 ; NewLevel is AutoLevel + 1, 2694 '$set_autoload_level'(NewLevel) 2695 ). 2696 2697'$set_autoload_level'(New) :- 2698 retractall('$autoload_nesting'(_)), 2699 asserta('$autoload_nesting'(New)). 2700 2701 2702%! '$print_message'(+Level, +Term) is det. 2703% 2704% As print_message/2, but deal with the fact that the message 2705% system might not yet be loaded. 2706 2707'$print_message'(Level, Term) :- 2708 current_predicate(system:print_message/2), 2709 !, 2710 print_message(Level, Term). 2711'$print_message'(warning, Term) :- 2712 source_location(File, Line), 2713 !, 2714 format(user_error, 'WARNING: ~w:~w: ~p~n', [File, Line, Term]). 2715'$print_message'(error, Term) :- 2716 !, 2717 source_location(File, Line), 2718 !, 2719 format(user_error, 'ERROR: ~w:~w: ~p~n', [File, Line, Term]). 2720'$print_message'(_Level, _Term). 2721 2722'$print_message_fail'(E) :- 2723 '$print_message'(error, E), 2724 fail. 2725 2726%! '$consult_file'(+Path, +Module, -Action, -LoadedIn, +Options) 2727% 2728% Called from '$do_load_file'/4 using the goal returned by 2729% '$consult_goal'/2. This means that the calling conventions must 2730% be kept synchronous with '$qload_file'/6. 2731 2732'$consult_file'(Absolute, Module, What, LM, Options) :- 2733 '$current_source_module'(Module), % same module 2734 !, 2735 '$consult_file_2'(Absolute, Module, What, LM, Options). 2736'$consult_file'(Absolute, Module, What, LM, Options) :- 2737 '$set_source_module'(OldModule, Module), 2738 '$ifcompiling'('$qlf_start_sub_module'(Module)), 2739 '$consult_file_2'(Absolute, Module, What, LM, Options), 2740 '$ifcompiling'('$qlf_end_part'), 2741 '$set_source_module'(OldModule). 2742 2743'$consult_file_2'(Absolute, Module, What, LM, Options) :- 2744 '$set_source_module'(OldModule, Module), 2745 '$load_id'(Absolute, Id, Modified, Options), 2746 '$compile_type'(What), 2747 '$save_lex_state'(LexState, Options), 2748 '$set_dialect'(Options), 2749 setup_call_cleanup( 2750 '$start_consult'(Id, Modified), 2751 '$load_file'(Absolute, Id, LM, Options), 2752 '$end_consult'(Id, LexState, OldModule)). 2753 2754'$end_consult'(Id, LexState, OldModule) :- 2755 '$end_consult'(Id), 2756 '$restore_lex_state'(LexState), 2757 '$set_source_module'(OldModule). 2758 2759 2760:- create_prolog_flag(emulated_dialect, swi, [type(atom)]). 2761 2762%! '$save_lex_state'(-LexState, +Options) is det. 2763 2764'$save_lex_state'(State, Options) :- 2765 memberchk(scope_settings(false), Options), 2766 !, 2767 State = (-). 2768'$save_lex_state'(lexstate(Style, Dialect), _) :- 2769 '$style_check'(Style, Style), 2770 current_prolog_flag(emulated_dialect, Dialect). 2771 2772'$restore_lex_state'(-) :- !. 2773'$restore_lex_state'(lexstate(Style, Dialect)) :- 2774 '$style_check'(_, Style), 2775 set_prolog_flag(emulated_dialect, Dialect). 2776 2777'$set_dialect'(Options) :- 2778 memberchk(dialect(Dialect), Options), 2779 !, 2780 '$expects_dialect'(Dialect). 2781'$set_dialect'(_). 2782 2783'$load_id'(stream(Id, _, _), Id, Modified, Options) :- 2784 !, 2785 '$modified_id'(Id, Modified, Options). 2786'$load_id'(Id, Id, Modified, Options) :- 2787 '$modified_id'(Id, Modified, Options). 2788 2789'$modified_id'(_, Modified, Options) :- 2790 '$option'(modified(Stamp), Options, Def), 2791 Stamp \== Def, 2792 !, 2793 Modified = Stamp. 2794'$modified_id'(Id, Modified, _) :- 2795 catch(time_file(Id, Modified), 2796 error(_, _), 2797 fail), 2798 !. 2799'$modified_id'(_, 0.0, _). 2800 2801 2802'$compile_type'(What) :- 2803 '$compilation_mode'(How), 2804 ( How == database 2805 -> What = compiled 2806 ; How == qlf 2807 -> What = '*qcompiled*' 2808 ; What = 'boot compiled' 2809 ). 2810 2811%! '$assert_load_context_module'(+File, -Module, -Options) 2812% 2813% Record the module a file was loaded from (see make/0). The first 2814% clause deals with loading from another file. On reload, this 2815% clause will be discarded by $start_consult/1. The second clause 2816% deals with reload from the toplevel. Here we avoid creating a 2817% duplicate dynamic (i.e., not related to a source) clause. 2818 2819:- dynamic 2820 '$load_context_module'/3. 2821:- multifile 2822 '$load_context_module'/3. 2823 2824'$assert_load_context_module'(_, _, Options) :- 2825 memberchk(register(false), Options), 2826 !. 2827'$assert_load_context_module'(File, Module, Options) :- 2828 source_location(FromFile, Line), 2829 !, 2830 '$master_file'(FromFile, MasterFile), 2831 '$check_load_non_module'(File, Module), 2832 '$add_dialect'(Options, Options1), 2833 '$load_ctx_options'(Options1, Options2), 2834 '$store_admin_clause'( 2835 system:'$load_context_module'(File, Module, Options2), 2836 _Layout, MasterFile, FromFile:Line). 2837'$assert_load_context_module'(File, Module, Options) :- 2838 '$check_load_non_module'(File, Module), 2839 '$add_dialect'(Options, Options1), 2840 '$load_ctx_options'(Options1, Options2), 2841 ( clause('$load_context_module'(File, Module, _), true, Ref), 2842 \+ clause_property(Ref, file(_)), 2843 erase(Ref) 2844 -> true 2845 ; true 2846 ), 2847 assertz('$load_context_module'(File, Module, Options2)). 2848 2849'$add_dialect'(Options0, Options) :- 2850 current_prolog_flag(emulated_dialect, Dialect), Dialect \== swi, 2851 !, 2852 Options = [dialect(Dialect)|Options0]. 2853'$add_dialect'(Options, Options). 2854 2855%! '$load_ctx_options'(+Options, -CtxOptions) is det. 2856% 2857% Select the load options that determine the load semantics to 2858% perform a proper reload. Delete the others. 2859 2860'$load_ctx_options'(Options, CtxOptions) :- 2861 '$load_ctx_options2'(Options, CtxOptions0), 2862 sort(CtxOptions0, CtxOptions). 2863 2864'$load_ctx_options2'([], []). 2865'$load_ctx_options2'([H|T0], [H|T]) :- 2866 '$load_ctx_option'(H), 2867 !, 2868 '$load_ctx_options2'(T0, T). 2869'$load_ctx_options2'([_|T0], T) :- 2870 '$load_ctx_options2'(T0, T). 2871 2872'$load_ctx_option'(derived_from(_)). 2873'$load_ctx_option'(dialect(_)). 2874'$load_ctx_option'(encoding(_)). 2875'$load_ctx_option'(imports(_)). 2876'$load_ctx_option'(reexport(_)). 2877 2878 2879%! '$check_load_non_module'(+File) is det. 2880% 2881% Test that a non-module file is not loaded into multiple 2882% contexts. 2883 2884'$check_load_non_module'(File, _) :- 2885 '$current_module'(_, File), 2886 !. % File is a module file 2887'$check_load_non_module'(File, Module) :- 2888 '$load_context_module'(File, OldModule, _), 2889 Module \== OldModule, 2890 !, 2891 format(atom(Msg), 2892 'Non-module file already loaded into module ~w; \c 2893 trying to load into ~w', 2894 [OldModule, Module]), 2895 throw(error(permission_error(load, source, File), 2896 context(load_files/2, Msg))). 2897'$check_load_non_module'(_, _). 2898 2899%! '$load_file'(+Path, +Id, -Module, +Options) 2900% 2901% '$load_file'/4 does the actual loading. 2902% 2903% state(FirstTerm:boolean, 2904% Module:atom, 2905% AtEnd:atom, 2906% Stop:boolean, 2907% Id:atom, 2908% Dialect:atom) 2909 2910'$load_file'(Path, Id, Module, Options) :- 2911 State = state(true, _, true, false, Id, -), 2912 ( '$source_term'(Path, _Read, _Layout, Term, Layout, 2913 _Stream, Options), 2914 '$valid_term'(Term), 2915 ( arg(1, State, true) 2916 -> '$first_term'(Term, Layout, Id, State, Options), 2917 nb_setarg(1, State, false) 2918 ; '$compile_term'(Term, Layout, Id) 2919 ), 2920 arg(4, State, true) 2921 ; '$fixup_reconsult'(Id), 2922 '$end_load_file'(State) 2923 ), 2924 !, 2925 arg(2, State, Module). 2926 2927'$valid_term'(Var) :- 2928 var(Var), 2929 !, 2930 print_message(error, error(instantiation_error, _)). 2931'$valid_term'(Term) :- 2932 Term \== []. 2933 2934'$end_load_file'(State) :- 2935 arg(1, State, true), % empty file 2936 !, 2937 nb_setarg(2, State, Module), 2938 arg(5, State, Id), 2939 '$current_source_module'(Module), 2940 '$ifcompiling'('$qlf_start_file'(Id)), 2941 '$ifcompiling'('$qlf_end_part'). 2942'$end_load_file'(State) :- 2943 arg(3, State, End), 2944 '$end_load_file'(End, State). 2945 2946'$end_load_file'(true, _). 2947'$end_load_file'(end_module, State) :- 2948 arg(2, State, Module), 2949 '$check_export'(Module), 2950 '$ifcompiling'('$qlf_end_part'). 2951'$end_load_file'(end_non_module, _State) :- 2952 '$ifcompiling'('$qlf_end_part'). 2953 2954 2955'$first_term'(?-(Directive), Layout, Id, State, Options) :- 2956 !, 2957 '$first_term'(:-(Directive), Layout, Id, State, Options). 2958'$first_term'(:-(Directive), _Layout, Id, State, Options) :- 2959 nonvar(Directive), 2960 ( ( Directive = module(Name, Public) 2961 -> Imports = [] 2962 ; Directive = module(Name, Public, Imports) 2963 ) 2964 -> !, 2965 '$module_name'(Name, Id, Module, Options), 2966 '$start_module'(Module, Public, State, Options), 2967 '$module3'(Imports) 2968 ; Directive = expects_dialect(Dialect) 2969 -> !, 2970 '$set_dialect'(Dialect, State), 2971 fail % Still consider next term as first 2972 ). 2973'$first_term'(Term, Layout, Id, State, Options) :- 2974 '$start_non_module'(Id, State, Options), 2975 '$compile_term'(Term, Layout, Id). 2976 2977'$compile_term'(Term, Layout, Id) :- 2978 '$compile_term'(Term, Layout, Id, -). 2979 2980'$compile_term'(Var, _Layout, _Id, _Src) :- 2981 var(Var), 2982 !, 2983 '$instantiation_error'(Var). 2984'$compile_term'((?-Directive), _Layout, Id, _) :- 2985 !, 2986 '$execute_directive'(Directive, Id). 2987'$compile_term'((:-Directive), _Layout, Id, _) :- 2988 !, 2989 '$execute_directive'(Directive, Id). 2990'$compile_term'('$source_location'(File, Line):Term, Layout, Id, _) :- 2991 !, 2992 '$compile_term'(Term, Layout, Id, File:Line). 2993'$compile_term'(Clause, Layout, Id, SrcLoc) :- 2994 E = error(_,_), 2995 catch('$store_clause'(Clause, Layout, Id, SrcLoc), E, 2996 '$print_message'(error, E)). 2997 2998'$start_non_module'(Id, _State, Options) :- 2999 '$option'(must_be_module(true), Options, false), 3000 !, 3001 throw(error(domain_error(module_file, Id), _)). 3002'$start_non_module'(Id, State, _Options) :- 3003 '$current_source_module'(Module), 3004 '$ifcompiling'('$qlf_start_file'(Id)), 3005 '$qset_dialect'(State), 3006 nb_setarg(2, State, Module), 3007 nb_setarg(3, State, end_non_module). 3008 3009%! '$set_dialect'(+Dialect, +State) 3010% 3011% Sets the expected dialect. This is difficult if we are compiling 3012% a .qlf file using qcompile/1 because the file is already open, 3013% while we are looking for the first term to decide wether this is 3014% a module or not. We save the dialect and set it after opening 3015% the file or module. 3016% 3017% Note that expects_dialect/1 itself may be autoloaded from the 3018% library. 3019 3020'$set_dialect'(Dialect, State) :- 3021 '$compilation_mode'(qlf, database), 3022 !, 3023 '$expects_dialect'(Dialect), 3024 '$compilation_mode'(_, qlf), 3025 nb_setarg(6, State, Dialect). 3026'$set_dialect'(Dialect, _) :- 3027 '$expects_dialect'(Dialect). 3028 3029'$qset_dialect'(State) :- 3030 '$compilation_mode'(qlf), 3031 arg(6, State, Dialect), Dialect \== (-), 3032 !, 3033 '$add_directive_wic'('$expects_dialect'(Dialect)). 3034'$qset_dialect'(_). 3035 3036'$expects_dialect'(Dialect) :- 3037 Dialect == swi, 3038 !, 3039 set_prolog_flag(emulated_dialect, Dialect). 3040'$expects_dialect'(Dialect) :- 3041 current_predicate(expects_dialect/1), 3042 !, 3043 expects_dialect(Dialect). 3044'$expects_dialect'(Dialect) :- 3045 use_module(library(dialect), [expects_dialect/1]), 3046 expects_dialect(Dialect). 3047 3048 3049 /******************************* 3050 * MODULES * 3051 *******************************/ 3052 3053'$start_module'(Module, _Public, State, _Options) :- 3054 '$current_module'(Module, OldFile), 3055 source_location(File, _Line), 3056 OldFile \== File, OldFile \== [], 3057 same_file(OldFile, File), 3058 !, 3059 nb_setarg(2, State, Module), 3060 nb_setarg(4, State, true). % Stop processing 3061'$start_module'(Module, Public, State, Options) :- 3062 arg(5, State, File), 3063 nb_setarg(2, State, Module), 3064 source_location(_File, Line), 3065 '$option'(redefine_module(Action), Options, false), 3066 '$module_class'(File, Class, Super), 3067 '$redefine_module'(Module, File, Action), 3068 '$declare_module'(Module, Class, Super, File, Line, false), 3069 '$export_list'(Public, Module, Ops), 3070 '$ifcompiling'('$qlf_start_module'(Module)), 3071 '$export_ops'(Ops, Module, File), 3072 '$qset_dialect'(State), 3073 nb_setarg(3, State, end_module). 3074 3075 3076%! '$module3'(+Spec) is det. 3077% 3078% Handle the 3th argument of a module declartion. 3079 3080'$module3'(Var) :- 3081 var(Var), 3082 !, 3083 '$instantiation_error'(Var). 3084'$module3'([]) :- !. 3085'$module3'([H|T]) :- 3086 !, 3087 '$module3'(H), 3088 '$module3'(T). 3089'$module3'(Id) :- 3090 use_module(library(dialect/Id)). 3091 3092%! '$module_name'(?Name, +Id, -Module, +Options) is semidet. 3093% 3094% Determine the module name. There are some cases: 3095% 3096% - Option module(Module) is given. In that case, use this 3097% module and if Module is the load context, ignore the module 3098% header. 3099% - The initial name is unbound. Use the base name of the 3100% source identifier (normally the file name). Compatibility 3101% to Ciao. This might change; I think it is wiser to use 3102% the full unique source identifier. 3103 3104'$module_name'(_, _, Module, Options) :- 3105 '$option'(module(Module), Options), 3106 !, 3107 '$current_source_module'(Context), 3108 Context \== Module. % cause '$first_term'/5 to fail. 3109'$module_name'(Var, Id, Module, Options) :- 3110 var(Var), 3111 !, 3112 file_base_name(Id, File), 3113 file_name_extension(Var, _, File), 3114 '$module_name'(Var, Id, Module, Options). 3115'$module_name'(Reserved, _, _, _) :- 3116 '$reserved_module'(Reserved), 3117 !, 3118 throw(error(permission_error(load, module, Reserved), _)). 3119'$module_name'(Module, _Id, Module, _). 3120 3121 3122'$reserved_module'(system). 3123'$reserved_module'(user). 3124 3125 3126%! '$redefine_module'(+Module, +File, -Redefine) 3127 3128'$redefine_module'(_Module, _, false) :- !. 3129'$redefine_module'(Module, File, true) :- 3130 !, 3131 ( module_property(Module, file(OldFile)), 3132 File \== OldFile 3133 -> unload_file(OldFile) 3134 ; true 3135 ). 3136'$redefine_module'(Module, File, ask) :- 3137 ( stream_property(user_input, tty(true)), 3138 module_property(Module, file(OldFile)), 3139 File \== OldFile, 3140 '$rdef_response'(Module, OldFile, File, true) 3141 -> '$redefine_module'(Module, File, true) 3142 ; true 3143 ). 3144 3145'$rdef_response'(Module, OldFile, File, Ok) :- 3146 repeat, 3147 print_message(query, redefine_module(Module, OldFile, File)), 3148 get_single_char(Char), 3149 '$rdef_response'(Char, Ok0), 3150 !, 3151 Ok = Ok0. 3152 3153'$rdef_response'(Char, true) :- 3154 memberchk(Char, `yY`), 3155 format(user_error, 'yes~n', []). 3156'$rdef_response'(Char, false) :- 3157 memberchk(Char, `nN`), 3158 format(user_error, 'no~n', []). 3159'$rdef_response'(Char, _) :- 3160 memberchk(Char, `a`), 3161 format(user_error, 'abort~n', []), 3162 abort. 3163'$rdef_response'(_, _) :- 3164 print_message(help, redefine_module_reply), 3165 fail. 3166 3167 3168%! '$module_class'(+File, -Class, -Super) is det. 3169% 3170% Determine the file class and initial module from which File 3171% inherits. All boot and library modules as well as the -F script 3172% files inherit from `system`, while all normal user modules inherit 3173% from `user`. 3174 3175'$module_class'(File, Class, system) :- 3176 current_prolog_flag(home, Home), 3177 sub_atom(File, 0, Len, _, Home), 3178 ( sub_atom(File, Len, _, _, '/boot/') 3179 -> Class = system 3180 ; '$lib_prefix'(Prefix), 3181 sub_atom(File, Len, _, _, Prefix) 3182 -> Class = library 3183 ; file_directory_name(File, Home), 3184 file_name_extension(_, rc, File) 3185 -> Class = library 3186 ), 3187 !. 3188'$module_class'(_, user, user). 3189 3190'$lib_prefix'('/library'). 3191'$lib_prefix'('/xpce/prolog/'). 3192 3193'$check_export'(Module) :- 3194 '$undefined_export'(Module, UndefList), 3195 ( '$member'(Undef, UndefList), 3196 strip_module(Undef, _, Local), 3197 print_message(error, 3198 undefined_export(Module, Local)), 3199 fail 3200 ; true 3201 ). 3202 3203 3204%! '$import_list'(+TargetModule, +FromModule, +Import, +Reexport) is det. 3205% 3206% Import from FromModule to TargetModule. Import is one of =all=, 3207% a list of optionally mapped predicate indicators or a term 3208% except(Import). 3209 3210'$import_list'(_, _, Var, _) :- 3211 var(Var), 3212 !, 3213 throw(error(instantitation_error, _)). 3214'$import_list'(Target, Source, all, Reexport) :- 3215 !, 3216 '$exported_ops'(Source, Import, Predicates), 3217 '$module_property'(Source, exports(Predicates)), 3218 '$import_all'(Import, Target, Source, Reexport, weak). 3219'$import_list'(Target, Source, except(Spec), Reexport) :- 3220 !, 3221 '$exported_ops'(Source, Export, Predicates), 3222 '$module_property'(Source, exports(Predicates)), 3223 ( is_list(Spec) 3224 -> true 3225 ; throw(error(type_error(list, Spec), _)) 3226 ), 3227 '$import_except'(Spec, Export, Import), 3228 '$import_all'(Import, Target, Source, Reexport, weak). 3229'$import_list'(Target, Source, Import, Reexport) :- 3230 !, 3231 is_list(Import), 3232 !, 3233 '$import_all'(Import, Target, Source, Reexport, strong). 3234'$import_list'(_, _, Import, _) :- 3235 throw(error(type_error(import_specifier, Import))). 3236 3237 3238'$import_except'([], List, List). 3239'$import_except'([H|T], List0, List) :- 3240 '$import_except_1'(H, List0, List1), 3241 '$import_except'(T, List1, List). 3242 3243'$import_except_1'(Var, _, _) :- 3244 var(Var), 3245 !, 3246 throw(error(instantitation_error, _)). 3247'$import_except_1'(PI as N, List0, List) :- 3248 '$pi'(PI), atom(N), 3249 !, 3250 '$canonical_pi'(PI, CPI), 3251 '$import_as'(CPI, N, List0, List). 3252'$import_except_1'(op(P,A,N), List0, List) :- 3253 !, 3254 '$remove_ops'(List0, op(P,A,N), List). 3255'$import_except_1'(PI, List0, List) :- 3256 '$pi'(PI), 3257 !, 3258 '$canonical_pi'(PI, CPI), 3259 '$select'(P, List0, List), 3260 '$canonical_pi'(CPI, P), 3261 !. 3262'$import_except_1'(Except, _, _) :- 3263 throw(error(type_error(import_specifier, Except), _)). 3264 3265'$import_as'(CPI, N, [PI2|T], [CPI as N|T]) :- 3266 '$canonical_pi'(PI2, CPI), 3267 !. 3268'$import_as'(PI, N, [H|T0], [H|T]) :- 3269 !, 3270 '$import_as'(PI, N, T0, T). 3271'$import_as'(PI, _, _, _) :- 3272 throw(error(existence_error(export, PI), _)). 3273 3274'$pi'(N/A) :- atom(N), integer(A), !. 3275'$pi'(N//A) :- atom(N), integer(A). 3276 3277'$canonical_pi'(N//A0, N/A) :- 3278 A is A0 + 2. 3279'$canonical_pi'(PI, PI). 3280 3281'$remove_ops'([], _, []). 3282'$remove_ops'([Op|T0], Pattern, T) :- 3283 subsumes_term(Pattern, Op), 3284 !, 3285 '$remove_ops'(T0, Pattern, T). 3286'$remove_ops'([H|T0], Pattern, [H|T]) :- 3287 '$remove_ops'(T0, Pattern, T). 3288 3289 3290%! '$import_all'(+Import, +Context, +Source, +Reexport, +Strength) 3291 3292'$import_all'(Import, Context, Source, Reexport, Strength) :- 3293 '$import_all2'(Import, Context, Source, Imported, ImpOps, Strength), 3294 ( Reexport == true, 3295 ( '$list_to_conj'(Imported, Conj) 3296 -> export(Context:Conj), 3297 '$ifcompiling'('$add_directive_wic'(export(Context:Conj))) 3298 ; true 3299 ), 3300 source_location(File, _Line), 3301 '$export_ops'(ImpOps, Context, File) 3302 ; true 3303 ). 3304 3305%! '$import_all2'(+Imports, +Context, +Source, -Imported, -ImpOps, +Strength) 3306 3307'$import_all2'([], _, _, [], [], _). 3308'$import_all2'([PI as NewName|Rest], Context, Source, 3309 [NewName/Arity|Imported], ImpOps, Strength) :- 3310 !, 3311 '$canonical_pi'(PI, Name/Arity), 3312 length(Args, Arity), 3313 Head =.. [Name|Args], 3314 NewHead =.. [NewName|Args], 3315 ( '$get_predicate_attribute'(Source:Head, transparent, 1) 3316 -> '$set_predicate_attribute'(Context:NewHead, transparent, true) 3317 ; true 3318 ), 3319 ( source_location(File, Line) 3320 -> E = error(_,_), 3321 catch('$store_admin_clause'((NewHead :- Source:Head), 3322 _Layout, File, File:Line), 3323 E, '$print_message'(error, E)) 3324 ; assertz((NewHead :- !, Source:Head)) % ! avoids problems with 3325 ), % duplicate load 3326 '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength). 3327'$import_all2'([op(P,A,N)|Rest], Context, Source, Imported, 3328 [op(P,A,N)|ImpOps], Strength) :- 3329 !, 3330 '$import_ops'(Context, Source, op(P,A,N)), 3331 '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength). 3332'$import_all2'([Pred|Rest], Context, Source, [Pred|Imported], ImpOps, Strength) :- 3333 Error = error(_,_), 3334 catch(Context:'$import'(Source:Pred, Strength), Error, 3335 print_message(error, Error)), 3336 '$ifcompiling'('$import_wic'(Source, Pred, Strength)), 3337 '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength). 3338 3339 3340'$list_to_conj'([One], One) :- !. 3341'$list_to_conj'([H|T], (H,Rest)) :- 3342 '$list_to_conj'(T, Rest). 3343 3344%! '$exported_ops'(+Module, -Ops, ?Tail) is det. 3345% 3346% Ops is a list of op(P,A,N) terms representing the operators 3347% exported from Module. 3348 3349'$exported_ops'(Module, Ops, Tail) :- 3350 '$c_current_predicate'(_, Module:'$exported_op'(_,_,_)), 3351 !, 3352 findall(op(P,A,N), Module:'$exported_op'(P,A,N), Ops, Tail). 3353'$exported_ops'(_, Ops, Ops). 3354 3355'$exported_op'(Module, P, A, N) :- 3356 '$c_current_predicate'(_, Module:'$exported_op'(_,_,_)), 3357 Module:'$exported_op'(P, A, N). 3358 3359%! '$import_ops'(+Target, +Source, +Pattern) 3360% 3361% Import the operators export from Source into the module table of 3362% Target. We only import operators that unify with Pattern. 3363 3364'$import_ops'(To, From, Pattern) :- 3365 ground(Pattern), 3366 !, 3367 Pattern = op(P,A,N), 3368 op(P,A,To:N), 3369 ( '$exported_op'(From, P, A, N) 3370 -> true 3371 ; print_message(warning, no_exported_op(From, Pattern)) 3372 ). 3373'$import_ops'(To, From, Pattern) :- 3374 ( '$exported_op'(From, Pri, Assoc, Name), 3375 Pattern = op(Pri, Assoc, Name), 3376 op(Pri, Assoc, To:Name), 3377 fail 3378 ; true 3379 ). 3380 3381 3382%! '$export_list'(+Declarations, +Module, -Ops) 3383% 3384% Handle the export list of the module declaration for Module 3385% associated to File. 3386 3387'$export_list'(Decls, Module, Ops) :- 3388 is_list(Decls), 3389 !, 3390 '$do_export_list'(Decls, Module, Ops). 3391'$export_list'(Decls, _, _) :- 3392 var(Decls), 3393 throw(error(instantiation_error, _)). 3394'$export_list'(Decls, _, _) :- 3395 throw(error(type_error(list, Decls), _)). 3396 3397'$do_export_list'([], _, []) :- !. 3398'$do_export_list'([H|T], Module, Ops) :- 3399 !, 3400 E = error(_,_), 3401 catch('$export1'(H, Module, Ops, Ops1), 3402 E, ('$print_message'(error, E), Ops = Ops1)), 3403 '$do_export_list'(T, Module, Ops1). 3404 3405'$export1'(Var, _, _, _) :- 3406 var(Var), 3407 !, 3408 throw(error(instantiation_error, _)). 3409'$export1'(Op, _, [Op|T], T) :- 3410 Op = op(_,_,_), 3411 !. 3412'$export1'(PI0, Module, Ops, Ops) :- 3413 strip_module(Module:PI0, M, PI), 3414 ( PI = (_//_) 3415 -> non_terminal(M:PI) 3416 ; true 3417 ), 3418 export(M:PI). 3419 3420'$export_ops'([op(Pri, Assoc, Name)|T], Module, File) :- 3421 E = error(_,_), 3422 catch(( '$execute_directive'(op(Pri, Assoc, Module:Name), File), 3423 '$export_op'(Pri, Assoc, Name, Module, File) 3424 ), 3425 E, '$print_message'(error, E)), 3426 '$export_ops'(T, Module, File). 3427'$export_ops'([], _, _). 3428 3429'$export_op'(Pri, Assoc, Name, Module, File) :- 3430 ( '$get_predicate_attribute'(Module:'$exported_op'(_,_,_), defined, 1) 3431 -> true 3432 ; '$execute_directive'(discontiguous(Module:'$exported_op'/3), File) 3433 ), 3434 '$store_admin_clause'('$exported_op'(Pri, Assoc, Name), _Layout, File, -). 3435 3436%! '$execute_directive'(:Goal, +File) is det. 3437% 3438% Execute the argument of :- or ?- while loading a file. 3439 3440'$execute_directive'(Goal, F) :- 3441 '$execute_directive_2'(Goal, F). 3442 3443'$execute_directive_2'(encoding(Encoding), _F) :- 3444 !, 3445 ( '$load_input'(_F, S) 3446 -> set_stream(S, encoding(Encoding)) 3447 ). 3448'$execute_directive_2'(Goal, _) :- 3449 \+ '$compilation_mode'(database), 3450 !, 3451 '$add_directive_wic2'(Goal, Type), 3452 ( Type == call % suspend compiling into .qlf file 3453 -> '$compilation_mode'(Old, database), 3454 setup_call_cleanup( 3455 '$directive_mode'(OldDir, Old), 3456 '$execute_directive_3'(Goal), 3457 ( '$set_compilation_mode'(Old), 3458 '$set_directive_mode'(OldDir) 3459 )) 3460 ; '$execute_directive_3'(Goal) 3461 ). 3462'$execute_directive_2'(Goal, _) :- 3463 '$execute_directive_3'(Goal). 3464 3465'$execute_directive_3'(Goal) :- 3466 '$current_source_module'(Module), 3467 '$valid_directive'(Module:Goal), 3468 !, 3469 ( '$pattr_directive'(Goal, Module) 3470 -> true 3471 ; Term = error(_,_), 3472 catch(Module:Goal, Term, '$exception_in_directive'(Term)) 3473 -> true 3474 ; '$print_message'(warning, goal_failed(directive, Module:Goal)), 3475 fail 3476 ). 3477'$execute_directive_3'(_). 3478 3479 3480%! '$valid_directive'(:Directive) is det. 3481% 3482% If the flag =sandboxed_load= is =true=, this calls 3483% prolog:sandbox_allowed_directive/1. This call can deny execution 3484% of the directive by throwing an exception. 3485 3486:- multifile prolog:sandbox_allowed_directive/1. 3487:- multifile prolog:sandbox_allowed_clause/1. 3488:- meta_predicate '$valid_directive'(:). 3489 3490'$valid_directive'(_) :- 3491 current_prolog_flag(sandboxed_load, false), 3492 !. 3493'$valid_directive'(Goal) :- 3494 Error = error(Formal, _), 3495 catch(prolog:sandbox_allowed_directive(Goal), Error, true), 3496 !, 3497 ( var(Formal) 3498 -> true 3499 ; print_message(error, Error), 3500 fail 3501 ). 3502'$valid_directive'(Goal) :- 3503 print_message(error, 3504 error(permission_error(execute, 3505 sandboxed_directive, 3506 Goal), _)), 3507 fail. 3508 3509'$exception_in_directive'(Term) :- 3510 '$print_message'(error, Term), 3511 fail. 3512 3513% Note that the list, consult and ensure_loaded directives are already 3514% handled at compile time and therefore should not go into the 3515% intermediate code file. 3516 3517'$add_directive_wic2'(Goal, Type) :- 3518 '$common_goal_type'(Goal, Type), 3519 !, 3520 ( Type == load 3521 -> true 3522 ; '$current_source_module'(Module), 3523 '$add_directive_wic'(Module:Goal) 3524 ). 3525'$add_directive_wic2'(Goal, _) :- 3526 ( '$compilation_mode'(qlf) % no problem for qlf files 3527 -> true 3528 ; print_message(error, mixed_directive(Goal)) 3529 ). 3530 3531'$common_goal_type'((A,B), Type) :- 3532 !, 3533 '$common_goal_type'(A, Type), 3534 '$common_goal_type'(B, Type). 3535'$common_goal_type'((A;B), Type) :- 3536 !, 3537 '$common_goal_type'(A, Type), 3538 '$common_goal_type'(B, Type). 3539'$common_goal_type'((A->B), Type) :- 3540 !, 3541 '$common_goal_type'(A, Type), 3542 '$common_goal_type'(B, Type). 3543'$common_goal_type'(Goal, Type) :- 3544 '$goal_type'(Goal, Type). 3545 3546'$goal_type'(Goal, Type) :- 3547 ( '$load_goal'(Goal) 3548 -> Type = load 3549 ; Type = call 3550 ). 3551 3552'$load_goal'([_|_]). 3553'$load_goal'(consult(_)). 3554'$load_goal'(load_files(_)). 3555'$load_goal'(load_files(_,Options)) :- 3556 memberchk(qcompile(QlfMode), Options), 3557 '$qlf_part_mode'(QlfMode). 3558'$load_goal'(ensure_loaded(_)) :- '$compilation_mode'(wic). 3559'$load_goal'(use_module(_)) :- '$compilation_mode'(wic). 3560'$load_goal'(use_module(_, _)) :- '$compilation_mode'(wic). 3561 3562'$qlf_part_mode'(part). 3563'$qlf_part_mode'(true). % compatibility 3564 3565 3566 /******************************** 3567 * COMPILE A CLAUSE * 3568 *********************************/ 3569 3570%! '$store_admin_clause'(+Clause, ?Layout, +Owner, +SrcLoc) is det. 3571% 3572% Store a clause into the database for administrative purposes. 3573% This bypasses sanity checking. 3574 3575'$store_admin_clause'(Clause, Layout, Owner, SrcLoc) :- 3576 Owner \== (-), 3577 !, 3578 setup_call_cleanup( 3579 '$start_aux'(Owner, Context), 3580 '$store_admin_clause2'(Clause, Layout, Owner, SrcLoc), 3581 '$end_aux'(Owner, Context)). 3582'$store_admin_clause'(Clause, Layout, File, SrcLoc) :- 3583 '$store_admin_clause2'(Clause, Layout, File, SrcLoc). 3584 3585'$store_admin_clause2'(Clause, _Layout, File, SrcLoc) :- 3586 ( '$compilation_mode'(database) 3587 -> '$record_clause'(Clause, File, SrcLoc) 3588 ; '$record_clause'(Clause, File, SrcLoc, Ref), 3589 '$qlf_assert_clause'(Ref, development) 3590 ). 3591 3592%! '$store_clause'(+Clause, ?Layout, +Owner, +SrcLoc) is det. 3593% 3594% Store a clause into the database. 3595% 3596% @arg Owner is the file-id that owns the clause 3597% @arg SrcLoc is the file:line term where the clause 3598% originates from. 3599 3600'$store_clause'((_, _), _, _, _) :- 3601 !, 3602 print_message(error, cannot_redefine_comma), 3603 fail. 3604'$store_clause'(Clause, _Layout, File, SrcLoc) :- 3605 '$valid_clause'(Clause), 3606 !, 3607 ( '$compilation_mode'(database) 3608 -> '$record_clause'(Clause, File, SrcLoc) 3609 ; '$record_clause'(Clause, File, SrcLoc, Ref), 3610 '$qlf_assert_clause'(Ref, development) 3611 ). 3612 3613'$valid_clause'(_) :- 3614 current_prolog_flag(sandboxed_load, false), 3615 !. 3616'$valid_clause'(Clause) :- 3617 \+ '$cross_module_clause'(Clause), 3618 !. 3619'$valid_clause'(Clause) :- 3620 Error = error(Formal, _), 3621 catch(prolog:sandbox_allowed_clause(Clause), Error, true), 3622 !, 3623 ( var(Formal) 3624 -> true 3625 ; print_message(error, Error), 3626 fail 3627 ). 3628'$valid_clause'(Clause) :- 3629 print_message(error, 3630 error(permission_error(assert, 3631 sandboxed_clause, 3632 Clause), _)), 3633 fail. 3634 3635'$cross_module_clause'(Clause) :- 3636 '$head_module'(Clause, Module), 3637 \+ '$current_source_module'(Module). 3638 3639'$head_module'(Var, _) :- 3640 var(Var), !, fail. 3641'$head_module'((Head :- _), Module) :- 3642 '$head_module'(Head, Module). 3643'$head_module'(Module:_, Module). 3644 3645'$clause_source'('$source_location'(File,Line):Clause, Clause, File:Line) :- !. 3646'$clause_source'(Clause, Clause, -). 3647 3648%! '$store_clause'(+Term, +Id) is det. 3649% 3650% This interface is used by PlDoc (and who knows). Kept for to avoid 3651% compatibility issues. 3652 3653:- public 3654 '$store_clause'/2. 3655 3656'$store_clause'(Term, Id) :- 3657 '$clause_source'(Term, Clause, SrcLoc), 3658 '$store_clause'(Clause, _, Id, SrcLoc). 3659 3660%! compile_aux_clauses(+Clauses) is det. 3661% 3662% Compile clauses given the current source location but do not 3663% change the notion of the current procedure such that 3664% discontiguous warnings are not issued. The clauses are 3665% associated with the current file and therefore wiped out if the 3666% file is reloaded. 3667% 3668% If the cross-referencer is active, we should not (re-)assert the 3669% clauses. Actually, we should make them known to the 3670% cross-referencer. How do we do that? Maybe we need a different 3671% API, such as in: 3672% 3673% == 3674% expand_term_aux(Goal, NewGoal, Clauses) 3675% == 3676% 3677% @tbd Deal with source code layout? 3678 3679compile_aux_clauses(_Clauses) :- 3680 current_prolog_flag(xref, true), 3681 !. 3682compile_aux_clauses(Clauses) :- 3683 source_location(File, _Line), 3684 '$compile_aux_clauses'(Clauses, File). 3685 3686'$compile_aux_clauses'(Clauses, File) :- 3687 setup_call_cleanup( 3688 '$start_aux'(File, Context), 3689 '$store_aux_clauses'(Clauses, File), 3690 '$end_aux'(File, Context)). 3691 3692'$store_aux_clauses'(Clauses, File) :- 3693 is_list(Clauses), 3694 !, 3695 forall('$member'(C,Clauses), 3696 '$compile_term'(C, _Layout, File)). 3697'$store_aux_clauses'(Clause, File) :- 3698 '$compile_term'(Clause, _Layout, File). 3699 3700 3701 /******************************* 3702 * STAGING * 3703 *******************************/ 3704 3705%! '$stage_file'(+Target, -Stage) is det. 3706%! '$install_staged_file'(+Catcher, +Staged, +Target, +OnError). 3707% 3708% Create files using _staging_, where we first write a temporary file 3709% and move it to Target if the file was created successfully. This 3710% provides an atomic transition, preventing customers from reading an 3711% incomplete file. 3712 3713'$stage_file'(Target, Stage) :- 3714 file_directory_name(Target, Dir), 3715 file_base_name(Target, File), 3716 current_prolog_flag(pid, Pid), 3717 format(atom(Stage), '~w/.~w.~d', [Dir,File,Pid]). 3718 3719'$install_staged_file'(exit, Staged, Target, error) :- 3720 !, 3721 rename_file(Staged, Target). 3722'$install_staged_file'(exit, Staged, Target, OnError) :- 3723 !, 3724 InstallError = error(_,_), 3725 catch(rename_file(Staged, Target), 3726 InstallError, 3727 '$install_staged_error'(OnError, InstallError, Staged, Target)). 3728'$install_staged_file'(_, Staged, _, _OnError) :- 3729 E = error(_,_), 3730 catch(delete_file(Staged), E, true). 3731 3732'$install_staged_error'(OnError, Error, Staged, _Target) :- 3733 E = error(_,_), 3734 catch(delete_file(Staged), E, true), 3735 ( OnError = silent 3736 -> true 3737 ; OnError = fail 3738 -> fail 3739 ; print_message(warning, Error) 3740 ). 3741 3742 3743 /******************************* 3744 * READING * 3745 *******************************/ 3746 3747:- multifile 3748 prolog:comment_hook/3. % hook for read_clause/3 3749 3750 3751 /******************************* 3752 * FOREIGN INTERFACE * 3753 *******************************/ 3754 3755% call-back from PL_register_foreign(). First argument is the module 3756% into which the foreign predicate is loaded and second is a term 3757% describing the arguments. 3758 3759:- dynamic 3760 '$foreign_registered'/2. 3761 3762 /******************************* 3763 * TEMPORARY TERM EXPANSION * 3764 *******************************/ 3765 3766% Provide temporary definitions for the boot-loader. These are replaced 3767% by the real thing in load.pl 3768 3769:- dynamic 3770 '$expand_goal'/2, 3771 '$expand_term'/4. 3772 3773'$expand_goal'(In, In). 3774'$expand_term'(In, Layout, In, Layout). 3775 3776 3777 /******************************* 3778 * TYPE SUPPORT * 3779 *******************************/ 3780 3781'$type_error'(Type, Value) :- 3782 ( var(Value) 3783 -> throw(error(instantiation_error, _)) 3784 ; throw(error(type_error(Type, Value), _)) 3785 ). 3786 3787'$domain_error'(Type, Value) :- 3788 throw(error(domain_error(Type, Value), _)). 3789 3790'$existence_error'(Type, Object) :- 3791 throw(error(existence_error(Type, Object), _)). 3792 3793'$permission_error'(Action, Type, Term) :- 3794 throw(error(permission_error(Action, Type, Term), _)). 3795 3796'$instantiation_error'(_Var) :- 3797 throw(error(instantiation_error, _)). 3798 3799'$uninstantiation_error'(NonVar) :- 3800 throw(error(uninstantiation_error(NonVar), _)). 3801 3802'$must_be'(list, X) :- !, 3803 '$skip_list'(_, X, Tail), 3804 ( Tail == [] 3805 -> true 3806 ; '$type_error'(list, Tail) 3807 ). 3808'$must_be'(options, X) :- !, 3809 ( '$is_options'(X) 3810 -> true 3811 ; '$type_error'(options, X) 3812 ). 3813'$must_be'(atom, X) :- !, 3814 ( atom(X) 3815 -> true 3816 ; '$type_error'(atom, X) 3817 ). 3818'$must_be'(integer, X) :- !, 3819 ( integer(X) 3820 -> true 3821 ; '$type_error'(integer, X) 3822 ). 3823'$must_be'(between(Low,High), X) :- !, 3824 ( integer(X) 3825 -> ( between(Low, High, X) 3826 -> true 3827 ; '$domain_error'(between(Low,High), X) 3828 ) 3829 ; '$type_error'(integer, X) 3830 ). 3831'$must_be'(callable, X) :- !, 3832 ( callable(X) 3833 -> true 3834 ; '$type_error'(callable, X) 3835 ). 3836'$must_be'(acyclic, X) :- !, 3837 ( acyclic_term(X) 3838 -> true 3839 ; '$domain_error'(acyclic_term, X) 3840 ). 3841'$must_be'(oneof(Type, Domain, List), X) :- !, 3842 '$must_be'(Type, X), 3843 ( memberchk(X, List) 3844 -> true 3845 ; '$domain_error'(Domain, X) 3846 ). 3847'$must_be'(boolean, X) :- !, 3848 ( (X == true ; X == false) 3849 -> true 3850 ; '$type_error'(boolean, X) 3851 ). 3852'$must_be'(ground, X) :- !, 3853 ( ground(X) 3854 -> true 3855 ; '$instantiation_error'(X) 3856 ). 3857'$must_be'(filespec, X) :- !, 3858 ( ( atom(X) 3859 ; string(X) 3860 ; compound(X), 3861 compound_name_arity(X, _, 1) 3862 ) 3863 -> true 3864 ; '$type_error'(filespec, X) 3865 ). 3866 3867% Use for debugging 3868%'$must_be'(Type, _X) :- format('Unknown $must_be type: ~q~n', [Type]). 3869 3870 3871 /******************************** 3872 * LIST PROCESSING * 3873 *********************************/ 3874 3875'$member'(El, [H|T]) :- 3876 '$member_'(T, El, H). 3877 3878'$member_'(_, El, El). 3879'$member_'([H|T], El, _) :- 3880 '$member_'(T, El, H). 3881 3882 3883'$append'([], L, L). 3884'$append'([H|T], L, [H|R]) :- 3885 '$append'(T, L, R). 3886 3887'$select'(X, [X|Tail], Tail). 3888'$select'(Elem, [Head|Tail], [Head|Rest]) :- 3889 '$select'(Elem, Tail, Rest). 3890 3891'$reverse'(L1, L2) :- 3892 '$reverse'(L1, [], L2). 3893 3894'$reverse'([], List, List). 3895'$reverse'([Head|List1], List2, List3) :- 3896 '$reverse'(List1, [Head|List2], List3). 3897 3898'$delete'([], _, []) :- !. 3899'$delete'([Elem|Tail], Elem, Result) :- 3900 !, 3901 '$delete'(Tail, Elem, Result). 3902'$delete'([Head|Tail], Elem, [Head|Rest]) :- 3903 '$delete'(Tail, Elem, Rest). 3904 3905'$last'([H|T], Last) :- 3906 '$last'(T, H, Last). 3907 3908'$last'([], Last, Last). 3909'$last'([H|T], _, Last) :- 3910 '$last'(T, H, Last). 3911 3912 3913%! length(?List, ?N) 3914% 3915% Is true when N is the length of List. 3916 3917:- '$iso'((length/2)). 3918 3919length(List, Length) :- 3920 var(Length), 3921 !, 3922 '$skip_list'(Length0, List, Tail), 3923 ( Tail == [] 3924 -> Length = Length0 % +,- 3925 ; var(Tail) 3926 -> Tail \== Length, % avoid length(L,L) 3927 '$length3'(Tail, Length, Length0) % -,- 3928 ; throw(error(type_error(list, List), 3929 context(length/2, _))) 3930 ). 3931length(List, Length) :- 3932 integer(Length), 3933 Length >= 0, 3934 !, 3935 '$skip_list'(Length0, List, Tail), 3936 ( Tail == [] % proper list 3937 -> Length = Length0 3938 ; var(Tail) 3939 -> Extra is Length-Length0, 3940 '$length'(Tail, Extra) 3941 ; throw(error(type_error(list, List), 3942 context(length/2, _))) 3943 ). 3944length(_, Length) :- 3945 integer(Length), 3946 !, 3947 throw(error(domain_error(not_less_than_zero, Length), 3948 context(length/2, _))). 3949length(_, Length) :- 3950 throw(error(type_error(integer, Length), 3951 context(length/2, _))). 3952 3953'$length3'([], N, N). 3954'$length3'([_|List], N, N0) :- 3955 N1 is N0+1, 3956 '$length3'(List, N, N1). 3957 3958 3959 /******************************* 3960 * OPTION PROCESSING * 3961 *******************************/ 3962 3963%! '$is_options'(@Term) is semidet. 3964% 3965% True if Term looks like it provides options. 3966 3967'$is_options'(Map) :- 3968 is_dict(Map, _), 3969 !. 3970'$is_options'(List) :- 3971 is_list(List), 3972 ( List == [] 3973 -> true 3974 ; List = [H|_], 3975 '$is_option'(H, _, _) 3976 ). 3977 3978'$is_option'(Var, _, _) :- 3979 var(Var), !, fail. 3980'$is_option'(F, Name, Value) :- 3981 functor(F, _, 1), 3982 !, 3983 F =.. [Name,Value]. 3984'$is_option'(Name=Value, Name, Value). 3985 3986%! '$option'(?Opt, +Options) is semidet. 3987 3988'$option'(Opt, Options) :- 3989 is_dict(Options), 3990 !, 3991 [Opt] :< Options. 3992'$option'(Opt, Options) :- 3993 memberchk(Opt, Options). 3994 3995%! '$option'(?Opt, +Options, +Default) is det. 3996 3997'$option'(Term, Options, Default) :- 3998 arg(1, Term, Value), 3999 functor(Term, Name, 1), 4000 ( is_dict(Options) 4001 -> ( get_dict(Name, Options, GVal) 4002 -> Value = GVal 4003 ; Value = Default 4004 ) 4005 ; functor(Gen, Name, 1), 4006 arg(1, Gen, GVal), 4007 ( memberchk(Gen, Options) 4008 -> Value = GVal 4009 ; Value = Default 4010 ) 4011 ). 4012 4013%! '$select_option'(?Opt, +Options, -Rest) is semidet. 4014% 4015% Select an option from Options. 4016% 4017% @arg Rest is always a map. 4018 4019'$select_option'(Opt, Options, Rest) :- 4020 select_dict([Opt], Options, Rest). 4021 4022%! '$merge_options'(+New, +Default, -Merged) is det. 4023% 4024% Add/replace options specified in New. 4025% 4026% @arg Merged is always a map. 4027 4028'$merge_options'(New, Old, Merged) :- 4029 put_dict(New, Old, Merged). 4030 4031 4032 /******************************* 4033 * HANDLE TRACER 'L'-COMMAND * 4034 *******************************/ 4035 4036:- public '$prolog_list_goal'/1. 4037 4038:- multifile 4039 user:prolog_list_goal/1. 4040 4041'$prolog_list_goal'(Goal) :- 4042 user:prolog_list_goal(Goal), 4043 !. 4044'$prolog_list_goal'(Goal) :- 4045 use_module(library(listing), [listing/1]), 4046 @(listing(Goal), user). 4047 4048 4049 /******************************* 4050 * HALT * 4051 *******************************/ 4052 4053:- '$iso'((halt/0)). 4054 4055halt :- 4056 halt(0). 4057 4058 4059%! at_halt(:Goal) 4060% 4061% Register Goal to be called if the system halts. 4062% 4063% @tbd: get location into the error message 4064 4065:- meta_predicate at_halt(0). 4066:- dynamic system:term_expansion/2, '$at_halt'/2. 4067:- multifile system:term_expansion/2, '$at_halt'/2. 4068 4069system:term_expansion((:- at_halt(Goal)), 4070 system:'$at_halt'(Module:Goal, File:Line)) :- 4071 \+ current_prolog_flag(xref, true), 4072 source_location(File, Line), 4073 '$current_source_module'(Module). 4074 4075at_halt(Goal) :- 4076 asserta('$at_halt'(Goal, (-):0)). 4077 4078:- public '$run_at_halt'/0. 4079 4080'$run_at_halt' :- 4081 forall(clause('$at_halt'(Goal, Src), true, Ref), 4082 ( '$call_at_halt'(Goal, Src), 4083 erase(Ref) 4084 )). 4085 4086'$call_at_halt'(Goal, _Src) :- 4087 catch(Goal, E, true), 4088 !, 4089 ( var(E) 4090 -> true 4091 ; subsumes_term(cancel_halt(_), E) 4092 -> '$print_message'(informational, E), 4093 fail 4094 ; '$print_message'(error, E) 4095 ). 4096'$call_at_halt'(Goal, _Src) :- 4097 '$print_message'(warning, goal_failed(at_halt, Goal)). 4098 4099%! cancel_halt(+Reason) 4100% 4101% This predicate may be called from at_halt/1 handlers to cancel 4102% halting the program. If causes halt/0 to fail rather than 4103% terminating the process. 4104 4105cancel_halt(Reason) :- 4106 throw(cancel_halt(Reason)). 4107 4108 4109 /******************************** 4110 * LOAD OTHER MODULES * 4111 *********************************/ 4112 4113:- meta_predicate 4114 '$load_wic_files'(:). 4115 4116'$load_wic_files'(Files) :- 4117 Files = Module:_, 4118 '$execute_directive'('$set_source_module'(OldM, Module), []), 4119 '$save_lex_state'(LexState, []), 4120 '$style_check'(_, 0xC7), % see style_name/2 in syspred.pl 4121 '$compilation_mode'(OldC, wic), 4122 consult(Files), 4123 '$execute_directive'('$set_source_module'(OldM), []), 4124 '$execute_directive'('$restore_lex_state'(LexState), []), 4125 '$set_compilation_mode'(OldC). 4126 4127 4128%! '$load_additional_boot_files' is det. 4129% 4130% Called from compileFileList() in pl-wic.c. Gets the files from 4131% "-c file ..." and loads them into the module user. 4132 4133:- public '$load_additional_boot_files'/0. 4134 4135'$load_additional_boot_files' :- 4136 current_prolog_flag(argv, Argv), 4137 '$get_files_argv'(Argv, Files), 4138 ( Files \== [] 4139 -> format('Loading additional boot files~n'), 4140 '$load_wic_files'(user:Files), 4141 format('additional boot files loaded~n') 4142 ; true 4143 ). 4144 4145'$get_files_argv'([], []) :- !. 4146'$get_files_argv'(['-c'|Files], Files) :- !. 4147'$get_files_argv'([_|Rest], Files) :- 4148 '$get_files_argv'(Rest, Files). 4149 4150'$:-'(('$boot_message'('Loading Prolog startup files~n', []), 4151 source_location(File, _Line), 4152 file_directory_name(File, Dir), 4153 atom_concat(Dir, '/load.pl', LoadFile), 4154 '$load_wic_files'(system:[LoadFile]), 4155 ( current_prolog_flag(windows, true) 4156 -> atom_concat(Dir, '/menu.pl', MenuFile), 4157 '$load_wic_files'(system:[MenuFile]) 4158 ; true 4159 ), 4160 '$boot_message'('SWI-Prolog boot files loaded~n', []), 4161 '$compilation_mode'(OldC, wic), 4162 '$execute_directive'('$set_source_module'(user), []), 4163 '$set_compilation_mode'(OldC) 4164 )). 4165