A modules is a compiler and interpreter entity. Modules have been
first designed for the compiler that compiles modules and then, links
them against libraries in order to produce executables. A module may
be split into several files but a file cannot contain more than
one module. A module is made of a module clause that is a list
for which the
car
is the symbol
module
and followed by
any Bigloo expression (that is definitions or expressions). The module
clause names the module and defines the scope of the definitions. At
last, the module clause is also the place where foreign bindings are
defined and where classes are defined. Recent versions of Bigloo (since 2.7b)
fully supports modules from the interpreter.
A Bigloo program is composed of one or more Bigloo modules where a module is
defined by the following grammar:
<module> ==> <module-declaration> <module-body>
<module-declaration> ==> the module declaration
<module-body> ==> the module body
|
A module is not related to a specific file and can be spread over
several files if that is convenient. In particular, there is no
relationship between module names and file names. The module declaration
(see
Module Declaration) must be the first expression in the first
of the files containing the module; other expressions form the body of
the module. The module body (see
Core Language) contains global
variables, function definitions and
top level expressions
(see
Expressions).
The module declaration form is
module name clause ... | bigloo syntax |
This form defines a module and must be the first in the file. The
argument name is a symbol naming the module. If the same
module name is used more than once, Bigloo signals an error. The
runtime library is composed of modules that are read when a user module
is compiled and hence, if a user module has the same name as one of the
library modules, an error is signaled.
A simple module can be:
(module foo)
(display "this is a module")
|
The first line here is the complete module definition, the last line is
the complete module body and together they form a complete Bigloo program. If
these lines were stored in file zz.scm , invoking bigloo zz.scm
would create the executable a.out which, when obeyed, would
display this is a module on the terminal.
Note:
Some special identifiers are reserved and can't be used to name modules.
If such an identifier is used, the compiler will produce the message:
#(module t
#^
# *** ERROR:bigloo:TOP-LEVEL:Parse error
# Illegal module name -- (MODULE eval ...
|
The list of reserved identifiers may be enlarged for next release. For
the current release that list is made of: eval , foreign and
t .
|
Module
clause
s can be:
main name | bigloo module clause |
This clause defines the entry point for a stand alone application to be
procedure name of arity one. Bigloo invokes this procedure at the
beginning of execution providing the list, composed of the shell command
line arguments, as its single argument.
(module foo
(main start))
(define (start argv)
(display argv)
(newline))
|
Then if this program is compiled into foo and invoked using the
command foo -t bar, the list which is the argument for the main
procedure start would be ("foo" "-t" "bar") .
The special form args-parse helps main function argument parsing
(see Command Line Parsing).
|
include file-name ... | bigloo module clause |
This is a list of file-name s to be included in the source file. Include
files are not modules and may have a special syntax. Thus, besides containing
Bigloo expressions, they can contain import and include clauses, which must
be written in a single list whose first element is the keyword
directives . Includes files can be used to include implementation-neutral
Scheme expressions and definitions in a Bigloo module. Here is an example of
an include file.
;; `foo.sch'
(define-struct point x y)
|
and the module that includes the `foo.sch' file:
;; `foo.scm'
(module foo
(include "foo.sch"))
(print (point 1 2))
|
Include files, may contain module information. This is the role of the
include directives clause here illustrated with the `bar.sch'
example:
;; `bar.sch'
;; the directives
(directives (include "foobar.sch")
(import hux))
;; expressions
(define (gee x) (print x))
|
|
import import ... | bigloo module clause |
An import is a list of the form:
<import> ==> <iclause> ...
<iclause> ==> (<bind-name> ... <bind-name> <module-name> <file-name> ...)
| (<bind-name> ... <bind-name> <module-name>)
| <module-name>
| (<module-name> <file-name> ...)
<bind-name> ==> <r5rs-ident>
| <alias-name>
<alias-name> ==> (<r5rs-ident> <r5rs-ident>)
<module-name> ==> <r5rs-ident>
<file-name> ==> <string>
|
The first alternative in iclause imports the variable named
bind-name which is defined in the module module-name ,
located in the files file-name .... The second does the same
but without specifying the name of the file where the module is located.
The third and the fourth form import all the exported variables of the module
module-name .
Note: The need for specifying in which files modules are located comes
from the fact that there is no automatic mapping between module names
and files names. Such a mapping can be defined in a ``module access file''
(see Module Access File) or in the import clause itself, as
in the first and fourth alternatives in iclause above.
Here is an example of an import clause:
(module foo
(import
;; import all bar exported bindings:
bar
;; import the hux binding exported by
;; the module hux :
(hux hux)
;; import the fun1 , fun2 and fun3 bindings exported by
;; the module mod :
(fun1 fun2 fun3 mod)
;; import the fun4 bindings that will be known in this module
;; under the alias name f
((f fun4) mod)
;; import all gee bindings. the gee module
;; is located in a file called `gee.scm':
(gee "gee.scm")))
|
|
use use ... | bigloo module clause |
use has the same meaning as import except that modules
which are used are not initialized (see Module Initialization).
Used modules are read before imported modules.
|
with with ... | bigloo module clause |
This clause specifies a list of modules which have to be
initialized at runtime and is used to force the initialization
of modules which are never imported but which are required by an
application (see Embedded Bigloo applications).
|
export export ... | bigloo module clause |
In order to make a module's global bindings available to other modules, they
have to be exported. Export clauses are in charge of this task and an
export is a list of the form:
<export> ==> <eclause> ...
<eclause> ==> <ident>
| (inline <ident> <ident> ...)
| (generic <ident> <ident> <ident> ...)
| (<ident> <ident> ...)
| <class>
| (macro <ident> <ident> ...)
| (expander <ident>)
| (syntax <ident>)
|
The first form of eclause allows the variable ident be exported,
the second allows the function ident , always regarded as immutable
when exported this way, to be exported and the third exports an
inline-procedure (see Inline Procedures) whose name is extracted from
the first ident after the word inline . The last two are both
connected with Bigloo's object system. The generic clause exports
generic functions (see Generic functions) and class clause exports
classes (see Class declaration).
Note: Only bindings defined in module m can be exported
by m (i.e. bindings imported by m cannot be
exported by m ).
Type information, specified in any ident in an export clause, is used
by Bigloo. Where no type information is given, a default generic type named
obj is used.
Note: The last formal argument of a multiple arity function can
not be typed because this argument is bound to be a pair
or null . This union cannot be denoted by any type.
Here is an example of the module foo that exports bindings:
(module foo
(export
;; export the bar mutable variable
bar
;; export the hux function. this
;; function takes exactly two arguments
(hux x y)
;; export the inline function gee
;; that takes at least one argument.
(inline gee x . z)))
|
|
static static ... | bigloo module clause |
A static clause has exactly the same syntax as an export
clause. However, bindings declared static are local to the module. Since
the default scope of all bindings is static, static module clauses
are useful only for program documentation.
|
from from ... | bigloo module clause |
from clauses have the syntax of import
clauses. The allow the re-exportation of imported bindings. That is, any
module can export any bindings imported via a from clause.
As an example, suppose we have module bar :
(module bar
(export (fun)))
(define (fun) "bar")
|
Now, suppose we have a module foo that imports bar , by the
means of a from clause. Module foo is able to re-export the
bar binding of module bar :
(module foo
(from (fun bar "bar.scm")))
|
A third module, let's name it gee , importing module foo , can see
the binding for function bar :
(module gee
(import (foo "foo.scm")))
(print (fun))
|
This feature is very useful when compiling modules exporting functions
with type annotations. In particular, one may write:
(module foo
(export (class c1 x)))
|
Then,
(module bar
(import foo)
(from foo)
(export (fun::c1)))
(define (fun)
(instantiate::c1 (x 10)))
|
And,
(module gee
(import bar)
(main main))
(define (main x)
(let ((o (fun)))
(print o)
(print (c1? o))))
|
|
load load ... | bigloo module clause |
A load is a list of the form:
<load> ==> <lclause> ...
<lclause> ==> (<module-name> <file-name>)
| <module-name>
|
This clause forces Bigloo to load the module specified in the lclause
in the environment used by the macro expansion mechanism. This means that
the user's macros can use all the bindings of all the load ed modules
but the load ed bindings remains unknown to the compiler.
If the module foo is defined by:
(module foo
(export (foo x)))
(define (foo x)
`(cons ,x ,x))
|
then,
(module gee
(load (foo "foo.scm")))
(define-macro (gee x)
`(cons ,(-fx x 1) ,(foo x)))
(gee 5) ==> (cons 4 (cons 5 5))
=> (4 5 . 5)
|
|
eval eval... | bigloo module clause |
This form allows interactions between compiled code and interpreted
code. (See the Section Eval command line options for a
presentation of compilation flags that enable compilation tuning for
eval .) Each eval has the following syntax:
<eval> ==> (export-all)
| (export-module)
| (export-exports)
| (export <bind-name>)
| (export (@ <bind-name> <module-name>))
| (import <bind-name>)
| (class <bind-name>)
| (library lib1 ...)
|
The first clause, (export-all) , exports all the variables bound
in the module (i.e., the variables defined in the module and the
imported variables). The second clause, (export-module) , exports
all the module's variables (those declared static and exported) to the
interpreter; the third exports all the exports (i.e. the ones present
inside an export clause) variables to the interpreter; the fourth
and fifth clause each export one variable to the interpreter. The last
clause imports a variable from the interpreter and all such imported
variables are immutable (i.e. they cannot be the first argument of a
set! expression with the compiled code). Variables that are
exported to the evaluators must be exported. If a variable is
exported to the evaluators but not exported within an export
clause, the compiler will produce an error message. The library
clause makes the variables and functions of a library accessible from
the interpreter.
(module foo
(export (fib x))
(eval (export fib)
(import bar)))
(define (fib x) ...)
(print bar)
|
The clause (class <bind-name>) exports a class definition to
the interpreter. This makes the class constructor, the class predicate
and the slots access functions available from the interpreter. The
form
(instantiate::class ...)
and
(with-access::class ...)
are also available from the interpreter.
|
extern extern ... | bigloo module clause |
Extern (aka foreign) clauses will be explained in the foreign interface
(see C Interface).
|
java java ... | bigloo module clause |
Java clauses will be explained in the Java interface
(see Java Interface).
|
option option ... | bigloo module clause |
This clause enables variables which affect compilation to be set from inside
a module and since the expressions, option ..., are evaluated
when compiling, no code is compiled for them. They are allowed to
make side effects and to change the values of the global variables which
describe how the compiler must compile. Usually they allow the control
variables, which are described when Bigloo is invoked with the -help2
option, to be set as in the following example:
(module examplar
(option (set! *debug* 3)
(set! *verbose* 2)))
(print 'dummy)
|
Whatever arguments are passed on the command line, Bigloo will compile this
module in both verbose mode and debug mode.
|
library library ... | bigloo module clause |
This clause enables libraries (see Bigloo Libraries) when compiling and
linking Bigloo modules. The expressions library ... are symbols
naming the libraries to be used.
Here is an example of a module declaration which makes use of a library
named format :
(module test
(library format)
(main test-format)
(import (test2 "test2.scm")))
|
Using a library does not automatically binds its variables and functions
to the interpreter. In order to make these available to the interpreter
an explicit use of an eval library clause must be used.
|
type type ... | bigloo module clause |
This forms is used to define builtin Bigloo types. It is not recommended
to use it in user programs. So, it is left undocumented.
|
3.3 Module initialization
|
Initializing a module means evaluating, at runtime, its
top level forms (global bindings are top level forms).
When a module,
module1
, imports a module,
module2
,
module2
is initialized before
module1
. Modules are
initialized only once, nothing being done if a module already met during
initialization is met again. Library modules are initialized before user
modules and imported modules are initialized in the same order as they
appear in import clauses.
Here is a first example with two modules. First the module
foo
:
;; module foo
(module foo
(main main)
(import (bar "bar.scm")))
(define (main argv)
(print "argv: " argv))
(print "foo")
|
Then the module
bar
;; module bar
(module bar)
(print "bar")
|
These can be compiled into the executable
a.out
with:
$ bigloo -c foo.scm
$ bigloo -c bar.scm
$ bigloo foo.o bar.o
|
Execution of
a.out
produces:
$ a.out
-| bar
foo
argv: (a.out)
|
The explanation is:
- module
foo
contains the program entry point so this is where
initialization begins.
- because
foo
imports module bar
, bar
must be
initialized before foo
. This explains why the word bar
is printed before anything else.
- module initialization for
foo
is completed before main
is called. This explains why word foo
is printed before main
is entered.
Let's consider another example with 3 modules:
;; module1
(module module1
(main main)
(import (module2 "module2.scm")))
(define (main argv)
(print "argv: " argv))
(print "module1")
|
The second module:
;; module2
(module module2
(import (module3 "module3.scm")))
(print "module2")
|
The third module:
;; module3
(module module3
(import (module1 "module1.scm")))
(print "module3")
|
Compile with:
$ bigloo module1.scm -c
$ bigloo module2.scm -c
$ bigloo module3.scm -c
$ bigloo module1.o module2.o module3.o
|
Execution produces:
$ a.out
-| module3
module2
module1
argv: (a.out)
|
The order of module initialization can be explicitly specified using
with
and
use
clauses.
Global variables can be referenced using implicit notation or
using
qualified notation. Implicit notation is used when
variables are referenced just by their name whereas qualified notation
is used when variables are referenced by their name and
the name of the module which defines them. Qualified notation has
the following syntax:
(@ <bind-name> <module-name>)
|
and is useful when several imported modules export a
variable with the same name. Using qualified notations instead of
short notation only affects compilation.
When several variables are defined under the same identifier, the
compiler uses the two following rules in order to decide which
variable is selected by an implicit reference: 1) the variable defined
in a module has a higher precedence than all imported variables, 2)
imported variables have a higher precedence than library variables.
Bigloo allows procedures called
inline and which differ from
normal ones only in the type of code planted. An inline procedure is a
first class object which can be manipulated in the same way as any other
procedure but when Bigloo sees a reference to one, rather than
generating a C function call to the function, the body of the inline
procedure is open-coded. The definition of an inline is given in the
following way:
define-inline (name args ...) body | bigloo syntax |
define-inline (name args ... . arg) body | bigloo syntax |
Apart from the initial word, this form has the same syntax as that used by
define for procedures. Inline procedures are exportable which means
that the compiler scans imported files to find the bodies of all inline
procedures. Here is a small example of a module which exports an inline and
a module which imports it.
;; the exporter module
(module exporter
(export (inline make-list . objs)))
(define-inline (make-list . objs) objs)
|
;; the importer module
(module importer
(import exporter))
(print (make-list 1 2 3 4 5))
|
Because of the open-coding of the exporter procedure, the above print
statement is equivalent to:
(print (let ((objs (list 1 2 3 4 5)))
objs))
|
Any procedure can be an inline. Also any exported procedure can be an inline
provided all global variables and functions it uses are also exported.
Note: Bigloo can decide to inline procedures declared with
define
but this can be achieved only with local procedures whereas procedures
declared with the define-inline form are open-coded even through
module importation.
Note: Procedures declared inline are macro expanded with
the macro defined in the module where they are invoked. That is, if
module module1 declares an inline procedure p and module
module2 imports it, p may have two different macro-expansions:
one for module1 and one for module2 .
|
Bigloo is different from languages such as C where a module is defined by a
file. For Bigloo, the module name is not necessarily the name of the file
where the text of the module is written and modules can even be split across
several files.
Since modules are defined independently of files, it is necessary to make a
link between a module and its files and there are two ways of doing this.
Choosing an import clause where the file-names are specified or creating a
``module access file''. Such a file must contain only one
list
, each
element of the list being of the form:
(module-name "file-name" ... "file-name")
Use the
-afile <file> option to specify the ``module accessfile'' when compiling. By default Bigloo checks if a file named
.afile
exists. If it exists it is loaded as a module access file.
See
The Bigloo command line.
Note: The Bigloo distribution contains a tool,
bglafile
,
that can automatically build a ``module access file''. See the manpage for
bglafile
for details.
Imported, included or loaded files are sought first in the current directory
and then in the directories, sequentially from start to end, of the list in
the
*load-path*
variable. This variable,
initially set to the empty list, can be reset by the
-I option of the
compiler.