module fixes plus add better docs
This commit is contained in:
parent
dbff20343a
commit
ce8a4b6958
10
C/eval.c
10
C/eval.c
@ -542,12 +542,6 @@ init_between( USES_REGS1 )
|
||||
return cont_between( PASS_REGS1 );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
void
|
||||
Yap_InitEval(void)
|
||||
{
|
||||
@ -562,3 +556,7 @@ Yap_InitEval(void)
|
||||
Yap_InitCPredBack("between", 3, 2, init_between, cont_between, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
@ -776,11 +776,13 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = /Users/vsc/git/yap-6.3/pl/modules.yap
|
||||
# INPUT = /Users/vsc/git/yap-6.3/pl/absf.yap
|
||||
# INPUT = /Users/vsc/git/yap-6.3/packages/ProbLog/problog_learning_lbdd.yap
|
||||
# INPUT = /Users/vsc/git/yap-6.3/packages/cplint/mcintyre.pl
|
||||
#INPUT = /Users/vsc/git/yap-6.3/packages/R/R.pl
|
||||
|
||||
INPUT = docs/yap.md \
|
||||
INPUTX = docs/yap.md \
|
||||
pl \
|
||||
C \
|
||||
H \
|
||||
@ -868,7 +870,7 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = *pltotex.pl
|
||||
EXCLUDE = *pltotex.pl packages/swig/android
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
|
316
docs/yap.md
316
docs/yap.md
@ -11,7 +11,9 @@ This file documents the YAP Prolog System version 6.3.4, a high-performance Prol
|
||||
|
||||
+ @subpage Loading_Programs presents the main predicates and
|
||||
directives available to load files and to control the Prolog environment.
|
||||
+ @subpage abs_file_name explains how to find a file full path.
|
||||
+ @ref yapmodules introduces the YAP module system and meta-predicates.
|
||||
|
||||
+ @ref absf0 explains how to find a file full path.
|
||||
|
||||
+ @subpage BuilthYins describes predicates providing core YAP
|
||||
functionality. Examples include
|
||||
@ -1510,7 +1512,7 @@ if it is `source` clauses are compiled and source code is stored;
|
||||
if it is `assert_all` clauses are asserted into the data-base.
|
||||
|
||||
</li>
|
||||
<li>comnsult(+ _Mode_)
|
||||
<li>consult(+ _Mode_)
|
||||
This extension controls the type of file to load. If _Mode_
|
||||
is `consult`, clauses are added to the data-base,
|
||||
is `reconsult`, clauses are recompiled,
|
||||
@ -1986,7 +1988,7 @@ defined, or search the default library directory.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@section Modules The Module System
|
||||
@section old_Modules The Module System
|
||||
|
||||
Module systems are quite important for the development of large
|
||||
applications. YAP implements a module system compatible with the Quintus
|
||||
@ -2006,314 +2008,6 @@ YAP allows one to ignore the module system if one does not want to use
|
||||
it. Last note that using the module system does not introduce any
|
||||
significant overheads.
|
||||
|
||||
@subsection Module_Concepts Module Concepts
|
||||
|
||||
The YAP module system applies to predicates. All predicates belong to a
|
||||
module. System predicates belong to the module `primitives`, and by
|
||||
default new predicates belong to the module `user`. Predicates from
|
||||
the module `primitives` are automatically visible to every module.
|
||||
|
||||
Every predicate must belong to a module. This module is called its
|
||||
<em>source module</em>.
|
||||
|
||||
By default, the source module for a clause occurring in a source file
|
||||
with a module declaration is the declared module. For goals typed in
|
||||
a source file without module declarations, their module is the module
|
||||
the file is being loaded into. If no module declarations exist, this is
|
||||
the current <em>type-in module</em>. The default type-in module is
|
||||
`user`, but one can set the current module by using the built-in
|
||||
`module/1`.
|
||||
|
||||
Note that in this module system one can explicitly specify the source
|
||||
mode for a clause by prefixing a clause with its module, say:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
user:(a :- b).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
In fact, to specify the source module for a clause it is sufficient to
|
||||
specify the source mode for the clause's head:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
user:a :- b.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The rules for goals are similar. If a goal appears in a text file with a
|
||||
module declaration, the goal's source module is the declared
|
||||
module. Otherwise, it is the module the file is being loaded into or the
|
||||
type-in module.
|
||||
|
||||
One can override this rule by prefixing a goal with the module it is
|
||||
supposed to be executed in, say:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
nasa:launch(apollo,13).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
will execute the goal `launch(apollo,13)` as if the current source
|
||||
module was `nasa`.
|
||||
|
||||
Note that this rule breaks encapsulation and should be used with care.
|
||||
|
||||
@subsection Defining_Modules Defining a New Module
|
||||
|
||||
A new module is defined by a `module` declaration:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>module(+ _M_,+ _L_) @anchor module
|
||||
|
||||
|
||||
This directive defines the file where it appears as a module file; it
|
||||
must be the first declaration in the file.
|
||||
_M_ must be an atom specifying the module name; _L_ must be a list
|
||||
containing the module's public predicates specification, in the form
|
||||
`[predicate_name/arity,...]`.
|
||||
|
||||
The public predicates of a module file can be made accessible by other
|
||||
files through the directives [use_module/1](@ref use_module), `use_module/2`,
|
||||
[ensure_loaded/1](@ref ensure_loaded) and the predicates [consult/1](@ref consult) or
|
||||
[reconsult/1](@ref reconsult). The non-public predicates
|
||||
of a module file are not visible by other files; they can, however, be
|
||||
accessed by prefixing the module name with the
|
||||
`:/2` operator.
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
The built-in `module/1` sets the current source module:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>module(+ _M_,+ _L_, + _Options_)
|
||||
|
||||
Similar to [module/2](@ref module), this directive defines the file where it
|
||||
appears in as a module file; it must be the first declaration in the file.
|
||||
_M_ must be an atom specifying the module name; _L_ must be a
|
||||
list containing the module's public predicates specification, in the
|
||||
form `[predicate_name/arity,...]`.
|
||||
|
||||
The last argument _Options_ must be a list of options, which can be:
|
||||
|
||||
<ul>
|
||||
<li>filename
|
||||
the filename for a module to import into the current module.
|
||||
|
||||
</li>
|
||||
<li>library(file)
|
||||
a library file to import into the current module.
|
||||
|
||||
</li>
|
||||
<li>hide( _Opt_)
|
||||
if _Opt_ is `false`, keep source code for current module, if
|
||||
`true`, disable.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
<li>module(+ _M_)
|
||||
|
||||
Defines _M_ to be the current working or type-in module. All files
|
||||
which are not bound to a module are assumed to belong to the working
|
||||
module (also referred to as type-in module). To compile a non-module
|
||||
file into a module which is not the working one, prefix the file name
|
||||
with the module name, in the form ` _Module_: _File_`, when
|
||||
loading the file.
|
||||
|
||||
</li>
|
||||
<li>export(+ _PredicateIndicator_) @anchor export
|
||||
|
||||
|
||||
|
||||
Add predicates to the public list of the context module. This implies
|
||||
the predicate will be imported into another module if this module is
|
||||
imported with `use_module/[1,2]`. Note that predicates are normally
|
||||
exported using the directive [module/2](@ref module). [export/1](@ref export) is meant
|
||||
to handle export from dynamically created modules. The directive argument
|
||||
may also be a list of predicates.
|
||||
|
||||
</li>
|
||||
<li>export_list(? _Mod_,? _ListOfPredicateIndicator_) @anchor export_list
|
||||
|
||||
|
||||
|
||||
The list _ListOfPredicateIndicator_ contains all predicates exported
|
||||
by module _Mod_.
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@subsection Using_Modules Using Modules
|
||||
|
||||
By default, all procedures to consult a file will load the modules
|
||||
defined therein. The two following declarations allow one to import a
|
||||
module explicitly. They differ on whether one imports all predicate
|
||||
declared in the module or not.
|
||||
|
||||
<ul>
|
||||
|
||||
<li>use_module(+ _F_) @anchor use_module
|
||||
|
||||
|
||||
Loads the files specified by _F_, importing all their public
|
||||
predicates. Predicate name clashes are resolved by asking the user about
|
||||
importing or not the predicate. A warning is displayed when _F_ is
|
||||
not a module file.
|
||||
|
||||
</li>
|
||||
<li>use_module(+ _F_,+ _L_)
|
||||
|
||||
Loads the files specified by _F_, importing the predicates specified
|
||||
in the list _L_. Predicate name clashes are resolved by asking the
|
||||
user about importing or not the predicate. A warning is displayed when
|
||||
_F_ is not a module file.
|
||||
|
||||
</li>
|
||||
<li>use_module(? _M_,? _F_,+ _L_)
|
||||
|
||||
If module _M_ has been defined, import the procedures in _L_ to
|
||||
the current module. Otherwise, load the files specified by _F_,
|
||||
importing the predicates specified in the list _L_.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@subsection MetahYPredicates_in_Modules Meta-Predicates and Modules
|
||||
|
||||
The module system must know whether predicates operate on goals or
|
||||
clauses. Otherwise, such predicates would call a goal in the module they
|
||||
were defined, instead of calling it in the module they are currently
|
||||
executing. So, for instance, consider a file example.pl:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
:- module(example,[a/1]).
|
||||
|
||||
a(G) :- call(G)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We import this module with `use_module(example)` into module
|
||||
`user`. The expected behavior for a goal `a(p)` is to
|
||||
execute goal `p` within the module `user`. However,
|
||||
`a/1` will call `p` within module `example`.
|
||||
|
||||
The [meta_predicate/1](@ref meta_predicate) declaration informs the system that some
|
||||
arguments of a predicate are goals, clauses, clauses heads or other
|
||||
terms related to a module, and that these arguments must be prefixed
|
||||
with the current source module:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>meta_predicate _G1_,...., _Gn_ @anchor meta_predicate
|
||||
|
||||
|
||||
Each _Gi_ is a mode specification.
|
||||
|
||||
If the argument is `:`, it does not refer directly to a predicate
|
||||
but must be module expanded. If the argument is an integer, the argument
|
||||
is a goal or a closure and must be expanded. Otherwise, the argument is
|
||||
not expanded. Note that the system already includes declarations for all
|
||||
built-ins.
|
||||
|
||||
For example, the declaration for [call/1](@ref call) and [setof/3](@ref setof) are:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
:- meta_predicate call(0), setof(?,0,?).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
The previous example is expanded to the following code which explains,
|
||||
why the goal `a(p)` calls `p` in `example` and not in
|
||||
`user`. The goal `call(G)` is expanded because of the
|
||||
meta-predicate declaration for [call/1](@ref call).
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
:- module(example,[a/1]).
|
||||
|
||||
a(G) :- call(example:G)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By adding a meta-predicate declaration for `a/1`, the goal
|
||||
`a(p)` in module user will be expanded to `a(user:p)`
|
||||
thereby preserving the module information.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
:- module(example,[a/1]).
|
||||
|
||||
:- meta_predicate a(:).
|
||||
a(G) :- call(G)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An alternate mechanism is the directive [module_transparent/1](@ref module_transparent)
|
||||
offered for compatibility with SWI-Prolog.
|
||||
|
||||
<ul>
|
||||
|
||||
<li>module_transparent + _Preds_ @anchor module_transparent
|
||||
|
||||
|
||||
_Preds_ is a comma separated sequence of name/arity predicate
|
||||
indicators (like
|
||||
[dynamic/1](@ref dynamic)). Each goal associated with a transparent declared
|
||||
predicate will inherit the context module from its parent goal.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@subsection RehYExporting_Modules Re-Exporting Predicates From Other Modules
|
||||
|
||||
It is sometimes convenient to re-export predicates originally defined in
|
||||
a different module. This is often useful if you are adding to the
|
||||
functionality of a module, or if you are composing a large module with
|
||||
several small modules. The following declarations can be used for that purpose:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>reexport(+ _F_) @anchor reexport
|
||||
|
||||
|
||||
Export all predicates defined in file _F_ as if they were defined in
|
||||
the current module.
|
||||
|
||||
</li>
|
||||
<li>reexport(+ _F_,+ _Decls_)
|
||||
|
||||
Export predicates defined in file _F_ according to _Decls_. The
|
||||
declarations may be of the form:
|
||||
|
||||
<ul>
|
||||
<li>A list of predicate declarations to be exported. Each declaration
|
||||
may be a predicate indicator or of the form `` _PI_ `as`
|
||||
_NewName_'', meaning that the predicate with indicator _PI_ is
|
||||
to be exported under name _NewName_.
|
||||
</li>
|
||||
<li>`except`( _List_)
|
||||
In this case, all predicates not in _List_ are exported. Moreover,
|
||||
if ` _PI_ `as` _NewName_` is found, the predicate with
|
||||
indicator _PI_ is to be exported under name _NewName_ as
|
||||
before.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Re-exporting predicates must be used with some care. Please, take into
|
||||
account the following observations:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The `reexport` declarations must be the first declarations to
|
||||
follow the `module` declaration.
|
||||
</li>
|
||||
<li>
|
||||
It is possible to use both `reexport` and `use_module`, but
|
||||
all predicates reexported are automatically available for use in the
|
||||
current module.
|
||||
</li>
|
||||
<li>
|
||||
In order to obtain efficient execution, YAP compiles dependencies
|
||||
between re-exported predicates. In practice, this means that changing a
|
||||
`reexport` declaration and then *just* recompiling the file
|
||||
may result in incorrect execution.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@page BuilthYins Built-In Predicates Library
|
||||
|
||||
|
@ -65,6 +65,9 @@ regardless of the cycle-length.
|
||||
left as a responsibility to the user.
|
||||
@see "Co-Logic Programming: Extending Logic Programming with Coinduction"
|
||||
by Luke Somin et al.
|
||||
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
:- meta_predicate coinductive(:).
|
||||
@ -155,7 +158,7 @@ writeG_val(G_var) :-
|
||||
|
||||
%-----------------------------------------------------
|
||||
|
||||
/**************************************
|
||||
/**
|
||||
|
||||
Some examples from Coinductive Logic Programming and its Applications by Gopal Gupta et al, ICLP 97
|
||||
|
||||
@ -191,6 +194,7 @@ i(s(N)) :- i(N).
|
||||
get_code(_),
|
||||
fail.
|
||||
|
||||
@}
|
||||
|
||||
**************************************/
|
||||
|
||||
|
31
pl/absf.yap
31
pl/absf.yap
@ -8,10 +8,7 @@
|
||||
* *
|
||||
*************************************************************************/
|
||||
|
||||
/**
|
||||
@file absf.yap
|
||||
|
||||
@defgroup abs_file_name File Name Resolution
|
||||
/** @defgroup absf0 File Name Resolution
|
||||
|
||||
Support for file name resolution through absolute_file_name/3 and
|
||||
friends. These utility built-ins describe a list of directories that
|
||||
@ -21,8 +18,7 @@
|
||||
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
**/
|
||||
|
||||
:- system_module( absolute_file_name, [absolute_file_name/2,
|
||||
absolute_file_name/3,
|
||||
@ -32,6 +28,7 @@
|
||||
remove_from_path/1], ['$full_filename'/3,
|
||||
'$system_library_directories'/2]).
|
||||
|
||||
|
||||
:- use_system_module( '$_boot', ['$system_catch'/4]).
|
||||
|
||||
:- use_system_module( '$_errors', ['$do_error'/2]).
|
||||
@ -39,8 +36,8 @@
|
||||
:- use_system_module( '$_lists', [member/2]).
|
||||
|
||||
/**
|
||||
absolute_file_name(+File:atom, +Options:list, +Path:atom) is nondet
|
||||
absolute_file_name(-File:atom, +Path:atom, +Options:list) is nondet
|
||||
@pred absolute_file_name(+File:atom, +Options:list, +Path:atom) is nondet
|
||||
@pred absolute_file_name(-File:atom, +Path:atom, +Options:list) is nondet
|
||||
|
||||
_Options_ is a list of options to guide the conversion:
|
||||
|
||||
@ -121,7 +118,7 @@ absolute_file_name(File,Opts,TrueFileName) :-
|
||||
'$absolute_file_name'(File,Opts,TrueFileName,absolute_file_name(File,Opts,TrueFileName)).
|
||||
|
||||
/**
|
||||
absolute_file_name(+Name:atom,+Path:atom) is nondet
|
||||
@pred absolute_file_name(+Name:atom,+Path:atom) is nondet
|
||||
|
||||
Converts the given file specification into an absolute path, using default options. See absolute_file_name/3 for details on the options.
|
||||
*/
|
||||
@ -461,7 +458,7 @@ absolute_file_name(File0,File) :-
|
||||
atom_concat([P0,A,Atoms],NFile).
|
||||
|
||||
/**
|
||||
path(-Directories:list) is det,deprecated
|
||||
@pred path(-Directories:list) is det,deprecated
|
||||
|
||||
YAP specific procedure that returns a list of user-defined directories
|
||||
in the library search-path.We suggest using user:file_search_path/2 for
|
||||
@ -475,7 +472,7 @@ path(Path) :- findall(X,'$in_path'(X),Path).
|
||||
atom_codes(X,S) ).
|
||||
|
||||
/**
|
||||
add_to_path(+Directory:atom) is det,deprecated
|
||||
@pred add_to_path(+Directory:atom) is det,deprecated
|
||||
|
||||
YAP-specific predicate to include directory in library search path.
|
||||
We suggest using user:file_search_path/2 for
|
||||
@ -484,7 +481,7 @@ path(Path) :- findall(X,'$in_path'(X),Path).
|
||||
add_to_path(New) :- add_to_path(New,last).
|
||||
|
||||
/**
|
||||
add_to_path(+Directory:atom, +Position:atom) is det,deprecated
|
||||
@pred add_to_path(+Directory:atom, +Position:atom) is det,deprecated
|
||||
|
||||
YAP-specific predicate to include directory in front or back of
|
||||
library search path. We suggest using user:file_search_path/2 for
|
||||
@ -500,7 +497,7 @@ add_to_path(New,Pos) :-
|
||||
'$add_to_path'(New,last) :- !, recordz('$path',New,_).
|
||||
'$add_to_path'(New,first) :- recorda('$path',New,_).
|
||||
|
||||
/** remove_from_path(+Directory:atom) is det,deprecated
|
||||
/** @pred remove_from_path(+Directory:atom) is det,deprecated
|
||||
|
||||
*/
|
||||
remove_from_path(New) :- '$check_path'(New,Path),
|
||||
@ -513,7 +510,7 @@ remove_from_path(New) :- '$check_path'(New,Path),
|
||||
'$check_path'([N|S],[N|SN]) :- integer(N), '$check_path'(S,SN).
|
||||
|
||||
/**
|
||||
user:library_directory(?Directory:atom) is nondet, dynamic
|
||||
@pred user:library_directory(?Directory:atom) is nondet, dynamic
|
||||
|
||||
Dynamic, multi-file predicate that succeeds when _Directory_ is a
|
||||
current library directory name. Asserted in the user module.
|
||||
@ -529,7 +526,7 @@ remove_from_path(New) :- '$check_path'(New,Path),
|
||||
:- dynamic user:library_directory/1.
|
||||
|
||||
/**
|
||||
user:commons_directory(?Directory:atom) is nondet, dynamic
|
||||
@pred user:commons_directory(?Directory:atom) is nondet, dynamic
|
||||
|
||||
*/
|
||||
|
||||
@ -538,7 +535,7 @@ remove_from_path(New) :- '$check_path'(New,Path),
|
||||
:- dynamic user:commons_directory/1.
|
||||
|
||||
/**
|
||||
user:prolog_file_type(?Suffix:atom, ?Handler:atom) is nondet, dynamic
|
||||
@pred user:prolog_file_type(?Suffix:atom, ?Handler:atom) is nondet, dynamic
|
||||
|
||||
This multifile/dynamic predicate relates a file extension _Suffix_
|
||||
to a language or file type _Handler_. By
|
||||
@ -578,7 +575,7 @@ user:prolog_file_type(A, executable) :-
|
||||
current_prolog_flag(shared_object_extension, A).
|
||||
|
||||
/**
|
||||
user:file_search_path(+Name:atom, -Directory:atom) is nondet
|
||||
@pred user:file_search_path(+Name:atom, -Directory:atom) is nondet
|
||||
|
||||
Allows writing file names as compound terms. The _Name_ and
|
||||
_DIRECTORY_ must be atoms. The predicate may generate multiple
|
||||
|
149
pl/consult.yap
149
pl/consult.yap
@ -357,47 +357,6 @@ exo_files(Fs) :-
|
||||
db_files(Fs) :-
|
||||
'$load_files'(Fs, [consult(db), if(not_loaded)], exo_files(Fs)).
|
||||
|
||||
%
|
||||
% stub to prevent modules defined within the prolog module.
|
||||
%
|
||||
module(Mod, Decls) :-
|
||||
'$current_module'(prolog, Mod), !,
|
||||
'$export_preds'(Decls).
|
||||
|
||||
'$export_preds'([]).
|
||||
'$export_preds'([N/A|Decls]) :-
|
||||
functor(S, N, A),
|
||||
'$sys_export'(S, prolog),
|
||||
'$export_preds'(Decls).
|
||||
|
||||
|
||||
% prevent modules within the kernel module...
|
||||
use_module(M,F,Is) :-
|
||||
'$use_module'(M,F,Is).
|
||||
|
||||
'$use_module'(M,F,Is) :-
|
||||
var(Is), !,
|
||||
'$use_module'(M,F,all).
|
||||
'$use_module'(M,F,Is) :-
|
||||
nonvar(F), !,
|
||||
strip_module(F, M0, F0),
|
||||
'$load_files'(M0:F0, [if(not_loaded),must_be_module(true),imports(Is)], use_module(M,F,Is)),
|
||||
( var(M) -> true
|
||||
;
|
||||
absolute_file_name( F0, F1, [expand(true),file_type(prolog)] ),
|
||||
recorded('$module','$module'(F1,M,_,_),_)
|
||||
).
|
||||
'$use_module'(M,F,Is) :-
|
||||
nonvar(M), !,
|
||||
strip_module(F, M0, F0),
|
||||
(
|
||||
recorded('$module','$module'(F1,M,_,_),_)
|
||||
->
|
||||
'$load_files'(M0:F1, [if(not_loaded),must_be_module(true),imports(Is)], use_module(M,F,Is))
|
||||
),
|
||||
(var(F0) -> F0 = F1 ; absolute_file_name( F1, F2, [expand(true),file_type(prolog)] ) -> F2 = F0 ).
|
||||
'$use_module'(M,F,Is) :-
|
||||
'$do_error'(instantiation_error,use_module(M,F,Is)).
|
||||
|
||||
'$csult'(Fs, M) :-
|
||||
'$extract_minus'(Fs, MFs), !,
|
||||
@ -666,6 +625,110 @@ initialization(G,OPT) :-
|
||||
print_message(Verbosity, loaded(included, Y, Mod, T, H)),
|
||||
nb_setval('$included_file',OY).
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@addtogroup yapmodules
|
||||
|
||||
@{
|
||||
|
||||
**/
|
||||
|
||||
%
|
||||
% stub to prevent modules defined within the prolog module.
|
||||
%
|
||||
module(Mod, Decls) :-
|
||||
'$current_module'(prolog, Mod), !,
|
||||
'$export_preds'(Decls).
|
||||
|
||||
'$export_preds'([]).
|
||||
'$export_preds'([N/A|Decls]) :-
|
||||
functor(S, N, A),
|
||||
'$sys_export'(S, prolog),
|
||||
'$export_preds'(Decls).
|
||||
|
||||
|
||||
% prevent modules within the kernel module...
|
||||
/** @pred use_module(? _M_,? _F_,+ _L_) is directive
|
||||
SICStus compatible way of using a module
|
||||
|
||||
If module _M_ is instantiated, import the procedures in _L_ to the
|
||||
current module. Otherwise, operate as use_module/2, and load the files
|
||||
specified by _F_, importing the predicates specified in the list _L_.
|
||||
*/
|
||||
|
||||
use_module(M,F,Is) :- '$use_module'(M,F,Is).
|
||||
|
||||
'$use_module'(M,F,Is) :-
|
||||
var(Is), !,
|
||||
'$use_module'(M,F,all).
|
||||
'$use_module'(M,F,Is) :-
|
||||
nonvar(F), !,
|
||||
strip_module(F, M0, F0),
|
||||
'$load_files'(M0:F0, [if(not_loaded),must_be_module(true),imports(Is)], use_module(M,F,Is)),
|
||||
( var(M) -> true
|
||||
;
|
||||
absolute_file_name( F0, F1, [expand(true),file_type(prolog)] ),
|
||||
recorded('$module','$module'(F1,M,_,_),_)
|
||||
).
|
||||
'$use_module'(M,F,Is) :-
|
||||
nonvar(M), !,
|
||||
strip_module(F, M0, F0),
|
||||
(
|
||||
recorded('$module','$module'(F1,M,_,_),_)
|
||||
->
|
||||
'$load_files'(M0:F1, [if(not_loaded),must_be_module(true),imports(Is)], use_module(M,F,Is))
|
||||
),
|
||||
(var(F0) -> F0 = F1 ; absolute_file_name( F1, F2, [expand(true),file_type(prolog)] ) -> F2 = F0 ).
|
||||
'$use_module'(M,F,Is) :-
|
||||
'$do_error'(instantiation_error,use_module(M,F,Is)).
|
||||
|
||||
/**
|
||||
|
||||
@pred reexport(+F) is directive
|
||||
@pred reexport(+F, +Decls ) is directive
|
||||
allow a module to use and export predicates from another module
|
||||
|
||||
Export all predicates defined in list _F_ as if they were defined in
|
||||
the current module.
|
||||
|
||||
Export predicates defined in file _F_ according to _Decls_. The
|
||||
declarations should be of the form:
|
||||
|
||||
<ul>
|
||||
<li>A list of predicate declarations to be exported. Each declaration
|
||||
may be a predicate indicator or of the form `` _PI_ `as`
|
||||
_NewName_'', meaning that the predicate with indicator _PI_ is
|
||||
to be exported under name _NewName_.
|
||||
</li>
|
||||
<li>`except`( _List_)
|
||||
In this case, all predicates not in _List_ are exported. Moreover,
|
||||
if ` _PI_ `as` _NewName_` is found, the predicate with
|
||||
indicator _PI_ is to be exported under name _NewName_ as
|
||||
before.
|
||||
</li>
|
||||
|
||||
Re-exporting predicates must be used with some care. Please, take into
|
||||
account the following observations:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The `reexport` declarations must be the first declarations to
|
||||
follow the `module` declaration.
|
||||
</li>
|
||||
<li>
|
||||
It is possible to use both `reexport` and `use_module`, but
|
||||
all predicates reexported are automatically available for use in the
|
||||
current module.
|
||||
</li>
|
||||
<li>
|
||||
In order to obtain efficient execution, YAP compiles dependencies
|
||||
between re-exported predicates. In practice, this means that changing a
|
||||
`reexport` declaration and then *just* recompiling the file
|
||||
may result in incorrect execution.
|
||||
</li>
|
||||
</ul>
|
||||
**/
|
||||
'$reexport'( TOpts, File, Imports, OldF ) :-
|
||||
'$lf_opt'(reexport, TOpts, Reexport),
|
||||
( Reexport == false -> true ;
|
||||
@ -675,6 +738,10 @@ initialization(G,OPT) :-
|
||||
'$extend_exports'(File, Imports, OldF )
|
||||
).
|
||||
|
||||
/**
|
||||
@}
|
||||
**/
|
||||
|
||||
%
|
||||
% reconsult at startup...
|
||||
%
|
||||
|
@ -253,6 +253,8 @@ system_message(error(permission_error(alias,new,P), Where)) -->
|
||||
system_message(error(permission_error(create,Name,P), Where)) -->
|
||||
{ object_name(Name, ObjName) },
|
||||
[ 'PERMISSION ERROR- ~w: cannot create ~a ~w' - [Where,ObjName,P] ].
|
||||
system_message(error(permission_error(import,M1:I,redefined,SecondMod), Where)) -->
|
||||
[ 'PERMISSION ERROR- loading ~w: modules ~w and ~w both define ~w' - [Where,M1,SecondMod,I] ].
|
||||
system_message(error(permission_error(input,binary_stream,Stream), Where)) -->
|
||||
[ 'PERMISSION ERROR- ~w: cannot read from binary stream ~w' - [Where,Stream] ].
|
||||
system_message(error(permission_error(input,closed_stream,Stream), Where)) -->
|
||||
|
608
pl/modules.yap
608
pl/modules.yap
@ -15,6 +15,210 @@
|
||||
* *
|
||||
*************************************************************************/
|
||||
|
||||
/**
|
||||
|
||||
\defgroup yapmodules The YAP module system
|
||||
|
||||
\section syapmods The YAP Module System
|
||||
|
||||
The YAP module system is based on the Quintus/SISCtus module
|
||||
system. In this design, modules are named collections of predicates,
|
||||
and all predicates belong to a single module. Predicates are only
|
||||
visible within a module, or _private_ to that module, but the module
|
||||
will most often will also define a list of predicates that are
|
||||
_exported_, that is, visible to other modules.
|
||||
|
||||
The main predicates in the module system are:
|
||||
|
||||
* module/2 associates a source file to a module. It has two arguments: the name of the new module, and a list of predicates exported by the module.
|
||||
|
||||
* use_module/1 and use_module/2 can be used to load a module. They take as first argument the source file for the module. Whereas use_module/1 loads all exported predicates, use_module/2 only takes the ones given by the second argument.
|
||||
|
||||
YAP pre-defines a number of modules. Most system predicates belong to
|
||||
the module `prolog`. Predicates from the module `prolog` are
|
||||
automatically visible to every module. The `system` module was
|
||||
introduced for SWI-Prolog compatibility, and in YAP mostly acts as an
|
||||
alias to `prolog`.
|
||||
|
||||
YAP is always associated to a module, the current <em>source
|
||||
module</em> or <em>type-in module</em>. By default, all predicates
|
||||
read-in and all calls to a goal will be made to predicates visible to
|
||||
the current source module, Initially, the source module for YAP is the
|
||||
module `user`. Thus Prolog programs that do not define modules will
|
||||
operate within the `user` module. In this case, all predicates will be
|
||||
visible to all source files.
|
||||
|
||||
YAP also includes a number of libraries and packages, most of them
|
||||
defining their own modules. Note that there is no system mechanism to
|
||||
avoid clashes between module names, so it is up to the programmer to
|
||||
carefully choose the names for her own program modules.
|
||||
|
||||
The main mechanism to change the current type-in module is by using
|
||||
the module/2 declaration.This declaration sets the source module when
|
||||
it starts consulting a file, and resets it at the end. One can set
|
||||
the type-in module permanently by using the built-in `module/1`.
|
||||
|
||||
\subsection Explicit Naming
|
||||
|
||||
The module system allows one to _explicitly_ specify the source mode for
|
||||
a clause by prefixing a clause with its module, say:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
user:(a :- b).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
it is also possible to type
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
|
||||
user:a :- user:b.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
both formulations describe the same clause, independently of the
|
||||
current type-in module.
|
||||
|
||||
In fact, it is sufficient to specify the source mode for the clause's
|
||||
head:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
user:a :- b.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if the current type-in module is `m`, the clause could also be written as:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
user:a :- m:b.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The compiler rewrites the source clauses to ensure that explicit calls
|
||||
are respected, and that implicit calls are made to the current source
|
||||
module.
|
||||
|
||||
A goal should refer to a predicate visible within the current type-in
|
||||
module. Thus, if a goal appears in a text file with a module
|
||||
declaration, the goal refers to that module's context (but see the
|
||||
initialization/1 directive for more details).
|
||||
|
||||
Again, one can override this rule by prefixing a goal with a module to
|
||||
be consulted. The following query:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
?- nasa:launch(apollo,13).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
invokes the goal `launch(apollo,13)` as if the current source
|
||||
module was `nasa`.
|
||||
|
||||
YAP and other Prolog systems allow the module prefix to see all
|
||||
predicates visible in the module, including predicates private to the
|
||||
module. This rule allows maximum flexibility, but it also breaks
|
||||
encapsulation and should be used with care. The ciao language proposes
|
||||
a different approach to this problem, see \cite .
|
||||
|
||||
Modules are not always associated with a source-file. They
|
||||
may range over several files, by using the
|
||||
`include`directive. Moreover, they may not be associated to any source
|
||||
file. As an example,
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
?- assert( nasa:launch(apollo,13) ).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
will create a module `nasa`, if does not already exist. In fact it is
|
||||
sufficient to call a predicate from a module to implicitly create the
|
||||
module. Hence after this call:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
?- nasa:launch(apollo,13).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
there will be a `nasa`module in the system, even if nasa:launch/2 is
|
||||
not at all defined.
|
||||
|
||||
\subsection Using_Modules Using Modules
|
||||
|
||||
By default, all procedures to consult a file will load the modules
|
||||
defined therein. The two following declarations allow one to import a
|
||||
module explicitly. They differ on whether one imports all predicate
|
||||
declared in the module or not.
|
||||
|
||||
|
||||
\subsection MetahYPredicates_in_Modules Meta-Predicates and Modules
|
||||
|
||||
Consider the files opl.pl and rel.pl:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
% opl.pl
|
||||
:- module(opl,[set_min/2]).
|
||||
|
||||
% obtain the smallest value for the last argument of goal G
|
||||
set_min(G, Min) :-
|
||||
last_argument( G, A ),
|
||||
findall( A, call(G, A), Vs),
|
||||
sort( Vs, [Min|_]).
|
||||
|
||||
% rel.pl
|
||||
:- module(rel,[min_last/2]).
|
||||
|
||||
:- use_module(opl).
|
||||
|
||||
node(1, 2).
|
||||
node(1, 4).
|
||||
node(2, 3).
|
||||
node(0, 4).
|
||||
node(1, 4).
|
||||
|
||||
min_last(First, Min) :-
|
||||
rel_min( node(First, V), Min).
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Calling `min_last(node(_,_),Min)` should return `Min = 2` and
|
||||
min_last(node(0,_),Min) should return `Min = 4`. To obtain this
|
||||
behavior we need to call rel:node/1 from opl:set_min/2. However,
|
||||
`opl:set_min/2` has no way to know that the goal `G` is from module
|
||||
`rel`.
|
||||
|
||||
The meta_predicate/1 declaration addresses this problem by informing
|
||||
the compiler that arguments of a predicate are goals, clauses, clauses
|
||||
heads or other terms related to a module, and that these arguments
|
||||
must be prefixed with their source module:
|
||||
|
||||
In the example we need to declare set_min/2 as a meta-predicate that
|
||||
calls its first argument:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
:- meta_predicate set_min(0,-).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The 0 in the first argument refers to the use of call/1. The second argument has a mode (output mode) declaration, but this is not used in YAP.
|
||||
|
||||
|
||||
The compiler uses this declaration to rewrite the calls to set_min/1 so that the module of the first argument is made explicit. In the example this corresponds to rewriting min_last/2.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
min_last(First, Min) :-
|
||||
rel_min( rel:node(First, V), Min).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note the prefix `rel` before passing the call to node/2.
|
||||
|
||||
This process is not entirely transparent. Namely, last_argument/2 is
|
||||
now forced to deal with the term `rel:node(First, V)`, instead of the
|
||||
simpler `node(First, V)`. The very useful built-in strip_module/3
|
||||
extracts the module prefix. We thus obtain:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
last_argument( G, A) :-
|
||||
strip_module( G, _M, T),
|
||||
functor(T, _, Arity),
|
||||
arg(Arity, T, A).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
An alternate mechanism is the directive module_transparent/1 that is
|
||||
offered for compatibility with SWI-Prolog.
|
||||
|
||||
\{
|
||||
|
||||
**/
|
||||
:- system_module( '$_modules', [abolish_module/1,
|
||||
add_import_module/3,
|
||||
current_module/1,
|
||||
@ -66,15 +270,252 @@
|
||||
% start using default definition of module.
|
||||
%
|
||||
|
||||
use_module(F) :-
|
||||
'$load_files'(F, [if(not_loaded),must_be_module(true)], use_module(F)).
|
||||
/**
|
||||
\pred use_module( +Files ) is directive
|
||||
loads a module file
|
||||
|
||||
This predicate loads the file specified by _Files_, importing all
|
||||
their public predicates into the current type-in module. It is
|
||||
implemented as if by:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
use_module(F) :-
|
||||
load_files(F, [if(not_loaded),must_be_module(true)]).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Notice that _Files_ may be a single file, or a list with a number
|
||||
files. The _Files_ are loaded in YAP only once, even if they have been
|
||||
updated meanwhile. YAP should also verify whether the files actually
|
||||
define modules. Please consult load_files/3 for other options when
|
||||
loading a file.
|
||||
|
||||
Predicate name clashes between two different modules may arise, either
|
||||
when trying to import predicates that are also defined in the current
|
||||
type-in module, or by trying to import the same predicate from two
|
||||
different modules.
|
||||
|
||||
In the first case, the local predicate is considered to have priority
|
||||
and use_module/1 simply gives a warning. As an example, if the file
|
||||
`a.pl` contains:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
:- module( a, [a/1] ).
|
||||
|
||||
:- use_module(b).
|
||||
|
||||
a(1).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
and the file `b.pl` contains:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
:- module( b, [a/1,b/1] ).
|
||||
|
||||
a(2).
|
||||
|
||||
b(1).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
YAP will execute as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
?- use_module(a).
|
||||
% consulting /Users/vsc/Yap/a.pl...
|
||||
% consulting /Users/vsc/Yap/b.pl...
|
||||
% consulted /Users/vsc/Yap/b.pl in module b, 0 msec 0 bytes
|
||||
%
|
||||
% Warning:
|
||||
% at line 5 in /Users/vsc/Yap/a.pl,
|
||||
% Module a redefines imported predicate b:a/1.
|
||||
% consulted /Users/vsc/Yap/a.pl in module a, 0 msec 0 bytes
|
||||
true.
|
||||
?- a(X).
|
||||
X = 1.
|
||||
?- b(X).
|
||||
ERROR!!
|
||||
EXISTENCE ERROR- procedure b/1 is undefined, called from context prolog:$user_call/2
|
||||
Goal was user:b(_131290)
|
||||
?- a:b(X).
|
||||
X = 1.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The example shows that the query `a(X)`has a single answer, the one
|
||||
defined in `a.pl`. Calls to `a(X)`succeed in the top-level, because
|
||||
the module `a` was loaded into `user`. On the other hand, `b(X)`is not
|
||||
exported by `a.pl`, and is not available to calls, although it can be
|
||||
accessed as a predicate in the module 'a' by using the `:` operator.
|
||||
|
||||
Next, consider the three files `c.pl`, `d1.pl`, and `d2.pl`:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
% c.pl
|
||||
:- module( c, [a/1] ).
|
||||
|
||||
:- use_module([d1, d2]).
|
||||
|
||||
a(X) :-
|
||||
b(X).
|
||||
a(X) :-
|
||||
c(X).
|
||||
a(X) :-
|
||||
d(X).
|
||||
|
||||
% d1.pl
|
||||
:- module( d1, [b/1,c/1] ).
|
||||
|
||||
b(2).
|
||||
c(3).
|
||||
|
||||
|
||||
% d2.pl
|
||||
:- module( d2, [b/1,d/1] ).
|
||||
|
||||
b(1).
|
||||
d(4).
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The result is as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
./yap -l c
|
||||
YAP 6.3.4 (x86_64-darwin13.3.0): Tue Jul 15 10:42:11 CDT 2014
|
||||
|
||||
ERROR!!
|
||||
at line 3 in /Users/vsc/Yap/bins/threads/d2.pl,
|
||||
PERMISSION ERROR- loading /Users/vsc/Yap/bins/threads/c.pl: modules d1 and d2 both define b/1
|
||||
?- a(X).
|
||||
X = 2 ? ;
|
||||
ERROR!!
|
||||
EXISTENCE ERROR- procedure c/1 is undefined, called from context prolog:$user_call/2
|
||||
Goal was c:c(_131290)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The state of the module system after this error is actually undefined.
|
||||
|
||||
|
||||
**/
|
||||
use_module(F) :- '$load_files'(F,
|
||||
[if(not_loaded),must_be_module(true)], use_module(F)).
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\pred use_module(+Files, +Imports)
|
||||
loads a module file but only imports the named predicates
|
||||
|
||||
This predicate loads the file specified by _Files_, importing their
|
||||
public predicates specified by _Imports_ into the current type-in
|
||||
module. It is implemented as if by:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
use_module(Files, Imports) :-
|
||||
load_files(Files, [if(not_loaded),must_be_module(true),imports(Imports)]).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The _Imports_ argument may be use to specify which predicates one
|
||||
wants to load. It can also be used to give the predicates a different name. As an example,
|
||||
the graphs library is implemented on top of the red-black trees library, and some predicates are just aliases:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pl
|
||||
:- use_module(library(rbtrees), [
|
||||
rb_min/3 as min_assoc,
|
||||
rb_max/3 as max_assoc,
|
||||
...]).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Unfortunately it is still not possible to change argument order.
|
||||
|
||||
**/
|
||||
use_module(F,Is) :-
|
||||
'$load_files'(F, [if(not_loaded),must_be_module(true),imports(Is)], use_module(F,Is)).
|
||||
|
||||
/**
|
||||
\pred module(+M) is det
|
||||
set the type-in module
|
||||
|
||||
|
||||
Defines _M_ to be the current working or type-in module. All files
|
||||
which are not bound to a module are assumed to belong to the working
|
||||
module (also referred to as type-in module). To compile a non-module
|
||||
file into a module which is not the working one, prefix the file name
|
||||
with the module name, in the form ` _Module_: _File_`, when
|
||||
loading the file.
|
||||
|
||||
**/
|
||||
module(N) :-
|
||||
var(N),
|
||||
'$do_error'(instantiation_error,module(N)).
|
||||
module(N) :-
|
||||
atom(N), !,
|
||||
% set it as current module.
|
||||
'$current_module'(_,N).
|
||||
module(N) :-
|
||||
'$do_error'(type_error(atom,N),module(N)).
|
||||
|
||||
/**
|
||||
\pred module(+ Module:atom, +ExportList:list) is directive
|
||||
define a new module
|
||||
|
||||
This directive defines the file where it appears as a _module file_;
|
||||
it must be the first declaration in the file. _Module_ must be an
|
||||
atom specifying the module name; _ExportList_ must be a list
|
||||
containing the module's public predicates specification, in the form
|
||||
`[predicate_name/arity,...]`. The _ExportList_ can also include
|
||||
operator declarations for operators that are exported by the module.
|
||||
|
||||
The public predicates of a module file can be made accessible by other
|
||||
files through loading the source file, using directives
|
||||
use_module/1 or use_module/2,
|
||||
ensure_loaded/1 and the predicates
|
||||
consult/1 or reconsult/1. The
|
||||
non-public predicates of a module file are not supposed to be visible
|
||||
to other modules; they can, however, be accessed by prefixing the module
|
||||
name with the `:/2` operator.
|
||||
|
||||
**/
|
||||
'$module_dec'(N, Ps) :-
|
||||
source_location(F, _),
|
||||
'$add_module_on_file'(N, F, Ps),
|
||||
'$current_module'(_,N).
|
||||
|
||||
'$module'(_,N,P) :-
|
||||
'$module_dec'(N,P).
|
||||
|
||||
/**
|
||||
\pred module(+ _M_,+ _L_, + _Options_) is directive
|
||||
define a new module with options
|
||||
|
||||
Similar to module/2, this directive defines the file where it
|
||||
appears in as a module file; it must be the first declaration in the file.
|
||||
_M_ must be an atom specifying the module name; _L_ must be a
|
||||
list containing the module's public predicates specification, in the
|
||||
form `[predicate_name/arity,...]`.
|
||||
|
||||
The last argument _Options_ must be a list of options, which can be:
|
||||
+ <b>filename</b>
|
||||
the filename for a module to import into the current module.
|
||||
|
||||
+ <b>library( +File )</b>
|
||||
a library file to import into the current module.
|
||||
|
||||
+ <b>hide( +Opt)</b>
|
||||
if _Opt_ is `false`, keep source code for current module, if `true`, disable.
|
||||
|
||||
+ <b>export(+PredicateIndicator )</b>
|
||||
Add predicates to the public list of the context module. This implies
|
||||
the predicate will be imported into another module if this moduleis imported with use_module/1 and use_module/2.
|
||||
|
||||
+ <b>export_list(? _Mod_,? _ListOfPredicateIndicator_)</b>
|
||||
The list _ListOfPredicateIndicator_ contains all predicates
|
||||
exported by module _Mod_
|
||||
|
||||
Note that predicates are normally exported using the directive
|
||||
`module/2`. The `export/1` argumwnt is meant to allow export from
|
||||
dynamically created modules. The directive argument may also be a list
|
||||
of predicates.
|
||||
|
||||
**/
|
||||
'$module'(O,N,P,Opts) :- !,
|
||||
'$module'(O,N,P),
|
||||
'$process_module_decls_options'(Opts,module(Opts,N,P)).
|
||||
@ -117,84 +558,39 @@ use_module(F,Is) :-
|
||||
'$prepare_restore_hidden'(Old,New) :-
|
||||
recorda('$system_initialisation', source_mode(New,Old), _).
|
||||
|
||||
module(N) :-
|
||||
var(N),
|
||||
'$do_error'(instantiation_error,module(N)).
|
||||
module(N) :-
|
||||
atom(N), !,
|
||||
% set it as current module.
|
||||
'$current_module'(_,N).
|
||||
module(N) :-
|
||||
'$do_error'(type_error(atom,N),module(N)).
|
||||
|
||||
'$module_dec'(N, Ps) :-
|
||||
source_location(F, _),
|
||||
'$add_module_on_file'(N, F, Ps),
|
||||
'$current_module'(_,N).
|
||||
|
||||
'$add_module_on_file'(Mod, F, Exports) :-
|
||||
recorded('$module','$module'(F0,Mod,_,_),R), !,
|
||||
'$add_preexisting_module_on_file'(F, F0, Mod, Exports, R).
|
||||
'$add_module_on_file'(Module, F, Exports) :-
|
||||
'$convert_for_export'(all, Exports, Module, Module, TranslationTab, AllExports0, load_files),
|
||||
'$add_to_imports'(TranslationTab, Module, Module), % insert ops, at least for now
|
||||
'$add_module_on_file'(DonorMod, DonorF, Exports) :-
|
||||
recorded('$module','$module'(DonorF, DonorMod, _, _),R),
|
||||
% the module has been found, are we reconsulting?
|
||||
(
|
||||
DonorF \= OtherF
|
||||
->
|
||||
'$do_error'(permission_error(module,redefined,DonorMod, OtherFile, DonorF),module(Mod,Exports))
|
||||
;
|
||||
recorded('$module','$module'(DonorF,DonorM, _, _), R),
|
||||
erase( R ),
|
||||
fail
|
||||
).
|
||||
'$add_module_on_file'(DonorM, DonorF, Exports) :-
|
||||
'$current_module'( HostM ),
|
||||
( recorded('$module','$module'( HostF, HostM, _, _),_) -> true ; HostF = user_input ),
|
||||
% first build the initial export tablee
|
||||
'$convert_for_export'(all, Exports, DonorM, HostM, TranslationTab, AllExports0, load_files),
|
||||
sort( AllExports0, AllExports ),
|
||||
( source_location(_, Line) -> true ; Line = 0 ),
|
||||
recorda('$module','$module'(F,Module,AllExports, Line),_).
|
||||
'$add_to_imports'(TranslationTab, DonorM, HostM), % insert ops, at least for now
|
||||
% last, export everything to the host: if the loading crashed you didn't actually do
|
||||
% no evil.
|
||||
recorda('$module','$module'(DonorF,DonorM,AllExports, Line),_).
|
||||
|
||||
'$extend_exports'(F, Exps , NewF) :-
|
||||
recorded('$module','$module'(NewF,NMod, NewExports, _),_R),
|
||||
recorded('$module','$module'(F, Module,OriginalExports,Line),R),
|
||||
'$convert_for_export'(Exps, NewExports, NMod, NMod, _TranslationTab, NewExports1, load_files),
|
||||
'$add_exports'( NewExports1, OriginalExports, Exports ),
|
||||
sort( Exports, AllExports ),
|
||||
erase(R),
|
||||
recorda('$module','$module'(F,Module,AllExports,Line),_),
|
||||
fail.
|
||||
'$extend_exports'(_F, _Module, _NewExports).
|
||||
|
||||
'$add_exports'( [], Exports, Exports ).
|
||||
'$add_exports'( [PI|NewExports], OriginalExports, [PI|Exports] ) :-
|
||||
% do not check for redefinitions, at least for now.
|
||||
'$add_exports'( NewExports, OriginalExports, Exports ).
|
||||
|
||||
|
||||
% redefining the same previously-defined file, no problem.
|
||||
'$add_preexisting_module_on_file'(F, F, Mod, Exports, R) :- !,
|
||||
erase(R),
|
||||
( recorded('$import','$import'(Mod,_,_,_,_,_),R), erase(R), fail; true),
|
||||
'$extend_exports'(HostF, Exports, DonorF ) :-
|
||||
( recorded('$module','$module'( DonorF, DonorM, _, DonorExports),_) -> true ; DonorF = user_input ),
|
||||
( recorded('$module','$module'( HostF, HostM, _, _),_) -> true ; HostF = user_input ),
|
||||
recorded('$module','$module'(HostF,HostM,AllExports, _Line), R), erase(R),
|
||||
'$convert_for_export'(Exports, DonorExports, DonorM, HostM, _TranslationTab, AllReExports, reexport(DonorF, Exports)),
|
||||
lists:append( AllReExports, AllExports, Everything0 ),
|
||||
sort( Everything0, Everything ),
|
||||
( source_location(_, Line) -> true ; Line = 0 ),
|
||||
recorda('$module','$module'(F,Mod,Exports, Line),_).
|
||||
'$add_preexisting_module_on_file'(F,F0,Mod,Exports,R) :-
|
||||
b_getval('$lf_status', TOpts),
|
||||
'$lf_opt'(redefine_module, TOpts, RM),
|
||||
( RM == false
|
||||
->
|
||||
'$do_error'(permission_error(module,redefined,Mod),module(Mod,Exports)), !
|
||||
;
|
||||
RM == true
|
||||
->
|
||||
'$add_preexisting_module_on_file'(F, F, Mod, Exports, R), !
|
||||
).
|
||||
'$add_preexisting_module_on_file'(F,F0,Mod,Exports,R) :-
|
||||
repeat,
|
||||
format(user_error, "The module ~a is being redefined.~n Old file: ~a~n New file: ~a~nDo you really want to redefine it? (y or n)",[Mod,F0,F]),
|
||||
'$mod_scan'(C), !,
|
||||
( C is "y" ->
|
||||
'$add_preexisting_module_on_file'(F, F, Mod, Exports, R)
|
||||
;
|
||||
'$do_error'(permission_error(module,redefined,Mod),module(Mod,Exports))
|
||||
).
|
||||
|
||||
'$mod_scan'(C) :-
|
||||
stream_property(user_input,tty(true)),
|
||||
stream_property(user_error,tty(true)),
|
||||
!,
|
||||
repeat,
|
||||
get0(C),
|
||||
'$skipeol'(C),
|
||||
(C is "y" -> true ; C is "n" -> true ; C is "h" -> true ; C is "e" -> halt(1) ; format(user_error, ' Please answer with ''y'', ''n'', ''e'' or ''h'' ', []), fail), !.
|
||||
'$mod_scan'(C) :- C is "n".
|
||||
recorda('$module','$module'(HostF,HostM,Everything, Line),_).
|
||||
|
||||
'$module_produced by'(M, M0, N, K) :-
|
||||
recorded('$import','$import'(M,M0,_,_,N,K),_), !.
|
||||
@ -478,6 +874,15 @@ expand_goal(G, G).
|
||||
|
||||
% module_transparent declaration
|
||||
%
|
||||
/** \pred module_transparent( + _Preds_ ) is directive
|
||||
_Preds_ can access the calling context.
|
||||
|
||||
_Preds_ is a comma separated sequence of name/arity predicate
|
||||
indicators (like in dynamic/1). Each goal associated with a
|
||||
transparent declared predicate will inherit the context module from
|
||||
its parent goal.
|
||||
|
||||
*/
|
||||
|
||||
:- dynamic('$module_transparent'/4).
|
||||
|
||||
@ -504,6 +909,24 @@ expand_goal(G, G).
|
||||
|
||||
% directive now meta_predicate Ps :- $meta_predicate(Ps).
|
||||
|
||||
/** meta_predicate(_G1_,...., _Gn) is directive
|
||||
|
||||
Declares that this predicate manipulates references to predicates.
|
||||
Each _Gi_ is a mode specification.
|
||||
|
||||
If the argument is `:`, it does not refer directly to a predicate
|
||||
but must be module expanded. If the argument is an integer, the argument
|
||||
is a goal or a closure and must be expanded. Otherwise, the argument is
|
||||
not expanded. Note that the system already includes declarations for all
|
||||
built-ins.
|
||||
|
||||
For example, the declaration for call/1 and setof/3 are:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
:- meta_predicate call(0), setof(?,0,?).
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*/
|
||||
:- dynamic('$meta_predicate'/4).
|
||||
|
||||
:- multifile '$meta_predicate'/4.
|
||||
@ -753,7 +1176,7 @@ export(Resource) :-
|
||||
export_resource(Resource).
|
||||
|
||||
export_resource(Resource) :-
|
||||
var(Resource),
|
||||
var(Resource), !,
|
||||
'$do_error'(instantiation_error,export(Resource)).
|
||||
export_resource(P) :-
|
||||
P = F/N, atom(F), number(N), N >= 0, !,
|
||||
@ -943,25 +1366,27 @@ export_list(Module, List) :-
|
||||
% dereference MI to M1, in order to find who
|
||||
% is actually generating
|
||||
( '$module_produced by'(M1, MI, N, K) -> true ; MI = M1 ),
|
||||
( '$module_produced by'(M2, Mod, N, K) -> true ; M = M2 ),
|
||||
( '$module_produced by'(M2, Mod, N, K) -> true ; Mod = M2 ),
|
||||
M2 \= M1, !,
|
||||
b_getval('$lf_status', TOpts),
|
||||
'$lf_opt'(redefine_module, TOpts, Action),
|
||||
'$redefine_action'(Action, M1, M2, M, N/K).
|
||||
'$redefine_action'(Action, M1, M2, M, ContextM, N/K).
|
||||
'$check_import'(_,_,_,_).
|
||||
|
||||
'$redefine_action'(ask, M1, M2, M, N/K) :-
|
||||
'$redefine_action'(ask, M1, M2, M, _, N/K) :-
|
||||
stream_property(user_input,tty(true)), !,
|
||||
format(user_error,'NAME CLASH: ~w was already imported to module ~w;~n',[M1:N/K,M2]),
|
||||
format(user_error,' Do you want to import it from ~w ? [y, n, e or h] ',M),
|
||||
'$mod_scan'(C),
|
||||
( C =:= 0'e -> halt(1) ;
|
||||
C =:= 0'y ).
|
||||
'$redefine_action'(true, M1, _, _, _) :- !,
|
||||
'$redefine_action'(true, M1, _, _, _, _) :- !,
|
||||
recorded('$module','$module'(F, M1, _MyExports,_Line),_),
|
||||
unload_file(F).
|
||||
'$redefine_action'(false, M1,M2, M, N/K) :-
|
||||
'$do_error'(permission_error(import,M1:N/K,redefined,M2),module(M)).
|
||||
'$redefine_action'(false, M1, M2, M, ContextM, N/K) :-
|
||||
recorded('$module','$module'(F, ContextM, _MyExports,_Line),_),
|
||||
'$current_module'(_, M2),
|
||||
'$do_error'(permission_error(import,M1:N/K,redefined,M2),F).
|
||||
|
||||
% I assume the clause has been processed, so the
|
||||
% var case is long gone! Yes :)
|
||||
@ -1051,15 +1476,17 @@ delete_import_module(Mod, ImportModule) :-
|
||||
'$set_source_module'(Source0, SourceF) :-
|
||||
current_module(Source0, SourceF).
|
||||
|
||||
/** '$declare_module'(+Module, +Super, +File, +Line, +Redefine) is det.
|
||||
/**
|
||||
\pred declare_module(+Module, +Super, +File, +Line, +Redefine) is det
|
||||
declare explicitely a module
|
||||
|
||||
Start a new (source-)module
|
||||
|
||||
@param Module is the name of the module to declare
|
||||
@param File is the canonical name of the file from which the module
|
||||
\param Module is the name of the module to declare
|
||||
\param File is the canonical name of the file from which the module
|
||||
is loaded
|
||||
@param Line is the line-number of the :- module/2 directive.
|
||||
@param Redefine If =true=, allow associating the module to a new file
|
||||
\param Line is the line-number of the :- module/2 directive.
|
||||
\param Redefine If `true`, allow associating the module to a new file
|
||||
*/
|
||||
'$declare_module'(Name, _Test, Context, _File, _Line) :-
|
||||
add_import_module(Name, Context, start).
|
||||
@ -1103,3 +1530,8 @@ ls_imports.
|
||||
'$system_module'('system').
|
||||
'$system_module'('$attributes').
|
||||
|
||||
/**
|
||||
|
||||
\}
|
||||
|
||||
**/
|
||||
|
Reference in New Issue
Block a user