General-Purpose Mail Filter
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.
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 ‘.mf’ 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
bye, whichever occurs first.
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
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.
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 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 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
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.
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.mf in the current search path (see include search path). If no such file is found, a compilation error is reported.
For example, the following statement:
imports all interfaces from the module revip.mf.
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
construct. The symbols is a comma-separated list of symbol
names to import from module. A symbol name may be given in
Literals specify exact symbol names to import. For example, the following statement imports from module A.mf symbols ‘foo’ and ‘bar’:
from A import foo,bar.
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.mf 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
#pragma regex (see regex).
Regular expression may be followed by a s-expression, i.e. a
sed-like expression of the form:
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.
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.mf declared a function ‘foo_1’, it becomes visible under the name of ‘my_foo_1’.
This document was generated on January 3, 2019 using makeinfo.Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.