A module is the compilation unit for Frege. It constitutes a name space for the enclosed definitions. Compiled modules can be imported from other modules to access the exported types, type classes and functions.
Note
|
Currently, all items not declared private can be accessed from other modules.
|
When module foo.A
imports module bar.B
we say that foo.A
depends on bar.B
and on all modules that bar.B
depends on. A module must not depend on itself.
A source file defines exactly one module.
A module name consists of a number of identifiers separated with dots. The last or only component must start with an uppercase letter.
Compilation of a module results in a Java class whose fully qualified name matches the module name.
module org.desperate.programmers.Foo where { ... }
will result in the following Java code:
package org.desperate.programmers; public class Foo { ... }
It is customary to use lowercase identifiers for the package part, that is, only the last component of a Frege module name should start with an uppercase letter.
Note
|
Because of the way the JVM works, it is only possible to reference classes in the unnamed package from classes that are also in the unnamed package. It is therefore not recommended to use simple module names for library modules. |
If the first component of a module name starts with an uppercase letter, that letter gets replaced with it’s lowercase associate and the extra component frege
is prepended to the module name.
import Data.List
import frege.data.List
module ::= DOCUMENTATION* moduleheader? '{' definitions+ '}' moduleheader ::= 'module' modulename 'where'
When the module header is missing, the compiler inserts
module Main where
When the module header is missing and the first token that follows the optional documentation comments is not an opening brace, the lexical analyzer will assume layout mode starting at column one.
It is sometimes desirable that compilation of a Frege module produces a class that extends another JVM class, or implements some interfaces. Usually, this requires also glue java code.
To achieve this, there is the native module
directive, that can occur as top level definition. There must be at most one such directive per module.
module-directive ::= 'native' 'module' ('type' typeApp)? ('interface' typeApp (',' typeApp)*)? 'where' '{' java code '}'
The type after the type
keyword must denote a native type. The compiler will create a class that claims to extends this type. (Hence this native type must actually be a Java class.)
The types after the interface
keyword must all denote native types. The compiler will create a class that claims to implement those interfaces.
Necessary glue code can be written in curly braces after the where
keyword. The curly braces should be given explicitly, to avoid insertion of semicolons.
The java code is parsed as a sequence of tokens that are simply replicated in code generation. Because of this, avoid the Java --
operator, as this would be interpreted as the start of a line comment.
Observe that the types to extend or implement are given as Frege types! This means, appropriate native definitions must be in scope.