Next: , Previous: , Up: MFL   [Contents][Index]

4.24 Modules

A module is a logically isolated part of code that implements a separate concern or feature and contains a collection of conceptually united functions and/or data. Each module occupies a separate compilation unit (i.e. file). The functionality provided by a module is incorporated into another module or the main program by requiring this module or by importing the desired components from it.


Next: , Up: Modules   [Contents][Index]

4.24.1 Declaring Modules

A module file must begin with a module declaration:

module modname [interface-type].

Note the final dot.

The modname parameter declares the name of the module. It is recommended that it be the same as the file name without the ‘.mfl’ extension. The module name must be a valid MFL literal. It also must not coincide with any defined MFL symbol, therefore we recommend to always quote it (see example below).

The optional parameter interface-type defines the default scope of visibility for the symbols declared in this module. If it is ‘public’, then all symbols declared in this module are made public (importable) by default, unless explicitly declared otherwise (see scope of visibility). If it is ‘static’, then all symbols, not explicitly marked as public, become static. If the interface-type is not given, ‘public’ is assumed.

The actual MFL code follows the ‘module’ line.

The module definition is terminated by the logical end of its compilation unit, i.e. either by the end of file, or by the keyword bye, whichever occurs first.

Special keyword bye may be used to prematurely end the current compilation unit before the physical end of the containing file. Any material between bye and the end of file is ignored by the compiler.

Let’s illustrate these concepts by writing a module ‘revip’:

module 'revip' public.

func revip(string ip)
  returns string
do
  return inet_ntoa(ntohl(inet_aton(ip)))
done

bye

This text is ignored.  You may put any additional
documentation here.

Next: , Previous: , Up: Modules   [Contents][Index]

4.24.2 Scope of Visibility

Scope of Visibility of a symbol defines from where this symbol may be referred to. Symbols in MFL may have either of the following two scopes:

Public

Public symbols are visible from the current module, as well as from any external modules, including the main script file, provided that they are properly imported (see import).

Static

Static symbols are visible only from the current module. There is no way to refer to them from outside.

The default scope of visibility for all symbols declared within a module is defined in the module declaration (see module structure). It may be overridden for any individual symbol by prefixing its declaration with an appropriate qualifier: either public or static.


Previous: , Up: Modules   [Contents][Index]

4.24.3 Require and Import

Functions or variables declared in another module must be imported prior to their actual use. MFL provides two ways of doing so: by requiring the entire module or by importing selected symbols from it.

Modules are looked up in the module search path. The default module search path consists of two directories:

  1. prefix/share/mailfromd
  2. prefix/share/mailfromd/9.0

where prefix stands for the installation prefix (normally /usr or /usr/local).

Module search path can be changed in the configuration file, using the module-path statement (see module-path), or from the command line, using the -P (--module-path) option (see --module-path).

Module Import: require modname

The require statement instructs the compiler to locate the module modname and to load all public interfaces from it.

The compiler looks for the file modname.mfl in the module search path. If no such file is found, a compilation error is reported.

For example, the following statement:

require revip

imports all interfaces from the module revip.mfl.

Another, more sophisticated way to import from a module is to use the ‘from ... import’ construct:

from module import symbols.

Note the final dot. The ‘from’ and ‘module’ statements are the only two constructs in MFL that require the delimiter.

The module has the same semantics as in the require construct. The symbols is a comma-separated list of symbol names to import from module. A symbol name may be given in several forms:

  1. Literal

    Literals specify exact symbol names to import. For example, the following statement imports from module A.mfl symbols ‘foo’ and ‘bar’:

    from A import foo,bar.
    
  2. Regular expression

    Regular expressions must be surrounded by slashes. A regular expression instructs the compiler to import all symbols whose names match that expression. For example, the following statement imports from A.mfl all symbols whose names begin with ‘foo’ and contain at least one digit after it:

    from A import '/^foo.*[0-9]/'.
    

    The type of regular expressions used in the ‘from’ statement is controlled by #pragma regex (see regex).

  3. Regular expression with transformation

    Regular expression may be followed by a s-expression, i.e. a sed-like expression of the form:

    s/regexp/replace/[flags]
    

    where regexp is a regular expression, replace is a replacement for each part of the input that matches regexp. S-expressions and their parts are discussed in detail in s-expression.

    The effect of such construct is to import all symbols that match the regular expression and apply the s-expression to their names.

    For example:

    from A import '/^foo.*[0-9]/s/.*/my_&/'.
    

    This statement imports all symbols whose names begin with ‘foo’ and contain at least one digit after it, and renames them, by prefixing their names with the string ‘my_’. Thus, if A.mfl declared a function ‘foo_1’, it becomes visible under the name of ‘my_foo_1’.


Previous: , Up: Modules   [Contents][Index]