Skip to content

Language Specification (2) : Compilation Units and Scopes

Benjamin Kowarsch edited this page Sep 7, 2020 · 10 revisions

Compilation Units and Scopes

Compilation Units

Modula-2 programs and libraries consist of one or more compilation units called modules. A program consists of exactly one program MODULE and any number of library modules. A library module consists of a definition part, called a DEFINITION MODULE, and an optional implementation part, called an IMPLEMENTATION MODULE. The definition part defines the client interface of the library. The implementation part implements the library according to the interface. The implementation part is strictly accessible through its definition part only.

Identifier Visibility

Identifiers that are predefined by the language are pervasive, that is, they are visible in every scope without import. Identifiers provided by a special built-in module are visible only within a scope into which they are explicitly imported. Identifiers defined within a definition module are visible within the definition module in which they are defined, within the corresponding implementation module and any scope into which they are imported. Identifiers declared within an implementation or program module are visible only within the scope in which they are declared.

Visibility of Constants and Aliases

Constants and aliases are visible in the scope in which they are defined or declared from the point forward where they are defined or declared. That is, they must be defined or declared before they are referenced.

Visibility of Types, Procedures and Variables

Types, procedures and variables are visible in the entire scope in which they are defined or declared. That is, they may be referenced before they are defined or declared.

Scope

Scope is a measure of the visibility of identifiers. There are three levels of scope. Global scope, module scope and local scope. Module scope is a sub-scope of global scope and local scope is a sub-scope of module scope.

Global Scope

Global scope encompasses an entire program. Only predefined identifiers have global scope.

Module Scope

Module scope encompasses a module. Identifiers that are defined or declared in, or imported into the top level of a module have module scope. Module scopes may not be nested.

Local Scope

Local scope encompasses a PROCEDURE declaration or a FOR statement. Identifiers defined or declared within a procedure or the header of a statement have local scope. Local scopes may be nested. The surrounding scope in which a local scope is nested is called the outer scope. The nested scope is called the inner scope.

Identifiers defined or declared in an outer scope are also visible in an inner scope and may be redefined within the inner scope. Redefining an identifier of an outer scope within an inner scope causes the entity denoted by the identifier to be shadowed. A shadowed entity is no longer addressable through its identifier within the scope in which it has been shadowed and within any of its sub-scopes. Identifiers that belong only to an inner scope are visible only in the inner scope and any of its sub-scopes but not in any outer scope.

Procedure Scope

Procedure scope is created by a PROCEDURE declaration.

Procedure scope overlaps with the outer scope of the procedure. The outer scope extends to the end of the pro- cedure header and continues after the end of the procedure body. The inner scope extends from the beginning of the procedure header to the end of the procedure body. The procedure header thus belongs to both the outer and the inner scope.

The procedure’s identifier is visible in both the outer and the inner scope. It may be referenced in either scope and may not be redefined in either scope. The identifiers of a procedure’s formal parameters exist in both the outer and the inner scope but are visible only within the inner scope and may not be redefined therein.

FOR Statement Scope

FOR statement scope is created by a FOR statement.

A FOR statement scope does not overlap with its outer scope. It extends from the beginning of the FOR statement’s header to the end of its body. The loop variants declared within the loop header have local scope, they are only visible within the loop.

Import and Export

Identifiers defined within a definition module are automatically exported for import and use by client modules. By contrast, program and implementation modules do not export any identifiers. An IMPORT directive may be used within any kind of module to explicitly import the identifiers exported by definition modules. A definition module does not implicitly re-export imported identifiers.

IMPORT FooLib, BarLib, BazLib;

Duplicate Import

A duplicate import is an import of a library that has already been imported into the same scope. Any such import is ignored and will cause a compile time warning.

Qualified Import

All imports are qualified. That is, an imported identifier is referenced in the importing module by a qualified identifier. A qualified identifier consists of the module identifier, followed by a period, followed by the actual identifier. Qualification prevents name conflicts between identical identifiers in different libraries.

IMPORT Flintstones, Rubbles;
...
person := Flintstones.Fred;
person.spouse := Flintstones.Wilma;
person.friend := Rubbles.Barney;
person.friend.spouse := Rubbles.Betty;

Import Aggregation

Imported modules are not implicitly re-exported but they may be explicitly re-exported. Module identifiers to be imported for automatic re-export are marked with a re-export suffix +.

import := IMPORT libIdent reExport? ( ’,’ libIdent reExport? )* ’;’ ;
alias libIdent = StdIdent ;
alias reExport = ’+’ ;

A library module that imports other modules for the sole purpose of re-export is called an import aggregator. The facility is called import aggregation. It is useful for importing multiple libraries with a single import directive.

DEFINITION MODULE CharIO;
IMPORT SoleCharIO+, ArrayOfCharIO+; END CharIO.

When a client module M imports an import aggregator which imports and re-exports modules B and C, client module M then automatically imports modules B and C.

IMPORT CharIO; VAR char : CHAR; str : ARRAY 10 OF CHAR;
...
WRITE "char: ", char; (* use of syntax bindings in SoleCharIO *)
WRITE "string: ", str; (* use of syntax bindings in ArrayOfCharIO *)

Abstract Data Type Libraries

An abstract data type library is a library that provides an abstract data type (ADT) whose identifier matches the identifier of its library module.

DEFINITION MODULE String;
TYPE String = POINTER;

The identifier of such an ADT is implicitly aliased when it is imported and may therefore be used unqualified.

IMPORT String;
VAR s : String; (* alias for String.String *)

Institution

The introduction of a name along with an associated specification of an entity is called institution. There are two kinds:

  • definition
  • declaration

A definition is an institution of interface of an entity, a declaration is an institution of implementation. However, in the case of constants, variables and types other than opaque types, interface and implementation are inseparable. For this reason, by convention, any institution within the definition part of a library module is called a definition and any institution within the implementation part of a library module is called a declaration.

Clone this wiki locally