Site Menu Project Specification Implementation Recommendations Reference Needs Updating Work in Progress Wastebasket Wiki Manual |
Language ReportCopyright © 2010-2015 B.Kowarsch & R.Sutcliffe. All rights reserved. Reproduction requires written permission. LexisSemanticsCompilation UnitsDefinition ModulesExportDefinitions
Implementation And Program ModulesStatements
ExpressionsOperators
Structured ValuesPredefined IdentifiersPredefined ConstantsPredefined Types
Predefined Procedures
Predefined Functions
Built-in Compile-Time MacrosPrimitivesPragmasMandatory Pragmas
Optional Pragmas
Implementation Defined Pragmas(To do: transfer missing content from PDF version and update) SemanticsCompilation UnitsA compilation unit is a sequence of source code that can be independently compiled. There are four kinds.
Any Modula-2 program consists of exactly one program module and zero or more library modules and blueprints. Program ModulesA program module represents the topmost level of a Modula-2 program. At minimum it will consist of a body that contains one or more statements that will be executed when the program is run. Additionally, it may define or declare constants, types, variables and procedures and function procedures of its own, or it may use such entities provided by one or more library modules. It does not provide any such entities to other modules. Library ModulesLibrary modules represent repositories of constants, types, variables and procedures and function procedures for use by program modules and other library modules. Entities so provided are said to be exported by the library module. Additionally, library modules may use entities provided by other library modules. In order to use the entities provided by a library module, the use of the library must be explicitly declared. A library whose use is so declared is said to be imported. The Definition Part of Library ModulesThe definition part of a library module represents the public interface of the library module. Any entities defined or declared in the public interface of a library module are automatically exported. The Implementation Part of Library ModulesThe implementation part of a library module represents the implementation of the entities defined in its public interface. Any entities defined or declared in a library's definition part are automatically visible and available in its implementation part without import. By contrast, entities declared only within the implementation part are not visible outside the implementation part. Such entities are said to be encapsulated. Library BlueprintsA library blueprint represents a specification to enforce the consistency and integrity of libraries. A blueprint defines constraints and requirements which libraries may be required to meet. A library that is required to meet the constraints and requirements of a blueprint is said to declare conformance to the blueprint. When a library declares conformance to a blueprint, its actual conformance is compiler enforced. Certain language features such as binding procedures and functions to operators and built-in syntax are only available to libraries that declare conformance to certain blueprints. Importing LibrariesQualified ImportIdentifiers defined in the interface of a library module may be imported by other modules using an Example: IMPORT FileIO; (* import of module FileIO *) VAR status : FileIO.Status; (* qualified identifier *) Import With Re-ExportBy default, an imported library is not re-exported. That is, a library A library being imported within a definition part of another library may be re-exported by marking it with a re-export tag. Such a re-export tag is denoted by a plus sign trailing the module identifier in an When a library Example: IMPORT Foo+, Bar+, Baz+; (* import and re-export Foo, Bar and Baz *) Import AggregationA library that imports other libraries for the sole purpose of re-exporting them is called an import aggregator. This facility is useful for importing a collection of libraries or a library framework with a single import statement. Example: DEFINITION MODULE FooBarBaz; IMPORT Foo+, Bar+, Baz+; END FooBarBaz. MODULE Client; IMPORT FooBarBaz; (* equivalent to: IMPORT Foo, Bar, Baz; *) Importing Modules as TypesA type defined in the definition part of a library with the same name as the library is called a module type. When a library with a module type is imported, an unqualified alias for the module type is automatically defined in the importing module. This facility is useful in the construction of abstract data types as library modules. Example: DEFINITION MODULE Colour; TYPE Colour = ( red, green, blue ); (* public interface *) END Colour. IMPORT Colour; (* import module Colour *) VAR colour : Colour; (* type referenced as Colour instead of Colour.Colour *) Unqualified AliasingAn Example: IMPORT FileIO ALIAS Status; VAR status : Status; (* unqualified alias for FileIO.Status *) Repeat ImportImport of an Already Imported ModuleImport of a module that has already been imported into the same module scope is permissible. Only the first import is significant. Any subsequent imports are redundant. A redundant import has no effect but shall cause a soft compile time warning. Unqualified Aliasing of an Already Aliased IdentifierAliasing of a qualified identifier that has already been aliased within the same module scope is permissible. Only the first aliasing is significant. Any subsequent aliasing is redundant. Redundant aliasing has no effect but shall cause a soft compile time warning. Definition ModulesA definition module represents the definition part of a library, that is, its public interface. Any identifier defined in the definition part is available for use without import in the corresponding implementation part of the library and it is automatically exported, that is, it is available for import by other modules. Example: DEFINITION MODULE Counting; PROCEDURE LetterCount ( str : ARRAY OF CHAR ) : CARDINAL; PROCEDURE DigitCount ( str : ARRAY OF CHAR ) : CARDINAL; END Counting. DefinitionsConstant DefinitionsA constant is an immutable value determined at compile time. Its value is specified by a constant expression in its definition. A constant may not be defined as an alias of a module, a variable, a type or a procedure. Examples: CONST zero = 0; maxInt = TMAX(INTEGER); buffSize = 100 * TSIZE(INTEGER) + 42; Variable DeclarationsA variable is a container for a mutable value. A variable is always associated with a type and it can only hold values of its type. Its type is specified in its definition. Its definition is immutable. The value of a variable is undetermined when it is allocated. A value may be assigned at runtime. However, variables of pointer types are automatically intialised to hold the invalid pointer value Examples: VAR ch : CHAR; n, m : CARDINAL; i, j : INTEGER; x, y, z : REAL; Global VariablesA variable declared in the top level of a module has a global life span. It exists throughout the runtime of the program. However, it does not have global scope. It is only visible within the module where it is declared, and it it is exported, within modules that import it. A variable declared in the top level of a library module's definition part is always exported immutable. It may be assigned to within the library module's implementation part but it may not be assigned to within modules that import it. A pointer variable declared in the top level of a definition part shall cause a promotable compile time warning unless it is of an opaque type or a Local VariablesA variable declared within a procedure has local life span and local scope. It only exists during the lifetime of the procedure and it is only visible within the procedure where it is declared and procedures local to the procedure where it is declared. Type Definitions
Derived TypesA derived type is a nominal derivative of another type. The type it is derived from is called its base type. The base type may be any type. A derived type obtains its properties from its base type, except for its identifier. It is defined using the Examples: TYPE Celsius = REAL; Fahrenheit = REAL; Due to strict name equivalence, derived types and their base types are incompatible because their identifiers are different. Example: VAR celsius : Celsius; fahrenheit : Fahrenheit; celsius := fahrenheit; (* compile time error: incompatible types *) To assign values across type boundaries, type conversion is required. Example: celsius := (fahrenheit :: Celsius - 32.0) * 100.0/180.0; (* type conversion *)
|
Operator | Represented Operation | Position | Arity | Associativity | Precedence |
---|---|---|---|---|---|
^ | Pointer Dereference | postfix | unary | left | 6 (highest) |
:: | Type Conversion | infix | binary | left | 5 |
NOT | Logical Negation | prefix | unary | none | 4 |
* | Multiplication, Set Intersection | infix | binary | left | 3 |
/ | Real Division, Symmetric Set Difference | infix | binary | left | 3 |
DIV | Euclidean Integer Division | infix | binary | left | 3 |
MOD | Modulus of Euclidean Integer Division | infix | binary | left | 3 |
AND | Logical Conjunction | infix | binary | left | 3 |
\ | Set Difference | infix | binary | left | 3 |
+ | Addition, Set Union | infix | binary | left | 2 |
- | Sign Inversion | prefix | unary | none | 2 |
Subtraction | infix | binary | left | 2 | |
OR | Logical Disjunction | infix | binary | left | 2 |
& | Concatenation | infix | binary | left | 2 |
= | Equality Test | infix | binary | none | 1 |
# | Inequality Test | infix | binary | none | 1 |
> | Greater-Than Test, Proper Superset Test | infix | binary | none | 1 |
>= | Greater-Than-Or-Equal Test, Superset Test | infix | binary | none | 1 |
< | Less-Than Test, Proper Subset Test | infix | binary | none | 1 |
<= | Less-Than-Or-Equal Test, Subset Test | infix | binary | none | 1 |
IN | Membership Test | infix | binary | none | 1 |
== | Identity Test | infix | binary | none | 1 |
Symbol ^
denotes the pointer dereferencing operator. It is left associative and requires one operand. The operator follows its operand.
Examples:
int := intPointer^; (* pointer dereference *) value := pointer^^; (* double pointer dereference *)
The operator always represents the pointer dereferencing operation. Its operand must be of a pointer type. Its result type is the pointer's target type. Any use of the operator with an operand that is not a pointer type shall cause a compile time error. The pointer dereferencing operator is not bindable.
Symbol ::
denotes the type conversion operator. It is left associative and requires two operands.
Examples:
real := int :: REAL; (* integer to real conversion *) bcd := real :: BCD; (* real to binary coded decimal conversion *)
The operator always represents the type conversion operation. Its left operand must be of a convertible type. Its right operand indicates the target type and must be a type identifier. Its result type is the target type. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The type conversion operator is bindable.
NOT
OperatorReserved word NOT
denotes the logical NOT
operator. It is non-associative and requires one operand. The operator precedes its operand.
Example:
inverse := NOT condition; (* logical negation *)
The operator always represents the logical negation operation. Its single operand may be any expression of type BOOLEAN
and its result type is BOOLEAN
. Any use of the operator with an operand whose type is not BOOLEAN
shall cause a compile time error. The NOT
operator is not bindable.
Symbol *
denotes a multi-purpose operator. It is left associative and requires two operands.
Examples:
product := 3.0 * 5.5; (* real multiplication *) intersect := { foo, bar, baz } * { bar, baz, bam }; (* set intersection *)
The operator represents different operations, depending on the type of its operands. If the operand type is a numeric type, it represents multiplication. If the operand type is a set type, it represents set intersection. Its operands must be type compatible. Its result type is the operand type. Any use of the operator with incompatible operand types shall cause a compile time error. The asterisk operator is bindable.
Symbol /
denotes a multi-purpose operator. It is left associative and requires two operands.
Examples:
quotient := 7.5 / 3.0; (* real division *) symDiff := { foo, bar, baz } / { bar, baz, bam }; (* symmetric set difference *)
The operator represents different operations, depending on the type of its operands. If the operand type is a numeric type, it represents real division. If the operand type is a set type, it represents symmetric set difference. Its operands must be type compatible. Its result type is the operand type. Any use of the operator with incompatible operand types shall cause a compile time error. The slash operator is bindable.
DIV
OperatorReserved word DIV
denotes the Euclidean division operator. It is left associative and requires two operands.
Example:
quotient := 7 DIV 3; (* Euclidean integer division *)
The operator always represents Euclidean integer division. Its operands must be of a whole number types and they must be type compatible. Its result type is the operand type. Any use of the operator with an operand that is not a whole number type or with incompatible operand types shall cause a compile time error. The DIV
operator is bindable.
MOD
OperatorReserved word MOD
denotes the modulus operator. It is left associative and requires two operands.
Example:
modulus := 7 MOD 3; (* Euclidean modulus *)
The operator always represents the modulus of Euclidean integer division. Its operands must be of a whole number type and they must be type compatible. Its result type is the operand type. Any use of the operator with an operand that is not a whole number type or with incompatible operand types shall cause a compile time error. The MOD
operator is bindable.
AND
OperatorReserved word AND
denotes the logical AND
operator. It is left-associative and requires two operands.
Example:
conjunction := foo AND bar; (* logical conjunction *)
The operator always represents the logical conjunction operation. Its operands must be of type BOOLEAN
and its result type is BOOLEAN
. Any use of the operator with an operand whose type is not BOOLEAN
shall cause a compile time error. The AND
operator is not bindable.
Symbol \
denotes the set difference operator. It is left associative and requires two operands.
Example:
setDiff := { foo, bar, baz } \ { baz }; (* set difference *)
The operator always represents the set difference operation. Its operands must be of a set type and they must be type compatible. Its result type is the operand type. Any use of the operator with an operand that is not a set type or with incompatible operand types shall cause a compile time error. The set difference operator is bindable.
Symbol +
denotes a multi-purpose operator. It is left associative and requires two operands.
Example:
nSum := 100 + 42; (* whole number addition *) rSum := 7.5 + 1.0; (* real number addition *) union := { foo, bar } + { baz, bam }; (* set union *)
The operator represents different operations, depending on the type of its operands. If the operand type is a numeric type, it represents addition. If the operand type is a set type, it represents set union. Its operands must be type compatible. Its result type is the operand type. Any use of the operator with incompatible operand types shall cause a compile time error. The binary plus operator is bindable.
Symbol -
denotes a multi-purpose operator. There are two variants:
The unary minus operator is non-associative and requires one operand. The operator precedes its operand.
Example:
i := -42; (* sign inversion *)
The operator always represents the sign inversion operation. Its operands must be of a signed numeric type. Its result type is the operand type. Any use of the operator with an operand that is not a signed numeric type shall cause a compile time error. The unary minus operator is bindable using the +/-
binding symbol.
The binary minus operator is left-associative and requires two operands.
Examples:
nDiff := 100 - 42; (* whole number subtraction *) rDiff := 7.5 - 1.0; (* real number subtraction *)
The operator always represents the subtraction operation. Its operands must be of numeric types and they must be type compatible. Its result type is the operand type. Any use of the operator with an operand that is not a numeric type or with incompatible operand types shall cause a compile time error. The binary minus operator is bindable.
Symbol &
denotes the concatenation operator. It is left-associative and requires two operands.
Example:
string := "foo" & "bar"; (* concatenation *)
The operator always represents the concatenation operation. Its operands must be collection types and their component types must be compatible. Its result type is the target type of the expression. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The concatenation operator is not bindable.
OR
OperatorReserved word OR
denotes the logical OR
operator. It is left-associative and requires two operands.
Example:
disjunction := foo OR bar; (* logical disjunction *)
The operator always represents the logical disjunction operation. Its operands must be of type BOOLEAN
and its result type is BOOLEAN
. Any use of the operator with an operand whose type is not BOOLEAN
shall cause a compile time error. The OR
operator is not bindable.
Symbol =
denotes the equality operator. It is non-associative and requires two operands.
Example:
isEqual := foo = bar; (* equality test *)
The operator always represents the equality test operation. Its operands may be of any type but must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The equality operator is bindable.
Symbol #
denotes the inequality operator. It is non-associative and requires two operands.
Example:
notEqual := foo # bar; (* inequality test *)
The operator always represents the inequality test operation. Its operands may be of any type but must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The inequality operator is not bindable.
>
OperatorSymbol >
denotes a dual-purpose relational operator. It is non-associative and requires two operands.
Example:
isGreater := 10 > 5; (* greater-than test *) isSuperset := { foo, bar, baz } > { foo, baz }; (* proper superset test *)
The operator represents different operations, depending on the type of its operands. If the operand type is numeric, it represents the greater-than test operation. If it is a set type, it represents the proper-superset test operation. Its operands must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The >
operator is bindable.
>=
OperatorSymbol >=
denotes a dual-purpose relational operator. It is non-associative and requires two operands.
Example:
isGreaterOrEqual := 10 >= 5; (* greater-or-equal test *) isSuperset := { foo, bar, baz } >= { foo, baz }; (* superset test *)
The operator represents different operations, depending on the type of its operands. If the operand type is numeric, it represents the greater-or-equal test operation. If it is a set type, it represents the superset test operation. Its operands must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The >=
operator is not bindable.
<
OperatorSymbol <
denotes a dual-purpose relational operator. It is non-associative and requires two operands.
Example:
isLess := 5 < 10; (* less-than test *) isSubset := { foo, baz } < { foo, bar, baz }; (* proper subset test *)
The operator represents different operations, depending on the type of its operands. If the operand type is numeric, it represents the less-than test operation. If it is a set type, it represents the proper-subset test operation. Its operands must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The <
operator is bindable.
<=
OperatorSymbol <=
denotes a dual-purpose relational operator. It is non-associative and requires two operands.
Example:
isGreaterOrEqual := 5 <= 10; (* less-or-equal test *) isSuperset := { foo, bar, baz } <= { foo, baz }; (* subset test *)
The operator represents different operations, depending on the type of its operands. If the operand type is numeric, it represents the less-or-equal test operation. If it is a set type, it represents the subset test operation. Its operands must be type compatible. Its result type is BOOLEAN
. Any use of the operator with incompatible operand types shall cause a compile time error. The <=
operator is not bindable.
IN
OperatorReserved word IN
denotes the IN
operator. It is non-associative and requires two operands.
Example:
isMember := foo IN { foo, bar, baz }; (* membership test *)
The operator always represents the membership test operation. Its right operand must be of a collection type and its left operand must be of the component type of said collection type. Its result type is BOOLEAN
. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The membership operator is bindable.
Symbol ==
denotes the identity operator. It is non-associative and requires two operands.
Example:
isEqual := foo = bar; (* equality test *)
The operator always represents the identity test operation. Its operands must be compatible pointer types. Its result type is BOOLEAN
. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The identity operator is not bindable.
A structured value is a compound value that consists of a comma separated list of value components enclosed in braces. A component value may be a value repetition clause, a value range, a literal, a structured value or an identifier denoting a value or structured value. A value repetition clause is a constant expression followed by BY
followed by a repetition factor which shall be a constant expression of a whole number type. A value range is an ordinal constant expression representing the start value followed by ..
followed by another ordinal constant expression representing the end value, both ordinal values shall be of the same type.
Examples:
{ 0 BY 100 }, { "a" .. "z" }, { 1 .. 31 } { 1970, Month.Jan, 1, 0, 0, 0.0, TZ.UTC } { "a", "bcd", 123, 456.78, { 9, 10 }, { foo, bar, baz } }
Predefined identifiers are language defined identifiers that are visible in any lexical scope without import. There are five kinds:
Invalid pointer value: NIL
Empty collection value: EMPTY
Boolean truth values: TRUE
, FALSE
Boolean type: BOOLEAN
Character types: CHAR
, UNICHAR
Unsigned whole number types: OCTET
, CARDINAL
, LONGCARD
Signed whole number types: INTEGER
, LONGINT
Real number types: REAL
, LONGREAL
INSERT
(c, ...)
inserts values or accessor/value pairs into collection c
APPEND
(c, v1, v2, v3)
appends values to the end of list or array collection c
REMOVE
(c, ...)
removes values or key/value pairs from collection c
SORT
(t, s, order)
sorts values of source collection s
into target collection t
SORTNEW
(t, s, order)
sorts values of source collection s
into newly allocated target collection t
READ
(f, x)
reads value from file or channel f
into x
READNEW
(f, x)
reads value from file or channel f
into newly allocated x
WRITE
(f, x)
writes x
unformatted to file or channel f
WRITEF
(f, fmtStr, x, ...)
writes one or more values formatted to file or channel f
TODO
(str)
prints str
to console, causes warning in DEBUG mode, or error otherwise
ABS
(x)
returns the absolute value of x
ODD
(x)
returns TRUE
if x
is an odd number
PRED
(x, n)
returns n
-th predecessor of x
SUCC
(x, n)
returns n
-th successor of x
ORD
(x)
returns the ordinal value of x
CHR
(x)
returns the character for codepoint x
EXISTS
(c, a, v)
returns TRUE
if value v
exists for accessor a
in collection c
COUNT
(c)
returns the number of values stored in collection c
LENGTH
(s)
returns length of character string s
PTR
(v, T)
returns typed pointer to variable v
if its type is compatible with T
FIRST
(c)
returns first value of ordered collection c
LAST
(c)
returns last value of ordered collection c
MIN
(v1, v2, v3 ...)
returns smallest value of a list of ordinal or scalar values
MAX
(v1, v2, v3 ...)
returns largest value of a list of ordinal or scalar values
TMIN
(T)
replaced by smallest legal value of type T
TMAX
(T)
replaced by largest legal value of type T
TLIMIT
(T)
replaced by the capacity of collection type T
TSIZE
(T)
replaced by allocation size required for type T
NIL
The constant NIL
represents an invalid pointer. It is compatible with any pointer type. Its value is defined as:
CONST NIL = 0 :: POINTER TO CONST OCTET;
Dereferencing the constant NIL
results in a compile time error. Dereferencing a pointer whose value is NIL
results in a runtime error.
EMPTY
The constant EMPTY
represents an empty collection literal. It is compatible with any collection type. Its value is defined as:
CONST EMPTY = { } | "";
TRUE
and FALSE
The constants TRUE
and FALSE
represent the values of type BOOLEAN
. Their values are defined as:
CONST TRUE = BOOLEAN.TRUE; CONST FALSE = BOOLEAN.FALSE; ORD(TRUE) = 0 ORD(FALSE) = 1
see also BOOLEAN
BOOLEAN
Type BOOLEAN
is an ordinal type for boolean algebra. All boolean expressions evaluate to type BOOLEAN
. It is defined as:
TYPE BOOLEAN = ( TRUE, FALSE ); TMIN(BOOLEAN) = BOOLEAN.TRUE TMAX(BOOLEAN) = BOOLEAN.FALSE TSIZE(BOOLEAN) = 2 (* 2 octets *)
CHAR
Type CHAR
is an ordinal type for 7-bit character values and its value range is 0u0 .. 0u7F
. It is defined as:
TYPE CHAR = ( CHR(0) .. CHR(127) ); TMIN(CHAR) = CHR(0) TMAX(CHAR) = CHR(127) TSIZE(CHAR) = 1 (* 1 octet *)
UNICHAR
Type UNICHAR
is a container type for Unicode character values. Its size is always 32-bit but its value range is 0u0 .. 0u10FFFF
. Type CHAR
is upwards compatible with UNICHAR
but the reverse is not the case. This restriction exists because every legal value of type CHAR
is also a legal value of type UNICHAR
but not every value of type UNICHAR
is also a legal value of type CHAR
.
OCTET
Type OCTET
is an unsigned whole number type that represents a storage unit of eight bits. Its parameters are:
TMIN(OCTET) = 0
TMAX(OCTET) = 255
TSIZE(OCTET) = 1 (* one octet, eight bits by definition *)
CARDINAL
Type CARDINAL
is an unsigned integer type large enough to hold any value in the range 0 to 65535 and any value of type SYSTEM.WORD
whichever is larger. The type's parameters are:
TMIN(CARDINAL) = 0
TMAX(CARDINAL) = pow(2, TSIZE(CARDINAL) * 8) - 1
TSIZE(CARDINAL) >= MAX(TSIZE(OCTET) * 2, TSIZE(WORD))
LONGCARD
Type LONGCARD
is an unsigned integer type large enough to hold the size of the largest allocatable storage area measured in octets. The type is defined as:
TMIN(LONGCARD) = 0
TMAX(LONGCARD) = pow(2, TSIZE(LONGCARD) * 8) - 1
TSIZE(LONGCARD) >= (TSIZE(ADDRESS) DIV 8)
INTEGER
Type INTEGER
is a signed integer type large enough to hold any value in the range -32768 to 32767 and any value of type SYSTEM.WORD
whichever is larger. The type is defined as:
TMIN(INTEGER) = (pow(2, TSIZE(INTEGER) * 8) DIV 2) * (-1)
TMAX(INTEGER) = (pow(2, TSIZE(INTEGER) * 8) DIV 2) - 1
TSIZE(INTEGER) = TSIZE(CARDINAL)
LONGINT
Type LONGINT
is a signed integer type large enough to hold the size of the largest allocatable storage area measured in octets. The type is defined as:
TMIN(LONGINT) = (pow(2, TSIZE(LONGINT) * 8) DIV 2) * (-1)
TMAX(LONGINT) = (pow(2, TSIZE(LONGINT) * 8) DIV 2) - 1
TSIZE(LONGINT) = TSIZE(LONGCARD)
REAL
Type REAL
is a real number type with implementation defined precision and range.
LONGREAL
Type LONGREAL
is a real number type with a precision and range equal to or higher than that of type REAL
.
No predefined type may be an ALIAS
type of another, even if the types share the same implementation.
Predefined procedures are built-in procedures that are bound to predefined identifiers visible in every scope without import.
A predefined procedure differs from a library defined procedure:
INSERT
Procedure INSERT
is a polymorphic procedure to insert one or more values or key/value pairs into an instance of a collection type. It has three signatures:
PROCEDURE INSERT ( VAR set : <SetType>; elements : ARGLIST >0 OF <ElementType> );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST >0 OF { key : <KeyType>; value : <ValueType> } );
PROCEDURE INSERT ( VAR seq : <SeqType>; atIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
APPEND
Procedure APPEND
is a polymorphic procedure to append one or more values to an instance of a collection type. It has one signature:
PROCEDURE APPEND ( VAR seq : <SeqType>; values : ARGLIST >0 OF <ValueType> );
REMOVE
Procedure REMOVE
is a polymorphic procedure to remove one or more values or all values from an instance of a collection type. It has three signatures:
PROCEDURE REMOVE ( VAR set : <SetType>; elements : ARGLIST >0 OF <ElementType> );
PROCEDURE REMOVE ( VAR dict : <DictType>; values : ARGLIST >0 OF <KeyType> } );
PROCEDURE REMOVE ( VAR seq : <SeqType>; startIndex, endIndex : <IndexType>; );
SORT
Procedure SORT
is a polymorphic procedure to sort the values of a collection and copy them into another. It has one signature:
PROCEDURE SORT ( VAR target : <TargetCollectionType>; source : <SourceCollectionType>; order : CHAR );
SORTNEW
Procedure SORTNEW
is a polymorphic procedure to initialise an immutable target collection with the sorted values of another collection. It has one signature:
PROCEDURE SORTNEW ( NEW target : <TargetCollectionType>; source : <SourceCollectionType>; order : CHAR );
READ
Procedure READ
is a polymorphic procedure to read a value from a file into a target. It has two signatures:
PROCEDURE READ ( VAR target : <TargetType> );
PROCEDURE READ ( f : FILE; VAR target : <TargetType> );
READNEW
Procedure READNEW
is a polymorphic procedure to initialise an immutable target with the contents of a file. It has two signatures:
PROCEDURE READNEW ( NEW target : <TargetType> );
PROCEDURE READNEW ( f : FILE; NEW target : <TargetType> );
WRITE
Procedure WRITE
is a polymorphic procedure to write a value to a file. It has two signatures:
PROCEDURE WRITE ( CONST source : <SourceType> );
PROCEDURE WRITE ( f : FILE; CONST source : <SourceType> );
WRITEF
Procedure WRITEF
is a polymorphic procedure for formatted writing of one or more values to a file. It has two signatures:
PROCEDURE WRITEF ( CONST fmt : ARRAY OF CHAR; CONST source : ARGLIST >0 OF <SourceType> );
PROCEDURE WRITE ( f : FILE; CONST fmt : ARRAY OF CHAR; CONST source : ARGLIST >0 OF <SourceType> );
TODO
Procedure TODO
is a dummy procedure to indicate unimplemented code. It causes a compile time warning when compiling in DEBUG mode, otherwise it causes a compile time error, either way printing a user defined compile time message. It has one signature:
PROCEDURE TODO ( msg : <StringLiteral> );
ABS
Function ABS
is a polymorphic function to return the absolute value of its operand. Unlike the mathematical definition of abs(x), the ABS
function is strictly limited to scalar operands. Its operand shall be of a scalar type. Its return type is the operand type. It has one signature:
PROCEDURE ABS ( value : <ScalarType> ) : <OperandType>;
ODD
Function ODD
is a polymorphic function to test whether its operand is odd. Its operand shall be of a whole number type. Its return type is BOOLEAN
. It returns TRUE
if its operand is odd, otherwise FALSE
. It has one signature:
PROCEDURE ODD ( value : <WholeNumberType> ) : BOOLEAN;
PRED
Function PRED
is a polymorphic function to return the n-th predecessor of its first operand, where n is the second operand, or one if it is omitted. Its first operand shall be of an ordinal type. Its second operand is of type CARDINAL
. Its return type is the first operand type. It has two signatures:
PROCEDURE PRED ( value : <OrdinalType> ) : <OperandType>;
PROCEDURE PRED ( value : <OrdinalType>; n : CARDINAL ) : <OperandType>;
SUCC
Function SUCC
is a polymorphic function to return the n-th successor of its first operand, where n is the second operand, or one if it is omitted. Its first operand shall be of an ordinal type. Its second operand is of type CARDINAL
. Its return type is the first operand type. It has two signatures:
PROCEDURE SUCC ( value : <OrdinalType> ) : <OperandType>;
PROCEDURE SUCC ( value : <OrdinalType>; n : CARDINAL ) : <OperandType>;
ORD
Function ORD
is a polymorphic function to return the ordinal value of its operand. Its operand shall be of type CHAR
or any enumeration type. Its return type is type CARDINAL
. It has one signature:
PROCEDURE ORD ( value : <CharOrEnumType> ) : CARDINAL;
CHR
Function CHR
is a polymorphic function to return the character for the code point given by its operand. Its operand shall be of type OCTET
or CARDINAL
or LONGCARD
. If the value of the operand is less than 128 then its return type is CHAR
, otherwise it is UNICHAR
. It has one signature:
PROCEDURE CHR ( codePoint : <OctetOrCardinalOrLongcard> ) : <CharOrUnichar>;
EXISTS
Function EXISTS
is a polymorphic function to test the presence of a key/value pair in a dictionary. It has three operands. Its first operand is the dictionary to be tested and it shall be of a dictionary ADT. Its second and third operands are the key and value respectively, and they shall be of the dictionary ADT's key and value types, respectively. The function returns TRUE
if the key/value pair is present, otherwise FALSE
. Its return type is type BOOLEAN
.
It returnsTRUE
if the value is present, otherwiseFALSE
. It has one signature:
PROCEDURE EXISTS ( dict : <DictionaryType>; key : <KeyType>; value : <ValueType> ) : BOOLEAN;
COUNT
Function COUNT
is a polymorphic function to return the number of values stored in its operand or the number of actual parameters passed in a formal parameter denoted by its operand. Its return type is type LONGCARD
. It has three signatures:
To obtain the number of values stored in a collection, the function is called passing the collection as a single operand. The operand shall be of a collection type.
PROCEDURE COUNT ( c : <CollectionType> ) : LONGCARD;
To obtain the number of values stored for a given key in a multi-dictionary, the function is called passing the dictionary as its first operand and the key as its second operand. The first operand shall be of a dictionary ADT. The second operand shall be of the dictionary's key type.
PROCEDURE COUNT ( c : <DictionaryType>; key : <KeyType> ) : LONGCARD;
To obtain the number of actual parameters passed to a variadic parameter list within the body of a variadic procedure, the function is called passing the designator of the variadic parameter list.
PROCEDURE COUNT ( designator : <VariadicFormalParameter> ) : LONGCARD;
LENGTH
Function COUNT
is a polymorphic function to return the number of characters stored in its operand. Its operand shall be of a CHAR
or UNICHAR
array type or a string ADT. Its return type is type LONGCARD
. It has one signature:
PROCEDURE LENGTH ( s : <CharacterStringType> ) : LONGCARD;
PTR
Function PTR
is a polymorphic function to return a typed pointer to its first operand. Its return type is given by its second operand. Its first operand shall be a variable of arbitrary type. Its second operand shall be a pointer type whose target type is the type of the first operand. If the first operand is immutable within the scope where PTR
is invoked, the second operand shall be a pointer type with immutable target. Otherwise, the second operand may be a pointer type with mutable or immutable target. The function has one signature:
PROCEDURE PTR ( v : <AnyType>; T : <TypeIdentifier> ) : <T>;
FIRST
Function FIRST
is a polymorphic function to return the first value of its operand. Its operand shall be of an ordered collection type. Its return type is the value type of the type of the first operand. It has one signature:
PROCEDURE FIRST ( c : <OrderedCollectionType> ) : <ValueType>;
LAST
Function LAST
is a polymorphic function to return the last value of its operand. Its operand shall be of an ordered collection type. Its return type is the value type of the type of the first operand. It has one signature:
PROCEDURE LAST ( c : <OrderedCollectionType> ) : <ValueType>;
MIN
Function MIN
is a polymorphic function to return the smallest value from a non-empty variadic list of operands. All its operands shall be of the same type. The operand type shall be a scalar or ordinal type. Its return type is the operand type. It has one signature:
PROCEDURE MIN ( values : ARGLIST >0 OF <ScalarOrOrdinalType> ) : <OperandType>;
MAX
Function MAX
is a polymorphic function to return the largest value from a non-empty variadic list of operands. All its operands shall be of the same type. The operand type shall be a scalar or ordinal type. Its return type is the operand type. It has one signature:
PROCEDURE MAX ( values : ARGLIST >0 OF <ScalarOrOrdinalType> ) : <OperandType>;
TMIN
An Invocation of TMIN
is replaced by the smallest legal value of its operand. Its operand shall be the type identifier of a scalar or ordinal type. Its replacement value is of the type denoted by its operand. It has one signature:
PROCEDURE TMIN ( T : <ScalarOrOrdinalTypeIdentifier> ) : <T>;
TMAX
An Invocation of TMAX
is replaced by the largest legal value of its operand. Its operand shall be the type identifier of a scalar or ordinal type. Its replacement value is of the type denoted by its operand. It has one signature:
PROCEDURE TMAX ( T : <ScalarOrOrdinalTypeIdentifier> ) : <T>;
TLIMIT
An Invocation of TLIMIT
is replaced by the capacity limit of its operand. Its operand shall be the type identifier of a collection type. Its replacement value is of type LONGCARD
. It has one signature:
PROCEDURE TLIMIT ( T : <CollectionTypeIdentifier> ) : LONGCARD;
TSIZE
An Invocation of TSIZE
is replaced by the allocation size required for an instance of a type denoted by its operand. Its operand shall be any type identifier. Its replacement value is of type LONGCARD
. It has one signature:
PROCEDURE TSIZE ( T : <TypeIdentifier> ) : LONGCARD;
to do
to do
to do
to do
to do
Primitives are built-in polymorphic macros for internal use by the compiler to synthesise various operations for library defined ADTs. They should not need to be invoked directly by library or program code since their functionality becomes available through built-in syntax. Library implementations of ADTs may be required to provide specific implementations and bind them to their respective primitives.
SXF
VAL
STORE
VALUE
SEEK
SUBSET
SXF
Primitive SXF
is a polymorphic primitive to serialise a scalar value given by its first operand to scalar exchange format and pass the serialised value back in its second operand. Its first operand shall be of a scalar type. Its second operand shall be an OCTET
array large enough to hold the serialised value. It has one signature:
PROCEDURE SXF ( CONST value : <ScalarType>; VAR sxfValue : ARRAY OF OCTET );
VAL
Primitive VAL
is a polymorphic primitive to convert a serialised scalar value given by its first operand to a value of a scalar type and pass the converted value back in its second operand. Its first operand shall be an OCTET
array. Its second operand shall be of the scalar target type. It has one signature:
PROCEDURE VAL ( CONST sxfValue : ARRAY OF OCTET; VAR value : <ScalarType> );
STORE
Primitive STORE
is a polymorphic primitive to overwrite one or more values in a collection. It has nine signatures:
To overwrite a value at a given index in an array, the primitive is called passing the array as its first operand, the index as its second operand and the value to be written as its third operand. The first operand shall be of an array type. The second operand shall be of the array type's index type. The third operand shall be of the array's value type.
PROCEDURE STORE ( c : <ArrayType>; atIndex : <IndexType>; value : <ValueType> );
To overwrite a value for a given accessor in a list, the primitive is called passing the list as its first operand, the accessor as its second operand and the value to be written as its third operand. The first operand shall be of a list type. The second operand shall be of the list type's accessor type. The third operand shall be of the list's value type.
PROCEDURE STORE ( c : <ListType>; p : <AccessorType>; value : <ValueType> );
To overwrite one or more consecutive values starting at a given index in an array or list, the primitive is called passing the array or list as its first operand, the start index as its second operand and the values to be written as its third operand. The first operand shall be of an array or list type. The second operand shall be of the array's index type or in the case of a list, it shall be of type LONGCARD
. The third operand shall be a non-empty variadic list of the value type of the array or list.
PROCEDURE STORE ( c : <SeqType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
To overwrite one or more consecutive values starting at a given index in an array or list with a fill value, the primitive is called passing the array or list as its first operand, the start index as its second operand, the number of values to be overwritten as its third operand and the fill value as its fourth operand. The first operand shall be of an array or list type. The second operand shall be of the array's index type or in case of a list, it shall be of type LONGCARD
. The third operand shall be of type LONGCARD
and the fourth operand shall be of the value type of the array or list.
PROCEDURE STORE ( c : <SeqType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
To overwrite the element counter of a given element in a set, the primitive is called passing the set as its first operand, the element as its second operand and the counter value to be written as its third operand. The first operand shall be of a set type. The second operand shall be of the set's element type. The third operand shall be of the set's counter type.
PROCEDURE STORE ( c : <SetType>; element : <ElementType>; counter : <CounterType> );
To overwrite the element counters of multiple given elements in a set, the primitive is called passing the set as its first operand and a list of element/counter pairs to be written as its second operand. The first operand shall be of a set type. The second operand shall be a non-empty variadic list of element/counter pairs, where the elements are of the set's element type and the counters are of its counter type.
PROCEDURE STORE ( c : <SetType>; entries : ARGLIST >0 OF { element : <ElementType>; counter : <CounterType> } );
To overwrite a value for a given key in a dictionary, the primitive is called passing the dictionary as its first operand, the key as its second operand and the value to be written as its third operand. The first operand shall be of a dictionary type. The second operand shall be of the dictionary's key type. The third operand shall be of the dictionary's value type.
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; value : <ValueType> );
To overwrite multiple values for given keys in a dictionary, the primitive is called passing the dictionary as its first operand and a list of key/value pairs to be written as its second operand. The first operand shall be of a dictionary type. The second operand shall be a non-empty variadic list of key/value pairs, where the keys are of the dictionary's key type and the values are of its value type.
PROCEDURE STORE ( c : <DictionaryType>; entries : ARGLIST >0 OF { key : <KeyType >; value : <ValueType> );
To overwrite the n-th value for a given key in a multi-dictionary, the primitive is called passing the dictionary as its first operand, the key as its second operand, the index of the value to be overwritten as its third operand and the value to be written as its fourth operand. The first operand shall be of a multi-dictionary type. The second operand shall be of the dictionary's key type. The third operand shall be of type CARDINAL
. The fourth operand shall be of the dictionary's value type.
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
VALUE
Primitive VALUE
is a polymorphic primitive to retrieve a value from a collection. It has five signatures:
To retrieve the value stored at a given index in an array, the primitive is called passing the array as its first operand and the index as its second operand. The first operand shall be of an array type and the second operand shall be of the array's index type. The primitive returns the value stored at the index in the array.
PROCEDURE VALUE ( VAR c : <ArrayType>; atIndex : <IndexType> ) : <ValueType>;
To retrieve the value stored at a given list element accessor from a list, the primitive is called passing the list as its firs operand and the element accessor as its second operand. The first operand shall be of a list type and the second operand shall be of the list's accessor type. The primitive returns the value stored at the accessor in the list.
PROCEDURE VALUE ( VAR c : <ListType>; p : <AccessorType> ) : <ValueType>;
To retrieve the counter for a given element in a set, the primitive is called passing the set as its first operand and the element as its second operand. The first operand shall be of a set type and the second operand shall be of the set's element type. The primitive returns a value indicating how many times the element is stored in the list.
PROCEDURE VALUE ( VAR c : <SetType>; element : <ElementType> ) : <CounterType>;
To retrieve the value stored for a given key in a dictionary, the primitive is called passing the dictionary as its first operand and the key as its second operand. The first operand shall be of a dictionary type and the second operand shall be of the dictionary's key type. The primitive returns the value stored for the key in the dictionary.
PROCEDURE VALUE ( VAR c : <DictionaryType>; key : <KeyType> ) : <ValueType>;
To retrieve the n-th value stored for a key in a multi-dictionary, the primitive is called passing the dictionary as its first operand, the key as its second operand and the index of the value to be retrieved as its third operand. The first operand shall be of a multi-dictionary type. The second operand shall be of the dictionary's key type and the third operand shall be of type CARDINAL
. The primitive returns the value stored at the index for the key in the dictionary.
PROCEDURE VALUE ( VAR c : <DictionaryType>; key : <KeyType>; index : CARDINAL ) : <ValueType>;
SEEK
Primitive SEEK
is a polymorphic primitive to obtain accessors to list elements for list traversal. It has two signatures:
To obtain a list element accessor for the n-th value stored in a list, the primitive is called passing the list as its first operand and the index as its second operand. The first operand shall be of a list type and the second operand shall be of type LONGCARD
. The primitive returns an accessor for the list element that stores the value or NIL
if no element exists at the given index.
PROCEDURE SEEK ( c : <ListType>; index : LONGCARD ) : <AccessorType>;
To obtain the preceding or succeeding list element accessor of a known accessor in a list, the primitive is called passing the list as its first operand, the known accessor as its second operand and a neighbour selector as its third operand. The first operand shall be of a list type. The second operand shall be of the list's accessor type and the third operand shall be a quoted character literal of type CHAR
where "+" selects the succeeding and "-" selects the preceding neighbour. The primitive returns an accessor to the selected neighbour element in the list or NIL
if the selected neighbour does not exist.
PROCEDURE SEEK ( c : <ListType>; current : <AccessorType>; plusOrMinus : <CharLiteral> ) : <AccessorType>;
SUBSET
Primitive SUBSET
is a polymorphic primitive to test whether a set is a subset of another. It is called passing the set to be tested as its first operand and the suspected superset as its second operand. Both operands shall be of the same set type. The primitive returns TRUE
if the first operand is a subset of the second operand, otherwise FALSE
. It has one signature:
PROCEDURE SUBSET ( subset, superset : <SetType> ) : BOOLEAN;
Pragmas are directives to the compiler, used to control or influence the compilation process, but they do not change the meaning of a program. Language defined pragmas and their properties are listed below:
Pragma | Purpose | Scope | Availability | Safety |
---|---|---|---|---|
MSG | Emit compile time console messages | Pragma | mandatory | safe |
IF | Conditional compilation, if-branch | Pragma | mandatory | safe |
ELSIF | Conditional compilation, elsif-branch | Pragma | mandatory | safe |
ELSE | Conditional compilation, else-branch | Pragma | mandatory | safe |
END | Conditional compilation, terminator | Pragma | mandatory | safe |
INLINE | Suggest procedure inlining | Procedure | mandatory | safe |
NOINLINE | Inhibit procedure inlining | Procedure | mandatory | safe |
OUT | Promise to write to a VAR parameter | Formal parameter | mandatory | safe |
GENERATED | Date/time stamp of library generation | File | mandatory | safe |
ENCODING | Specify source text character encoding | File | mandatory | safe |
ALIGN | Specify memory alignment | Module, Type, Record | optional | safe |
PADBITS | Insert padding bits into packed records | Record | optional | safe |
NORETURN | Promise never to return | Regular procedure | optional | safe |
PURITY | Specify procedure purity level | Procedure, Type | optional | safe |
SINGLEASSIGN | Mark single-assignment variable | Global and Local Var | optional | safe |
LOWLATENCY | Mark latency-critical variable | Local Vsr | optional | safe |
VOLATILE | Mark volatile variable | Global Var | optional | safe |
DEPRECATED | Mark deprecated entity | Definition, Declaration | optional | safe |
FORWARD | Forward declaration for single-pass compilers | Pragma | optional | safe |
ADDR | Map procedure or variable to fixed address | Definition, Declaration | optional | unsafe |
FFI | Specify foreign function interface | Module | optional | unsafe |
FFIDENT | Map identifier to foreign identifier | Global Var, Procedure | optional | unsafe |
The position where a pragma may appear in the source text depends on its scope.
Scope | Applies to | Insertion Point |
---|---|---|
File | entire file | at the beginning of a file or immediately after a BOM |
Module | entire module | between module header and its trailing semicolon |
Pragma | pragma itself | anywhere a block comment may appear |
Type | array or procedure type declaration | between type declaration and its trailing semicolon |
Record | insertion point forward | anywhere a fieldlist may appear within a record |
Global Var | global variable declaration | between variable declaration and its trailing semicolon |
Procedure | procedure declaration | between procedure header and its trailing semicolon |
Formal Parameter | formal parameter declaration | immediately after the formal type of the parameter |
Local Var | local variable declaration | between variable declaration and its trailing semicolon |
A pragma is safe if it provides a safe facility. It is unsafe if it provides an unsafe facility. The use of an unsafe pragma must be enabled by unqualified import of its identically named enabler. Pragma enablers of supported unsafe pragmas shall be provided by pseudo-module UNSAFE
.
MSG
Pragma MSG
emits four different types of user definable console messages during compilation: informational messages, compilation warnings, compilation error messages and fatal compilation error messages. The type of a message is determined by a message mode selector. Console messages consist of a quoted string literal, the value of a compile time constant or pragma or a comma separated list of these components.
The value of a pragma that represents a compile time setting is denoted by the pragma symbol prefixed with a question mark. Language defined pragmas that represent compile settings are ALIGN
and ENCODING
.
Examples:
<*MSG=INFO : "The current alignment is: ", ?ALIGN*> (* emits alignment value *) <*MSG=INFO : "The current encoding is: ", ?ENCODING*> (* emits encoding name *)
Only pragmas that represent compile time settings may be queried in this way.
INFO
Message mode selector INFO
is used to emit user defined information during comilation. Emitting an informational message does not change the warning or error count of the current compilation run and it does not cause comilation to fail or abort. A compiler switch may be provided to silence informational messages.
Example:
<*MSG=INFO : "Library documentation is available at http://foolib.com"*>
WARN
Message mode selector WARN
is used to emit user defined warnings during compilation. Emitting a warning message increments the warning count of the current compilation run but it does not cause compilation to fail or abort. Warnings emitted via pragma MSG
are always hard compile time warnings.
Example:
<*MSG=WARN : "foo exceeds maximum value. A default of 100 will be used."*>
ERROR
Message mode selector ERROR
is used to emit user defined error messages during compilation. Emitting an error message increments the error count of the current compilation run and will ultimately cause compilation to fail but it does not cause an immediate abort. User defined error messages may not be silenced.
Example:
<*MSG=ERROR : "Value of foo is outside of its legal range of [1..100]."*>
FATAL
Message mode selector FATAL
is used to emit user defined fatal error messages during compilation. Emitting a fatal error message increments the error count of the current compilation run and causes compilation to fail and abort immediately. User defined fatal error messages may not be silenced. Abort may not be avoided.
Example:
<*MSG=ABORT : "Unsupported target architecture."*>
Conditional compilation pragmas are used to denote conditional compilation sections. A conditional compilation section is an arbitrary portion of source text that is either compiled or ignored, depending on whether or not a given condition in form of a boolean compile time expression within the pragma is met.
A conditional compilation section consists of an initial conditional compilation branch denoted by pragma IF
, followed by zero or more alternative branches denoted by pragma ELSIF
, followed by an optional default branch denoted by pragma ELSE
, followed by closing pragma END
.
Example:
<*IF (TSIZE(INTEGER)=2)*> CONST Model = TypeModel.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = TypeModel.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = TypeModel.large; <*ELSE*> <*MSG=FATAL : "unsupported type model."*> UNSAFE.HALT(Errors.UnsupportedTypeModel); <*END*>
Conditional compilation sections may be nested up to a maximum nesting level of ten including the outermost conditional compilation section. A fatal compile time error shall occur if this value is exceeded. Pragma IF
increments the current nesting level, Pragmas ELSIF
and ELSE
leave it unchanged and Pragma END
decrements it.
IF
Pragma IF
denoted the start of the initial branch of a conditional compilation section. The source text within the initial branch is only processed if the condition specified in the pragma is true, otherwise it is ignored.
ELSIF
Pragma ELSIF
denotes the start of an alternative branch in a conditional compilation section. The source text within an alternative branch is only processed if the condition specified in the pragma is true and the conditions specified for the corresponding initial branch and all preceding alternative branches of the same nesting level are false, otherwise it is ignored.
ELSE
Pragma ELSE
denotes the start of a default branch within a conditional compilation section. The source text within the default branch is only processed if the conditions specified for the initial branch and all preceding alternative branches of the same nesting level are false, otherwise it is ignored.
END
Pragma END
denotes the end of a conditional compilation section.
INLINE
Pragma INLINE
represents a suggestion that inlining of a procedure is desirable except for certain scenarios where it is specifically mandated. It shall appear both in the definition and implementation of the procedure. An informational message shall be emitted if the suggestion is not followed.
Example:
PROCEDURE Foo ( bar : Baz ) <*INLINE*>;
Scenarios where pragma INLINE
represents a mandate to inline are procedures with a single statement, such as procedures with a single assignment and functions with a single RETURN
statement. This inline guarantee exists to promote the use of data encapsulation. Mutators and accessors tagged with an INLINE
pragma shall always be inlined.
Examples:
(* Mutator with Inline Mandate *) PROCEDURE setFoo ( value : Foo ) <*INLINE*>; BEGIN hiddenFoo := value END setFoo; (* Accessor with Inline Mandate *) PROCEDURE foo : Foo <*INLINE*>; BEGIN RETURN hiddenFoo END foo;
NOINLINE
Pragma NOINLINE
represents a mandate that a procedure shall not be inlined. It shall appear both in the definition and implementation of the procedure. The use of pragmas INLINE
and NOINLINE
is mutually exclusive.
Example:
PROCEDURE Foo ( bar : Baz ) <*NOINLINE*>;
BLOCKING
Pragma BLOCKING
marks a procedure as blocking to indicate that it invokes a procedure or API that may cause it to wait for an event or availability of a shared resource or the completion of an IO operation. If a procedure not marked as blocking calls a procedure that is marked as blocking, a promotable compile time warning shall occur.
Example:
PROCEDURE Read ( f : File; VAR ch : CHAR ) <*BLOCKING*>;
OUT
Pragma OUT
marks a formal VAR
parameter p
in the header of a procedure P
with a promise to write. The promise is kept if it can be proven at compile time that p
is written to within the body of P
in every possible runtime scenario, either by assignment or by passing p
to an OUT
marked VAR
paramter in a procedure call. A promotable soft compile time warning shall occur if the promise is not kept.
Example:
PROCEDURE init ( VAR n : OCTET <*OUT*> );
GENERATED
Pragma GENERATED
encodes the name of the template a library was generated from and the date and time when it was last generated. The pragma is inserted into the source by the Modula-2 template engine. A conforming implementation shall use the information recorded in the pragma to avoid unnecessary regeneration of libraries.
Example:
<*GENERATED FROM AssocArrays, 2014-12-31, 23:59:59+0100*>
ENCODING
Pragma ENCODING
specifies the encoding of the source file in which it appears. The pragma controls whether in addition to the characters that are permitted by the grammar, any further printable characters are permitted within quoted literals and comments. Any source file that is not strictly 7-bit ASCII encoded must contain an ENCODING
pragma to specify its encoding. Semantics are given below.
BOM | Encoding Pragma | Characters Permitted in Quoted Literals and Comments |
---|---|---|
No BOM | no encoding pragma in source | only printable 7-bit ASCII characters as per grammar |
with specifier "ASCII" | ||
with specifier "UTF8" | any printable character encodable in UTF8 | |
with implementation defined specifier | any printable character encodable in specified encoding | |
UTF8 BOM | no encoding pragma in source | only printable 7-bit ASCII characters as per grammar |
with specifier "ASCII" | ||
with specifier "UTF8" | any printable character encodable in UTF8 | |
Any other BOM | use of pragma is mandatory | any printable character encodable in specified encoding |
An implementation that supports ASCII only shall recognise encoding specifier "ASCII"
. It shall ignore any UTF8 BOM but reject any non-ASCII characters in the source file. An implementation that supports UTF8 shall recognise specifiers "ASCII"
and "UTF8"
. Support for other encodings is implementation defined. Only one encoding pragma per source file is permitted.
As an option, pragma ENCODING
may provide encoding verification. If supported, a list of arbitrary samples with pairs of quoted characters and their respective code point values may follow the encoding specifier.
If a sample list is specified within the pragma body, a verification is carried out by matching the quoted literals in the sample list against their respective code points. Any mismatching pair in the sample list shall cause a fatal compilation error and compilation to abort immediately. The maximum number of code point samples is implementation defined. A maximum of at least 16 is recommended. Excess samples shall be ignored.
Example:
<*ENCODING="UTF8" : "é"=0uE9, "©"=0uA9, "€"=0u20AC*>
ALIGN
Pragma ALIGN
controls memory alignment. Alignment is specified in octets.
When the pragma is placed in a module header, it has module scope and determines the default alignment within the module. Permitted alignment values range from one to 32 octets.
Example:
DEFINITION MODULE Foolib <*ALIGN=TSIZE(CARDINAL)*>; (* module scope *)
When the pragma is placed at the end of an array type declaration, it has array scope and determines the alignment of array components. Permitted alignment values range from one to 32 octets.
Example:
TYPE Array = ARRAY 10 OF OCTET <*ALIGN=4*>; (* array scope *)
When the pragma is placed in the body of a record type declaration, it has field list scope and determines the alignment of record fields following the pragma. Permitted alignment values range from zero to 32 octets.
Example:
TYPE Aligned = RECORD <*ALIGN=2*> foo, bar : INTEGER; (* 16 bit aligned *) <*ALIGN=4*> baz, bam : INTEGER; (* 32 bit aligned *) <*ALIGN=0*> bits, bobs : [0..15] OF OCTET (* packed *) END; (* Aligned *)
A value of zero specifies packing. When packing is specified, the allocation size of a field of an anonymous subrange of type OCTET, CARDINAL and LONGCARD is reduced to the smallest bit width required to encode its value range. Fields of any other type are aligned on octet boundaries when packing is specified.
PADBITS
Pragma PADBITS
inserts a specified number of padding bits into a packed record type declaration. The maximum permitted value is 256 bits. The pragma is only permitted where alignment is set to zero.
Example:
TYPE Packed = RECORD <*ALIGN=0*> oneBit : [0..1] OF OCTET; (* 1 bit *) <*PADBITS=2*> (* unused 2 bits *) twoBits : [0..3] OF OCTET; (* 2 bits *) threeBits : [0..7] OF OCTET; (* 3 bits *) END; (* Packed *)
NORETURN
Pragma NORETURN
marks a regular procedure with a promise never to return in any runtime scenario. A soft compile time warning shall occur if the compiler cannot prove that the promise is kept.
Example:
PROCEDURE Reboot System? <*NORETURN*>;
PURITY
Pragma PURITY
marks a procedure with an intended purity level:
• level 0 : may read and modify global state, may call procedures of any level (Default)
• level 1 : may read but not modify global state, may only call level 1 and level 3 procedures
• level 2 : may not read but modify global state, may only call level 2 and level 3 procedures
• level 3 : pure procedure, may not read nor modify global state, may only call level 3 procedures
An implementation shall emit a promotable soft compile time warning for any purity level violation.
Example:
PROCEDURE Foo ( bar : Bar) : Baz <*PURITY=3*>; (* pure and side-effect free *)
SINGLEASSIGN
Pragma SINGLEASSIGN
marks a variable as a single-assignment variable.
Such a variable should be assigned to only once in every possible runtime scenario. An implementation shall issue a promotable soft compile time warning for any single-assignment violation it may detect.
Example:
VAR foo : INTEGER <*SINGLEASSIGN*>;
LOWLATENCY
Pragma LOWLATENCY
marks a local variable as latency-critical.
Marking a variable latency-critical represents a suggestion that mapping the variable to a machine register is desirable. An informational message shall be emitted if the suggestion is not followed.
Example:
VAR foo : INTEGER <*LOWLATENCY*>;
VOLATILE
Pragma VOLATILE
marks a global variable as volatile.
By marking a variable volatile the author states that its value may change during the life time of a program even if no write access can be deduced from source code analysis. An implementation shall neither eliminate any variable so marked, nor shall it emit any unused variable warning for any variable so marked.
Example:
VAR foo : INTEGER <*VOLATILE*>;
DEPRECATED
Pragma DEPRECATED
marks a constant, variable, type or procedure as deprecated. A promotable soft com- pile time warning shall occur whenever an identifier of a deprecated entity is encountered.
Example:
PROCEDURE foo ( bar : Baz ) <*DEPRECATED*>;
FORWARD
Pragma FORWARD
shall be the only means of forward declaration in a single-pass compiler. Multi-pass compilers shall silently ignore any occurrences of pragma FORWARD
without analysis of its contents. Two kinds of forward declarations may be embedded in the pragma: Type and procedure declarations.
Example:
<*FORWARD TYPE ListNode*> TYPE ListNodePtr = POINTER TO ListNode; TYPE ListNode = RECORD data : Foo; nextNode : ListNodePtr END;
ADDR
Pragma ADDR
maps a procedure or a global variable to a fixed memory address.
Examples:
PROCEDURE Reset <*ADDR=0x12*>; VAR memoryMappedPort : CARDINAL <*ADDR=0x100*>;
FFI
Pragma FFI
marks a Modula-2 definition part as the Modula-2 interface to a library implemented in another language. Procedure definitions and type declarations in the definition part shall follow the calling convention of the specified language environment for the current target. Predefined foreign interface specifiers are “C”
, “Fortran”
, “CLR”
and “JVM”
. If pragma FFI
is provided, at least one foreign interface shall be supported. CLR or JVM support is recommended for implementations that target the CLR or JVM, respectively.
Example:
DEFINITION MODULE stdio <*FFI=“C”*>; FROM UNSAFE IMPORT FFI, VARGLIST; PROCEDURE printf ( CONST format : ARRAY OF CHAR; arglist : VARGLIST );
FFIDENT
Pragma FFIDENT
maps a Modula-2 identifier of a foreign procedure or variable definition to its respective identifier in the foreign library. It shall be used when the foreign identifier conflicts with Modula-2 reserved words or reserved identifiers. The pragma may only be used within a foreign function interface module.
Examples:
PROCEDURE Length ( s : ARRAY OF CHAR ) : INTEGER <*FFIDENT=”LENGTH”*>; VAR rwMode : [0..3] OF CARDINAL <*VOLATILE*> <*FFIDENT=”foobarlib_rw_mode”*>;
Implementation defined pragmas are compiler specific and generally non-portable.
An implementation defined pragma starts with a pragma symbol, which may be followed by a value assignment. The pragma ends with a mandatory default clause. The pragma symbol is an implementation defined name which shall be all-lowercase or mixed case. It may be qualified with an implementation prefix, indicating the name of the compiler. The value assignment follows if and only if the pragma is defined to hold a value. Such a value may be either a boolean value or a whole number.
Example:
<*GM2.UnrollLoops=TRUE|WARN*> (* turn loop-unrolling on, ignore but warn if unknown *)
The default clause specifies how the pragma shall be treated by implementations that do not recognise it. Modes INFO and WARN mandate it shall be ignored with an informational or warning message respectively. Modes ERROR and FATAL mandate it shall cause a compile time or fatal compile time error respectively.
A pragma is incorrectly used if it is malformed, misplaced or any other rule for its use is not met. Any incorrect use of a mandatory pragma or a supported optional pragma shall cause a compile time error. Use of an unsafe pragma that is not supported or has not been enabled shall cause a compile time error.
Use of a safe optional pragma that is not supported shall cause a promotable soft compile time warning. An unsupported or unrecognised encoding specifier in pragma ENCODING
shall cause a fatal compile time error. A code point sample list within pragma ENCODING
shall be ignored if encoding verification is not supported. If a code point sample list or any excess samples are ignored a soft compile time warning shall be emitted. An unsupported or unrecognised language specifier in pragma FFI
shall cause a compile time error.
An unrecognised implementation defined pragma shall be treated as specified by its default clause. An implementation defined pragma without a default clause is malformed and shall cause a compile time error.