Site Menu Project Specification Implementation Recommendations Reference Needs Updating Work in Progress Wastebasket Wiki Manual |
Language ReportSpec.LanguageReport HistoryHide minor edits - Show changes to markup 2015-10-09 22:33
by -
Changed line 704 from:
The target type of the opaque pointer is declared in the library's corresponding implementation part and it is therefore inaccessible to clients. It is declared using the to:
The target type of the opaque pointer is declared in the library's corresponding implementation part and it is therefore inaccessible to clients. It is declared using the 2015-10-09 22:05
by -
Changed line 224 from:
A blueprint defines constraints and requirements which libraries may be declared to meet. A library that promises 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. to:
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. 2015-10-08 18:53
by -
Changed line 260 from:
DEFINITION MODULE Foo Bar Baz?;
to:
DEFINITION MODULE FooBarBaz; Changed line 262 from:
END Foo Bar Baz?.
to:
END FooBarBaz. Changed line 264 from:
IMPORT Foo Bar Baz?; (* equivalent to: IMPORT Foo, Bar, Baz; *)
to:
IMPORT FooBarBaz; (* equivalent to: IMPORT Foo, Bar, Baz; *) 2015-10-08 18:52
by -
Changed lines 254-257 from:
Unqualified AliasingAn to:
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. Changed lines 260-261 from:
IMPORT FileIO ALIAS Status; VAR status : Status; (* unqualified alias for FileIO.Status *) to:
DEFINITION MODULE Foo Bar Baz?; IMPORT Foo+, Bar+, Baz+; END Foo Bar Baz?. MODULE Client; IMPORT Foo Bar Baz?; (* equivalent to: IMPORT Foo, Bar, Baz; *) Deleted lines 266-271:
Import Aggregationto do Added lines 281-289:
Unqualified AliasingAn Example: IMPORT FileIO ALIAS Status; VAR status : Status; (* unqualified alias for FileIO.Status *) 2015-10-08 18:44
by -
Changed lines 245-247 from:
An imported 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 to:
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 2015-10-08 18:34
by -
Added lines 239-249:
Import With Re-ExportBy default, an imported library is not re-exported. That is, a library An imported 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 Example: IMPORT Foo+, Bar+, Baz+; (* import and re-export Foo, Bar and Baz *) 2015-10-08 14:07
by -
Changed line 206 from:
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 announced. A library whose use is so announced is said to be imported. to:
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. 2015-10-08 14:04
by -
Changed lines 220-222 from:
BlueprintsA blueprint represents a specification to enforce the consistency and integrity of libraries. to:
Library BlueprintsA library blueprint represents a specification to enforce the consistency and integrity of libraries. 2015-10-08 14:03
by -
Changed line 218 from:
Any entities defined or declared in a library's definition part are automatically visible and available in its implementation part without import. Entities declared only within the implementation part are not visible outside the implementation part. Such entities are said to be encapsulated. to:
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. 2015-10-08 14:01
by -
Added lines 196-224:
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 announced. A library whose use is so announced 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. Entities declared only within the implementation part are not visible outside the implementation part. Such entities are said to be encapsulated. BlueprintsA blueprint represents a specification to enforce the consistency and integrity of libraries. A blueprint defines constraints and requirements which libraries may be declared to meet. A library that promises 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. 2015-10-08 09:26
by -
Changed line 2617 from:
Pragma to:
Pragma 2015-10-08 09:19
by -
Changed line 2621 from:
to:
Changed lines 2623-2624 from:
to:
Changed lines 2627-2628 from:
to:
2015-10-08 09:15
by -
Changed line 2622 from:
to:
Changed line 2625 from:
to:
Changed line 2627 from:
to:
2015-10-08 09:11
by -
Changed line 2622 from:
to:
Changed line 2625 from:
to:
Changed line 2627 from:
to:
2015-10-08 09:07
by -
Changed lines 2621-2626 from:
to:
2015-10-08 08:57
by -
Changed lines 2621-2622 from:
to:
Deleted lines 2636-2638:
to do 2015-10-08 08:43
by -
Changed line 2544 from:
Scenarios where pragma to:
Scenarios where pragma 2015-10-08 08:42
by -
Changed line 2544 from:
Scenarios where the pragma represents a mandate are mutators and accessors, also known as setter procedures and getter functions. A mutator is a procedure whose only purpose is to store a value in an encapsulated variable or record field. An accessor is a function whose only purpose is to return the value of an encapsulated variable or record field. to:
Scenarios where pragma 2015-10-08 08:32
by -
Changed lines 2544-2545 from:
Scenarios where the pragma represents a mandate are mutators and accessors, also known as setter procedures and getter functions. A mutator is a procedure whose only purpose is to store a value in an encapsulated variable or record field. An accessor is a function whose only purpose is to return the value of an encapsulated variable or record field. to:
Scenarios where the pragma represents a mandate are mutators and accessors, also known as setter procedures and getter functions. A mutator is a procedure whose only purpose is to store a value in an encapsulated variable or record field. An accessor is a function whose only purpose is to return the value of an encapsulated variable or record field. Changed line 2551 from:
foo := value (* hidden variable *) to:
hiddenFoo := value Changed line 2557 from:
RETURN foo (* hidden variable *) to:
RETURN hiddenFoo 2015-10-08 08:28
by -
Changed lines 2537-2538 from:
Pragma to:
Pragma Added lines 2544-2559:
Scenarios where the pragma represents a mandate are mutators and accessors, also known as setter procedures and getter functions. A mutator is a procedure whose only purpose is to store a value in an encapsulated variable or record field. An accessor is a function whose only purpose is to return the value of an encapsulated variable or record field. Examples: (* Mutator with Inline Mandate *) PROCEDURE setFoo ( value : Foo ) <*INLINE*>; BEGIN foo := value (* hidden variable *) END setFoo; (* Accessor with Inline Mandate *) PROCEDURE foo : Foo <*INLINE*>; BEGIN RETURN foo (* hidden variable *) END foo; 2015-10-08 08:15
by -
Changed lines 2771-2772 from:
TYPE List Node Ptr? = POINTER TO List Node?; TYPE List Node? = RECORD data : Foo; nextNode : List Node Ptr? END; to:
TYPE ListNodePtr = POINTER TO ListNode; TYPE ListNode = RECORD data : Foo; nextNode : ListNodePtr END; 2015-10-08 08:14
by -
Changed lines 2766-2773 from:
to do to:
Pragma Example: <*FORWARD TYPE List Node?*> TYPE List Node Ptr? = POINTER TO List Node?; TYPE List Node? = RECORD data : Foo; nextNode : List Node Ptr? END; 2015-10-08 08:00
by -
Changed lines 2-3 from:
Status: 2015-09-25 (update in progress) to:
Status: 2015-10-08 (update in progress) Added lines 2824-2831:
Incorrect Pragma Use and Unrecognised PragmasA 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 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. 2015-10-07 17:04
by -
Changed line 230 from:
If the interface of a module defines a type that has the same name as the module then the type is referenced unqualified. This facility is useful in the construction of abstract data types as library modules. to:
A 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. 2015-10-07 16:55
by -
Changed line 251 from:
Unqualified aliasing 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. to:
Aliasing 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. 2015-10-07 16:53
by - 2015-10-07 16:52
by -
Changed line 251 from:
Unqualified aliasing of an 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. to:
Unqualified aliasing 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. 2015-10-07 16:50
by -
Added line 227:
Changed lines 242-255 from:
Unqualified ImportWhen an identifier is imported by unqualified import, it is made available in the importing module as is. This facility is intended predominantly for import from pseudo-modules and in cases where its use will reduce clutter and improve readability. If two identically named identifiers from different modules are imported unqualified, a name conflict occurs and a compile time error shall be emitted. Example: FROM COMPILER IMPORT DEBUG; IF DEBUG THEN ... END; (* DEBUG instead of COMPILER.DEBUG *) Wildcard Importto do to:
Changed lines 245-259 from:
Qualified Import of an Already Imported ModuleQualified import of a module that has already been imported by qualified import 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 Import of an Already Imported IdentifierUnqualified import of an identifier that has already been imported unqualified from the same origin 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. Qualified and Unqualified Import of an IdentifierUnqualified import of an identifier that is also imported qualified into the same module scope is permissible. The imported entity may then be referenced both qualified and unqualified. No compile time warning shall be emitted. Unqualified Import from an Already Imported ADT Library ModuleUnqualified import of the type identifier of an ADT whole library module is also imported qualified into the same module scope results in a name conflict and shall cause a compile time error. However, unqualified import of any other identifier from an already imported ADT library module is permissible. to:
Import 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 IdentifierUnqualified aliasing of an 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. 2015-10-07 16:38
by -
Changed lines 198-199 from:
Import of Identifiersto:
Importing LibrariesQualified ImportChanged lines 212-214 from:
An to:
Unqualified AliasingAn 2015-10-07 16:34
by -
Changed lines 202-210 from:
Identifiers defined in the interface of a library module may be imported by other modules using an import directive. There are two kinds.
Qualified ImportWhen an identifier is imported by qualified import, it must be qualified with the exporting module's module identifier when it is referenced in the importing module. This avoids name conflicts when importing identically named identifiers from different modules. to:
Identifiers defined in the interface of a library module may be imported by other modules using an Changed lines 206-207 from:
IMPORT FileIO; (* qualified import of module FileIO *) VAR status : FileIO.Status; (* qualified identifier for Status *) to:
IMPORT FileIO; (* import of module FileIO *) VAR status : FileIO.Status; (* qualified identifier *) Added lines 210-218:
An Example: IMPORT FileIO ALIAS Status; VAR status : Status; (* unqualified alias for FileIO.Status *) Changed line 2632 from:
<*ENCODING="UTF8" : "é"=0uE9, "©"=0uA9, "€"=0u20AC*> to:
<*ENCODING="UTF8" : "é"=0uE9, "©"=0uA9, "€"=0u20AC*> 2015-10-07 07:06
by -
Added lines 148-149:
Added lines 160-161:
Changed lines 174-176 from:
to:
Added line 2442:
Added line 2635:
2015-10-07 06:35
by -
Changed line 2822 from:
<*G M2.Unroll Loops?=TRUE|WARN*> (* turn loop-unrolling on, ignore but warn if unknown *)
to:
<*GM2.UnrollLoops=TRUE|WARN*> (* turn loop-unrolling on, ignore but warn if unknown *) Added lines 2824-2825:
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. 2015-10-07 06:33
by -
Added lines 2809-2822:
Implementation Defined PragmasImplementation 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: <*G M2.Unroll Loops?=TRUE|WARN*> (* turn loop-unrolling on, ignore but warn if unknown *)
2015-10-06 17:04
by -
Changed line 2697 from:
Pragma PURITY marks a procedure with an intended purity level: to:
Pragma Changed lines 2714-2723 from:
to:
Pragma 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*>; Changed lines 2729-2737 from:
to:
Pragma 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*>; Changed lines 2743-2751 from:
to:
Pragma 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*>; Changed lines 2757-2763 from:
to:
Pragma Example: PROCEDURE foo ( bar : Baz ) <*DEPRECATED*>; Changed lines 2769-2770 from:
to:
to do Changed lines 2776-2783 from:
to:
Pragma Examples: PROCEDURE Reset <*ADDR=0x12*>; VAR memoryMappedPort : CARDINAL <*ADDR=0x100*>; Changed lines 2789-2797 from:
to:
Pragma Example: DEFINITION MODULE stdio <*FFI=“C”*>; FROM UNSAFE IMPORT FFI, VARGLIST; PROCEDURE printf ( CONST format : ARRAY OF CHAR; arglist : VARGLIST ); Changed lines 2803-2809 from:
to:
Pragma Examples: PROCEDURE Length ( s : ARRAY OF CHAR ) : INTEGER <*FFIDENT=”LENGTH”*>; VAR rwMode : [0..3] OF CARDINAL <*VOLATILE*> <*FFIDENT=”foobarlib_rw_mode”*>; 2015-10-06 16:51
by -
Changed lines 2685-2691 from:
to:
Pragma Example: PROCEDURE Reboot System? <*NORETURN*>;
Added lines 2697-2707:
Pragma PURITY marks a procedure with an intended purity level: Example: PROCEDURE Foo ( bar : Bar) : Baz <*PURITY=3*>; (* pure and side-effect free *) 2015-10-06 16:47
by -
Changed line 2674 from:
<*PADBITS=2*> (* unused 2 bits *) to:
<*PADBITS=2*> (* unused 2 bits *) 2015-10-06 16:46
by -
Added lines 2668-2678:
Pragma 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 *) 2015-10-04 16:00
by -
Changed line 1236 from:
to:
2015-10-04 15:59
by -
Changed lines 1234-1235 from:
to:
Deleted lines 1236-1237:
Changed lines 1363-1380 from:
Symbol
The Unary Plus OperatorThe unary plus operator is non-associative and requires one operand. The operator precedes its operand. Example: n := +42; (* arithmetic identity *) The operator always represents the arithmetic identity operation. Its operands must be of a numeric type. Its result type is the operand type. Any use of the operator with an operand that is not a numeric type shall cause a compile time error. The unary plus operator is not bindable. The Binary Plus OperatorThe binary plus operator is left-associative and requires two operands. to:
Symbol 2015-10-03 15:37
by -
Added lines 2654-2679:
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. 2015-10-03 15:28
by -
Deleted line 2416:
Added line 2425:
Added lines 2596-2597:
Added lines 2609-2610:
Added lines 2622-2623:
Changed lines 2644-2650 from:
to:
to do Optional Pragma
|
BOM | Encoding Pragma | Characters Permitted in Quoted Literals and Comments |
---|---|---|
An implementation that supports ASII 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 liter- als 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.
FORWARD
FORWARD
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 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 other than via a variable of a procedure type. A promotable soft compile time warning shall occur if the promise is not kept.
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.
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. An im- plementation shall use the information recorded in the pragma to avoid unnecessary regeneration of libraries.
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.
<*GENERATED FROM Assoc Arrays?, 2014-12-31, 23:59:59+0100*>
<*GENERATED FROM AssocArrays, 2014-12-31, 23:59:59+0100*>
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. An im- plementation shall use the information recorded in the pragma to avoid unnecessary regeneration of libraries.
Example:
<*GENERATED FROM Assoc Arrays?, 2014-12-31, 23:59:59+0100*>
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. If a procedure not marked as blocking calls a procedure that is marked as blocking, a promotable compile time warning shall occur.
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.
Pragma BLOCKING
marks a procedure as blocking to indicate that may invokes a procedure or API that may cause it to be suspended to wait for an event or availability of a shared resource. If a procedure not marked as blocking calls a procedure that is marked as blocking, a promotable compile time warning shall occur.
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. If a procedure not marked as blocking calls a procedure that is marked as blocking, a promotable compile time warning shall occur.
Pragma BLOCKING
marks a procedure as blocking.
Pragma BLOCKING
marks a procedure as blocking to indicate that may invokes a procedure or API that may cause it to be suspended to wait for an event or availability of a shared resource. 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*>;
Pragma INLINE
represents a suggestion that inlining of a procedure is desirable. 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*>;
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*>;
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 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 other than via a variable of a procedure type. A promotable soft compile time warning shall occur if the promise is not kept.
Example:
PROCEDURE init ( VAR n : OCTET <*OUT*> );
<*IF (TSIZE(INTEGER)=2)*> CONST Model = TypeModel.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = TypeModel.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = TypeModel.large;
<*IF (TSIZE(INTEGER)=2)*> CONST Model = TypeModel.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = TypeModel.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = TypeModel.large;
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.
<*IF (TSIZE(INTEGER)=2)*> CONST Model = Type Model?.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = Type Model?.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = Type Model?.large;
<*IF (TSIZE(INTEGER)=2)*> CONST Model = TypeModel.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = TypeModel.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = TypeModel.large;
UNSAFE.HALT(Errors.Unsupported Type Model?);
UNSAFE.HALT(Errors.UnsupportedTypeModel);
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, ELSIF
and ELSE
leave it unchanged and END
decrements it.
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.
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 = Type Model?.small; <*ELSIF (TSIZE(INTEGER)=4)*> CONST Model = Type Model?.medium; <*ELSIF (TSIZE(INTEGER)=8)*> CONST Model = Type Model?.large; <*ELSE*> <*MSG=FATAL : "unsupported type model."*> UNSAFE.HALT(Errors.Unsupported Type Model?); <*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, ELSIF
and ELSE
leave it unchanged and END
decrements it.
<*MSG=INFO : "Library documentation is available at `http://foolib.com"*>
<*MSG=INFO : "Library documentation is available at http://foolib.com"*>
<*MSG=INFO : "Library documentation is available at http://foolib.com"*>
<*MSG=INFO : "Library documentation is available at `http://foolib.com"*>
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."*>
INLINE
NOINLINE
OUT
GENERATED
ENCODING
FORWARD
PADBITS
NORETURN
PURITY
SINGLEASSIGN
LOWLATENCY
DEPRECATED
ADDR
FFI
FFIDENT
MSG
IF
ELSIF
ELSE
END
INLINE
NOINLINE
OUT
GENERATED
ENCODING
FORWARD
ALIGN
PADBITS
NORETURN
PURITY
SINGLEASSIGN
LOWLATENCY
VOLATILE
DEPRECATED
ADDR
FFI
FFIDENT
Global Var | global variable declaration | between variablde declaration and its trailing semicolon |
Global Var | global 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.
GENERATED | Date/time stamp of library generation | Module header | mandatory | safe |
ENCODING | Specify source text character encoding | Module header | 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, Fieldlist | optional | safe |
PADBITS | Insert padding bits into packed records | Fieldlist | optional | safe |
ALIGN | Specify memory alignment | Module, Type, Record | optional | safe |
PADBITS | Insert padding bits into packed records | Record | optional | safe |
SINGLEASSIGN | Mark single-assignment variable | VAR declaration | optional | safe |
LOWLATENCY | Mark latency-critical variable | local VAR declaration | optional | safe |
VOLATILE | Mark volatile variable | global VAR declaration | 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 |
FFI | Specify foreign function interface | Module header | optional | unsafe |
FFIDENT | Map identifier to foreign identifier | VAR , PROCEDURE | 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 variablde 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 |
IF | Conditional compilation, if-branch | Pragma | mandatory | safe |
IF | Conditional compilation, if-branch | Pragma | mandatory | safe |
ADDR | Map procedure or variable to fixed address | Definition, Declaration | optional | safe |
FFI | Specify foreign function interface | Module header | optional | safe |
FFIDENT | Map identifier to foreign identifier | VAR , PROCEDURE | optional | safe |
ADDR | Map procedure or variable to fixed address | Definition, Declaration | optional | unsafe |
FFI | Specify foreign function interface | Module header | optional | unsafe |
FFIDENT | Map identifier to foreign identifier | VAR , PROCEDURE | optional | unsafe |
to do
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 | Module header | mandatory | safe |
ENCODING | Specify source text character encoding | Module header | mandatory | safe |
FORWARD | Forward declaration for single-pass compilers | Pragma | optional | safe |
ALIGN | Specify memory alignment | Module, Type, Fieldlist | optional | safe |
PADBITS | Insert padding bits into packed records | Fieldlist | 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 | VAR declaration | optional | safe |
LOWLATENCY | Mark latency-critical variable | local VAR declaration | optional | safe |
VOLATILE | Mark volatile variable | global VAR declaration | optional | safe |
DEPRECATED | Mark deprecated entity | Definition, Declaration | optional | safe |
ADDR | Map procedure or variable to fixed address | Definition, Declaration | optional | safe |
FFI | Specify foreign function interface | Module header | optional | safe |
FFIDENT | Map identifier to foreign identifier | VAR , PROCEDURE | optional | safe |
A 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 export in the corresponding implementation part of the library and it is automatically exported, that is, it is available for import by other modules.
A 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.
PROCEDURE Letter Count? ( str : ARRAY OF CHAR ) : CARDINAL; PROCEDURE Digit Count? ( str : ARRAY OF CHAR ) : CARDINAL;
PROCEDURE LetterCount ( str : ARRAY OF CHAR ) : CARDINAL; PROCEDURE DigitCount ( str : ARRAY OF CHAR ) : CARDINAL;
to do
A 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 export 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 Letter Count? ( str : ARRAY OF CHAR ) : CARDINAL; PROCEDURE Digit Count? ( str : ARRAY OF CHAR ) : CARDINAL; END Counting.
example to paste
Example:
FROM COMPILER IMPORT DEBUG; IF DEBUG THEN ... END; (* DEBUG instead of COMPILER.DEBUG *)
An expression is a computational formula that evaluates to a value. An expression consists of operands, operators and optional punctuation.
An expression is a computational formula that evaluates to a value. An expression may consist of one of more sub-expressions. Sub-expressions consists of operands, operators and optional punctuation.
IMPORT File IO; (* qualified import of module File IO *) VAR status : File IO.Status; (* qualified identifier for Status *)
IMPORT FileIO; (* qualified import of module FileIO *) VAR status : FileIO.Status; (* qualified identifier for Status *)
Qualified import of a module that has already been imported by qualified import 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 import of an identifier that has already been imported unqualified from the same origin 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 import of an identifier that is also imported qualified into the same module scope is permissible. The imported entity may then be referenced both qualified and unqualified. No compile time warning shall be emitted.
Unqualified import of the type identifier of an ADT whole library module is also imported qualified into the same module scope results in a name conflict and shall cause a compile time error. However, unqualified import of any other identifier from an already imported ADT library module is permissible.
Identifiers defined in the interface of a library module may be imported by other modules using an import directive. There are two kinds.
When an identifier is imported by qualified import, it must be qualified with the exporting module's module identifier when it is referenced in the importing module. This avoids name conflicts when importing identically named identifiers from different modules.
Example:
IMPORT File IO; (* qualified import of module File IO *) VAR status : File IO.Status; (* qualified identifier for Status *)
If the interface of a module defines a type that has the same name as the module then the type is referenced unqualified. 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 *)
When an identifier is imported by unqualified import, it is made available in the importing module as is. This facility is intended predominantly for import from pseudo-modules and in cases where its use will reduce clutter and improve readability. If two identically named identifiers from different modules are imported unqualified, a name conflict occurs and a compile time error shall be emitted.
example to paste
to do
to do
A 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.
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 POINTER TO CONST type.
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 POINTER
TO
CONST
type.
A 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 POINTER TO CONST type.
A 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.
A variable is a container for a value determined at runtime. 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. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
A 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 NIL
.
A variable is a container for a value determined at runtime. A variable is always associated with a type and it can only hold values of its type. Its type is set at compile time and cannot be changed. The value of a variable is undetermined when it is allocated. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
A variable is a container for a value determined at runtime. 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. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
A variable is an container for a value determined at runtime. A variable is always associated with a type and it can only hold values of its type. Its type is set at compile time and cannot be changed. The value of a variable is undetermined when it is allocated. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
A variable is a container for a value determined at runtime. A variable is always associated with a type and it can only hold values of its type. Its type is set at compile time and cannot be changed. The value of a variable is undetermined when it is allocated. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
A constant is an immutable value determined at compile time. A constant may be defined as an alias of another constant, but not as an alias of a module, a variable, a type or procedure.
A 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.
CONST zero = 0; maxInt = TMAX(INTEGER); buffSize = MAX(fooLen, barLen, bazLen);
CONST zero = 0; maxInt = TMAX(INTEGER); buffSize = 100 * TSIZE(INTEGER) + 42;
to do
A variable is an container for a value determined at runtime. A variable is always associated with a type and it can only hold values of its type. Its type is set at compile time and cannot be changed. The value of a variable is undetermined when it is allocated. However, variables of pointer types are automatically intialised to hold the invalid pointer value NIL
.
Examples:
VAR ch : CHAR; n, m : CARDINAL; i, j : INTEGER; x, y, z : REAL;
to do
A constant is an immutable value determined at compile time. A constant may be defined as an alias of another constant, but not as an alias of a module, a variable, a type or procedure.
Examples:
CONST zero = 0; maxInt = TMAX(INTEGER); buffSize = MAX(fooLen, barLen, bazLen);
Operators are special symbols or reserved words that represent an operation within an expression. An operator may be unary or binary. Unary operators are prefix or postfix, binary operators are always infix. An operator may be either left-associative or non-associative and it has a precedence level between one and six, where six represents the highest level. Arity, associativity and precedence determine the order of evaluations in expressions that consist of multiple sub-expressions and may contain different operators.
Operators are special symbols or reserved words that represent an operation within an expression. An operator may be unary or binary. Unary operators are prefix or postfix, binary operators are always infix. An operator may be either left-associative or non-associative and it has a precedence level between one and six, where six represents the highest level. Arity, associativity and precedence determine the order of evaluation in expressions that consist of multiple sub-expressions and may contain different operators.
Grammar rule expression represents evaluation level one. Its operands are simple expressions. Its operators are the relational operators and the identity operator. Level one has the lowest precedence.
Expressions are evaluated at precedence level one. Its sub-expressions are simple expressions. Its operators are the relational operators and the identity operator. Level one has the lowest precedence.
Grammar rule simple expression represents evaluation level two. Its operands are terms. Its operators are the plus and minus operators and the OR
operator.
Simple expressions are evaluated at precedence level one. Its sub-expressions are terms. Its operators are the plus and minus operators and the OR
operator.
Grammar rule term represents evaluation level three. Its operands are simple terms. Its operators are the asterisk, solidus, DIV
, MOD
, AND
operators and the set difference operator.
Terms are evaluated at precedence level three. Its sub-expressions are simple terms. Its operators are the asterisk, solidus, DIV
, MOD
, AND
operators and the set difference operator.
Grammar rule simple term represents evaluation level four. Its operand is a factor and its operator is the NOT
operator.
Simple terms are evaluated at precedence level four. Its sub-expressions are factors and its operator is the NOT
operator.
Grammar rule factor represents evaluation level five. Its operand is a simple factor and its operator is the type conversion operator.
Factors are evaluated at precedence level five. Its sub-expressions are simple factors and its operator is the type conversion operator.
Grammar rule simple factor represents evaluation level six. It consists of literals, structured values, expressions in parentheses, designators and function calls. Its pseudo-operators are the parentheses of parenthesised expressions and the selectors of designators. Level six has the highest precedence.
Simple factors are evaluated at precedence level six. Its sub-expressions are literals, structured values, expressions in parentheses, designators and function calls. Its pseudo-operators are the parentheses of parenthesised expressions and the selectors of designators. Level six has the highest precedence.
to do
Grammar rule expression represents evaluation level one. Its operands are simple expressions. Its operators are the relational operators and the identity operator. Level one has the lowest precedence.
to do
Grammar rule simple expression represents evaluation level two. Its operands are terms. Its operators are the plus and minus operators and the OR
operator.
to do
Grammar rule term represents evaluation level three. Its operands are simple terms. Its operators are the asterisk, solidus, DIV
, MOD
, AND
operators and the set difference operator.
to do
Grammar rule simple term represents evaluation level four. Its operand is a factor and its operator is the NOT
operator.
to do
Grammar rule factor represents evaluation level five. Its operand is a simple factor and its operator is the type conversion operator.
to do
Grammar rule simple factor represents evaluation level six. It consists of literals, structured values, expressions in parentheses, designators and function calls. Its pseudo-operators are the parentheses of parenthesised expressions and the selectors of designators. Level six has the highest precedence.
A selector is a syntactical entity to select one or more components from a value. There are four kinds.
A selector is a suffix to select one or more components from a value. There are four kinds.
to do
to do
to do
to do
to do
to do
An operand may be a literal, a designator or a sub-expression. Whether any given operand may legally occur at a given position within an expression is determined by expression compatibility. Expression compatibility of operands is dependent on the operator of an expression or sub-expression as each operator defines what operand types it can accept.
A designator consists of an identifier that refers to a constant, a variable or a function call, followed by an optional designator tail that consists of one or more selectors. The identifier component of a designator may be a qualified identifier.
A selector is a syntactical entity to select one or more components from a value. There are four kinds.
to do
to do
to do
to do
to do
An expression is a computational formula that evaluates to a value. An expression consists of operands, operators and optional punctuation.
Expressions are classified according to their time of evaluation. An expression that may only be evaluated at runtime is called a runtime expression. An expression that is evaluated at compile time is called a compile time expression or constant expression. Constant expressions consist only of operands whose values are known at compile time and only invoke built-in functions or macros that may be evaluated at compile time.
The evaluation order of expressions is determined by operator precedence and punctuation. There are five levels of operator precedence. However, sub-expressions enclosed in parentheses, designators and function calls always take precedence over the evaluation order defined by operator precedence. This constitutes an implicit sixth level of expression evaluation.
The FOR
statement is used to iterate over an iterable entity and execute a statement or statement sequence during each iteration cycle. It consists of a loop header and a loop body. The loop header consists of one or two loop variants, an optional iteration order, and the iterable entity. The loop body consists of a statement or statement sequence.
The FOR
statement is used to iterate over an iterable entity and execute a statement or statement sequence during each iteration cycle. It consists of a loop header and a loop body. The loop header consists of one or two loop variants, an optional iteration order, and the iterable expression. The loop body consists of a statement or statement sequence.
The iterable entity — or iterable in short – is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. An ordinal type or subrange iterable is always immutable. A collection iterable may be either mutable or immutable.
The iterable expression — or iterable in short – is denoted by a designator if an instance of a collection type or by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type. An ordinal type or subrange iterable is always immutable. A collection iterable may be either mutable or immutable.
An immutable type is an immutable subtype of a mutable type. The type it is a subtype of is called its supertype. The supertype may be any dynamically allocatable ADT provided that it is not an immutable subtype itself. An immutable type obtains its properties from its supertype, except for its identifier. It is defined using the CONST
type constructor.
An immutable type is an immutable equivalence type of a mutable type. The type it is an equivalence type of is called its base type. The base type may be any dynamically allocatable ADT provided that it is not an immutable equivalence type itself. An immutable type obtains its properties from its base type, except for its identifier. It is defined using the CONST
type constructor.
An immutable type is compatible with its supertype. Any value of an immutable type is also a legal value of its supertype and vice versa. However, instances of an immutable type are immutable, they may not be L-values except for initialisation in a NEW
statement and they may not be passed to a formal VAR
parameter.
An immutable type is compatible with its base type. Any value of an immutable type is also a legal value of its base type and vice versa. However, instances of an immutable type are immutable, they may not be L-values except for initialisation in a NEW
statement and they may not be passed to a formal VAR
parameter.
An ALIAS
type is a nominal sub-type of another type. The type it is a sub-type of is called its base type. The base type may be any type. An ALIAS
type obtains its properties from its base type, except for its identifier. It is defined using the ALIAS
OF
type constructor.
An ALIAS
type is a nominal equivalence type of another type. The type it is an equivalence type of is called its base type. The base type may be any type. An ALIAS
type obtains its properties from its base type, except for its identifier. It is defined using the ALIAS
OF
type constructor.
An immutable type is compatible with its supertype, except where such compatibility would violate the subtype's immutability. Any value of an immutable type is also a legal value of its supertype and vice versa. However, instances of an immutable type are immutable, they may not be L-values except for initialisation in a NEW
statement and they may not be passed to a formal VAR
parameter.
An immutable type is compatible with its supertype. Any value of an immutable type is also a legal value of its supertype and vice versa. However, instances of an immutable type are immutable, they may not be L-values except for initialisation in a NEW
statement and they may not be passed to a formal VAR
parameter.
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
A 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 =
symbol followed by the base type in the type constructor.
An ALIAS
type is a derived type specifically defined to be compatible with its base type even though their identifiers are different. An ALIAS
type is defined using the ALIAS
OF
type constructor.
An ALIAS
type is a nominal sub-type of another type. The type it is a sub-type of is called its base type. The base type may be any type. An ALIAS
type obtains its properties from its base type, except for its identifier. It is defined using the ALIAS
OF
type constructor.
A subrange type is a type defined as a subset of a scalar or ordinal type. A subrange type is upwards compatible with its base type, but the base type is not downwards compatible with any subrange types derived from it. A subrange type inherits all its properties from its base type, except for its lower and upper bound. A subrange type's lower and upper bound must be specified in its type definition. Both lower and upper bound must be compatible with the base type and they must be legal values of the base type.
An immutable type is an immutable subtype of a mutable type. The type it is a subtype of is called its supertype. The supertype may be any dynamically allocatable ADT provided that it is not an immutable subtype itself. An immutable type obtains its properties from its supertype, except for its identifier. It is defined using the CONST
type constructor.
Examples:
TYPE Radian = [0.0 .. tau] OF REAL; TYPE Natural = [1 .. TMAX(CARDINAL)] OF CARDINAL;
Example:
TYPE ImmutableFooArray = CONST FooArray;
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol. An open bound of a subrange type is not a legal value of the type.
An immutable type is compatible with its supertype, except where such compatibility would violate the subtype's immutability. Any value of an immutable type is also a legal value of its supertype and vice versa. However, instances of an immutable type are immutable, they may not be L-values except for initialisation in a NEW
statement and they may not be passed to a formal VAR
parameter.
Examples:
TYPE PosReal = [>0.0 .. TMAX(REAL)] OF REAL; TYPE NegReal = [TMIN(REAL) .. <0.0] OF REAL;
Example:
VAR array : FooArray; immArray : ImmutableFooArray; NEW array; (* initialisation not required *) NEW immArray := { foo, bar, baz }; (* initialisation required *) COPY array := immArray; (* copying from immutable to mutable *) COPY immArray := array; (* compile time error: attempt to modify immutable instance *)
A CONST
type is a type defined to be an immutable alias type of a mutable ADT. A CONST
type is defined using the CONST
type constructor.
A subrange type is a subtype of a scalar or ordinal type. The type it is a subtype of is called its supertype. The supertype may be any scalar or ordinal type. A subrange type obtains its properties from its supertype, except for its identifier, and its lower and upper bounds. Both lower and upper bound must be specified in its type definition and they must be legal values of the supertype. A subrange type is defined using a range constructor.
Example:
TYPE ImmutableFooArray = CONST FooArray;
Examples:
TYPE Radian = [0.0 .. tau] OF REAL; TYPE Natural = [1 .. TMAX(CARDINAL)] OF CARDINAL;
A CONST
type is compatible with its base type, except where such compatibility would violate the type's immutability.
A subrange type is upwards compatible with its supertype, but the supertype is not downwards compatible with all of its subrange types. This restriction exists because any value of a subrange type is always a legal value of its supertype, but a value of a supertype is not necessarily a legal value of its subrange type.
Example:
VAR array : FooArray; immArray : ImmutableFooArray; NEW array; (* initialisation not required *) NEW immArray := { foo, bar, baz }; (* initialisation required *) COPY array := immArray; (* copying from immutable to mutable *) COPY immArray := array; (* compile time error: attempt to modify immutable instance *)
Examples:
VAR natural : Natural; cardinal : CARDINAL; natural := cardinal; (* compile time error *) cardinal := natural; (* OK *)
The subrange type definition of a scalar type that represents real numbers may specify open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol. An open bound of a subrange type is not a legal value of the subrange type.
Examples:
TYPE PosReal = [>0.0 .. TMAX(REAL)] OF REAL; TYPE NegReal = [TMIN(REAL) .. <0.0] OF REAL;
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
ALIAS
TypesALIAS
TypesNEW
StatementNEW
StatementRETAIN
StatementRETAIN
StatementRELEASE
StatementRELEASE
StatementCOPY
StatementCOPY
StatementRETURN
StatementRETURN
StatementYIELD
StatementYIELD
StatementIF
StatementIF
StatementCASE
StatementCASE
StatementWHILE
StatementWHILE
StatementREPEAT
StatementREPEAT
StatementLOOP
StatementLOOP
StatementFOR
StatementFOR
StatementCHAR
TypeCHAR
TypeEXIT
StatementEXIT
StatementNOT
OperatorNOT
OperatorDIV
OperatorDIV
OperatorMOD
OperatorMOD
OperatorAND
OperatorAND
OperatorOR
OperatorOR
Operator>
Operator>
Operator>=
Operator>=
Operator<
Operator<
Operator<=
Operator<=
OperatorIN
OperatorIN
OperatorNIL
NIL
EMPTY
EMPTY
TRUE
and FALSE
TRUE
and FALSE
BOOLEAN
BOOLEAN
CHAR
CHAR
UNICHAR
UNICHAR
OCTET
OCTET
CARDINAL
CARDINAL
LONGCARD
LONGCARD
INTEGER
INTEGER
LONGINT
LONGINT
REAL
REAL
LONGREAL
LONGREAL
Older Wiki content, parts of which may be reused:
(To do: enter from PDF version and update)
(To do: transfer missing content from PDF version and update)
(To do: move and merge content)
Older Wiki content, parts of which may be reused:
Type CHAR
is an ordinal type for 7-bit character values. It is defined as:
Type CHAR
is an ordinal type for 7-bit character values and its value range is 0u0 .. 0u7F
. It is defined as:
Type UNICHAR
is a container type for Unicode character values. Its size is always 32-bit. 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
.
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
.
TO DO
Type REAL
is a real number type with implementation defined precision and range.
TO DO
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.
A structured value is a compound value that consist 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.
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.
to do
A structured value is a compound value that consist 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 } }
IF
StatementAn IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. At most one block in the statement is executed. IF
-statements must always be terminated with an END
.
RETURN
StatementThe RETURN
statement is used within a procedure body to return control to its caller and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance shall cause a compile time error.
IF i > 0 THEN WRITE("Positive") ELSIF i = 0 THEN WRITE("Zero") ELSE WRITE("Negative") END;
PROCEDURE successor ( n : CARDINAL ) : CARDINAL; BEGIN RETURN n + 1 END successor;
CASE
StatementA CASE
statement is a flow-control statement that passes control to one of a number of labeled statements or statement sequences depending on the value of an ordinal expression. Control is passed to the first statement following the case label that matches the ordinal expression. If no label matches, control is passed to the ELSE
block.
YIELD
StatementThe YIELD
statement is used within a coroutine procedure body to suspend the coroutine and pass control to its caller. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When yielding from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance shall cause a compile time error.
CASE colour OF | colour.red : WRITE("Red") | colour.green : WRITE("Green") | colour.blue : WRITE("Blue") ELSE UNSAFE.HALT(1) (* fatal error -- abort *) END;
PROCEDURE [COROUTINE] iterator ( CONST array : ARRAY OF INTEGER ) : INTEGER; BEGIN FOR value IN array DO YIELD value END; RETURN -1 END iterator;
A case label shall be listed at most once. If a case is encountered at runtime that is not listed in the case label list and if there is no ELSE
block, no case label statements shall be executed and no error shall result.
WHILE
StatementA WHILE
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time before the DO
block is executed. The DO
block is repeated as long as the expression evaluates to TRUE
.
IF
StatementAn IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. At most one block in the statement is executed. IF
-statements must always be terminated with an END
.
WHILE NOT EOF(file) DO READ(file, ch) END;
IF i > 0 THEN WRITE("Positive") ELSIF i = 0 THEN WRITE("Zero") ELSE WRITE("Negative") END;
REPEAT
StatementA REPEAT
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time after the REPEAT
block has executed. the expression evaluates to TRUE
the REPEAT
block is executed, otherwise not.
CASE
StatementA CASE
statement is a flow-control statement that passes control to one of a number of labeled statements or statement sequences depending on the value of an ordinal expression. Control is passed to the first statement following the case label that matches the ordinal expression. If no label matches, control is passed to the ELSE
block.
REPEAT READ(file, ch) UNTIL ch = terminator END;
CASE colour OF | colour.red : WRITE("Red") | colour.green : WRITE("Green") | colour.blue : WRITE("Blue") ELSE UNSAFE.HALT(1) (* fatal error -- abort *) END;
LOOP
StatementA LOOP
statement is used to repeat a statement or statement sequence indefinitely unless explicitly terminated by an EXIT
statement.
A case label shall be listed at most once. If a case is encountered at runtime that is not listed in the case label list and if there is no ELSE
block, no case label statements shall be executed and no error shall result.
WHILE
StatementA WHILE
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time before the DO
block is executed. The DO
block is repeated as long as the expression evaluates to TRUE
.
LOOP READ(file, ch); IF ch IN TerminatorSet THEN EXIT END (* IF *) END; (* LOOP *)
WHILE NOT EOF(file) DO READ(file, ch) END;
REPEAT
StatementA REPEAT
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time after the REPEAT
block has executed. the expression evaluates to TRUE
the REPEAT
block is executed, otherwise not.
Example:
REPEAT READ(file, ch) UNTIL ch = terminator END;
LOOP
StatementA LOOP
statement is used to repeat a statement or statement sequence indefinitely unless explicitly terminated by an EXIT
statement.
Example:
LOOP READ(file, ch); IF ch IN TerminatorSet THEN EXIT END (* IF *) END; (* LOOP *)
RETURN
StatementThe RETURN
statement is used within a procedure body to return control to its caller and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance shall cause a compile time error.
Example:
PROCEDURE successor ( n : CARDINAL ) : CARDINAL; BEGIN RETURN n + 1 END successor;
YIELD
StatementThe YIELD
statement is used within a coroutine procedure body to suspend the coroutine and pass control to its caller. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When yielding from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance shall cause a compile time error.
Example:
PROCEDURE [COROUTINE] iterator ( CONST array : ARRAY OF INTEGER ) : INTEGER; BEGIN FOR value IN array DO YIELD value END; RETURN -1 END iterator;
An opaque record type is a record type with export restricted fields. An export restricted field is a field that is directly accessible only within the library module in which the type is defined and within any extension library thereof. It is not directly accessible within any other scope. Such a field is declared by prefixing the field declaration with the *
symbol.
An opaque record type is a record type whose identifier is available to client modules that import it but its fields are not. Such a record type is defined with exported restricted fields. An export restricted field is a field that is directly accessible only within the library module in which the type is defined and within any extension library thereof. It is not directly accessible within any other scope. Such a field is declared by prefixing the field declaration with the *
symbol.
An opaque record type is a record type with export restricted fields, used for the construction of ADTs. An export restricted field is a field that is directly accessible only within the library module in which the type is defined and within any extension library thereof. It is not directly accessible within any other scope. An export restricted field is declared by prefixing its declaration with the *
symbol.
An opaque record type is a record type with export restricted fields. An export restricted field is a field that is directly accessible only within the library module in which the type is defined and within any extension library thereof. It is not directly accessible within any other scope. Such a field is declared by prefixing the field declaration with the *
symbol.
Since all record fields are lexically present within the definition part, the allocation size of an opaque record type can be calculated at compile time even when no source code is available for the corresponding implementation part. Instances of opaque record based ADTs are therefore statically allocatable.
Since all record fields are lexically present within the definition part, the allocation size of an opaque record type can be determined at compile time even when no source code is available for the corresponding implementation part. Instances of opaque record types are therefore statically allocatable.
Since export restricted fields are not directly accessible outside their defining library, they may only be operated on by clients through facilities provided in the library's public interface.
Any attempt to access a restricted field within a scope where it is not accessible shall cause a compile time error.
A record type may contain both public and export restricted fields. Such a record is called semi-opaque.
A record type may contain both public and export restricted fields. Such a record type is called semi-opaque.
A record type may contain both public and export restricted fields. Such a record is called semi-opaque or partially opaque.
A record type may contain both public and export restricted fields. Such a record is called semi-opaque.
When an instance of a semi-opaque record type is assigned a structured value, the structured value may only contain values for public fields.
When a structured value is assigned to an instance of a semi-opaque record type, it may only contain values for public fields.
Semi-opaque record based AD Ts? should be designed such that restricted fields of instances are auto-initialised.
Example:
TYPE SemiOpaque = RECORD * i : INTEGER = 0; (* auto-initialising restricted field *) j, k : INTEGER (* public fields *) END;
It is safe practise to declare the restricted fields of semi-opaque record types with an initialisation expression.
len := Pascal String?.Length(str); (* proper use: access via public interface *)
len := PascalString.Length(str); (* proper use: access via public interface *)
DEFINITION MODULE PascalString;
TYPE Semi Opaque? = RECORD
TYPE SemiOpaque = RECORD
VAR triplet : Semi Opaque?;
VAR triplet : SemiOpaque;
TYPE Semi Opaque? = RECORD
* i : INTEGER = 0; (* restricted field *)
TYPE SemiOpaque = RECORD * i : INTEGER = 0; (* auto-initialising restricted field *)
* length : OCTET = 0; (* export restricted field *) * data : ARRAY 255 OF OCTET (* export restricted field *)
* length : OCTET; (* export restricted field *) * data : OctetArray255 (* export restricted field *)
Fields that are not export restricted are directly accessible in any scope into which an opaque record type has been imported, but export restricted fields are only accessible within the implementation part and extension modules of the library that defines the opaque record type. Export restricted fields may only be operated on by clients through facilities provided in the library's public interface.
Since export restricted fields are not directly accessible outside their defining library, they may only be operated on by clients through facilities provided in the library's public interface.
VAR str : PascalString; str.length := 5; (* compile time error: access of a restricted field *) Terminal.WriteOctets(str.data); (* compile time error: access of a restricted field *) PascalString.copy(str, "foobar"); (* proper use: operation through public interface *)
VAR str : PascalString; len : OCTET;
len := str.length; (* compile time error: access of a restricted field *)
len := Pascal String?.Length(str); (* proper use: access via public interface *)
Export restricted fields may be automatically initialised for every instance of the type by suffixing the field declaration with an initialisation expression. The initialisation expression shall be a compile time expression of the type of the field.
Example:
DEFINITION MODULE PascalString; TYPE PascalString = RECORD * length : OCTET = 0; (* auto-initialisation to zero *) * data : OctetArray255 END;
A record type may contain both public and export restricted fields. Such a record is called semi-opaque or partially opaque.
Example:
TYPE Semi Opaque? = RECORD
* i : INTEGER; (* restricted field *)
j, k : INTEGER (* public fields *)
END;
When an instance of a semi-opaque record type is assigned a structured value, the structured value may only contain values for public fields.
Example:
VAR triplet : Semi Opaque?;
triplet := { 0, 0, 0 }; (* compile time error: access of a restricted field *)
triplet := { 0, 0 }; (* proper use: only public fields are written to *)
Semi-opaque record based AD Ts? should be designed such that restricted fields of instances are auto-initialised.
Example:
TYPE Semi Opaque? = RECORD
* i : INTEGER = 0; (* restricted field *)
j, k : INTEGER (* public fields *)
END;
One or more fields in a record type declaration may be export restricted by prefixing their declaration with the *
symbol. An export restricted field is only accessible within the library module in which the record type is defined and any extension library thereof.
An instance of a record type holds exactly one value for each field. Fields are addressable by selector using dot notation.
Example:
TYPE Point = RECORD * typeID : UniqueTypeID; (* export restricted field *) x, y : REAL (* publicly accessible fields *) END;
An instance of a record type holds exactly one value for each field. Fields are addressable by selector using dot notation.
An opaque record type is a record type with export restricted fields. It is used for the construction of ADTs.
An opaque record type is a record type with export restricted fields, used for the construction of ADTs. An export restricted field is a field that is directly accessible only within the library module in which the type is defined and within any extension library thereof. It is not directly accessible within any other scope. An export restricted field is declared by prefixing its declaration with the *
symbol.
* length : OCTET; (* export restricted field *)
* length : OCTET = 0; (* export restricted field *)
str.length := 0; (* compile time error: access of a restricted field *)
str.length := 5; (* compile time error: access of a restricted field *)
One or more fields in a record type declaration may be export restricted by prefixing their declaration with the *
symbol. An export restricted field is only accessible within the library module in which the record type is defined and any extension library thereof.
Example:
TYPE Point = RECORD * typeID : UniqueTypeID; (* export restricted field *) x, y : REAL (* publicly accessible fields *) END;
Since all fields are lexically present within the definition part, the allocation size of an opaque record type can be calculated even when no source code is available for the corresponding implementation part. Instances of opaque record based ADTs are therefore statically allocatable.
Since all record fields are lexically present within the definition part, the allocation size of an opaque record type can be calculated at compile time even when no source code is available for the corresponding implementation part. Instances of opaque record based ADTs are therefore statically allocatable.
Fields that are not export restricted are directly accessible in any scope into which an opaque record type has been imported, but export restricted fields are only accessible within the implementation part and extension modules of the library that defines the opaque record type. They may only be operated on by clients through facilities provided in the library's public interface.
Fields that are not export restricted are directly accessible in any scope into which an opaque record type has been imported, but export restricted fields are only accessible within the implementation part and extension modules of the library that defines the opaque record type. Export restricted fields may only be operated on by clients through facilities provided in the library's public interface.
* length : OCTET; * data : ARRAY 255 OF OCTET (* export restricted *)
* length : OCTET; (* export restricted field *) * data : ARRAY 255 OF OCTET (* export restricted field *)
DEFINITION MODULE Pascal String?; TYPE Pascal String? = RECORD
DEFINITION MODULE PascalString; TYPE PascalString = RECORD
END Pascal String?.
END PascalString.
IMPORT Pascal String?; VAR str : Pascal String?; (* allocated on the stack *)
IMPORT PascalString; VAR str : PascalString; (* allocated on the stack *)
IMPORT Pascal String?; VAR str : Pascal String?;
IMPORT PascalString; VAR str : PascalString;
Terminal.Write Octets?(str.data); (* compile time error: access of a restricted field *) Pascal String?.copy(str, "foobar"); (* proper use: operation through public interface *)
Terminal.WriteOctets(str.data); (* compile time error: access of a restricted field *) PascalString.copy(str, "foobar"); (* proper use: operation through public interface *)
An instance of a record type holds exactly one value for each field. Fields are addressable by selector.
An instance of a record type holds exactly one value for each field. Fields are addressable by selector using dot notation.
An opaque record type is a record type with export restricted fields. It is used for the construction of ADTs.
Example:
DEFINITION MODULE Pascal String?; TYPE Pascal String? = RECORD * length : OCTET; * data : ARRAY 255 OF OCTET (* export restricted *) END; (* public interface *) END Pascal String?.
Since all fields are lexically present within the definition part, the allocation size of an opaque record type can be calculated even when no source code is available for the corresponding implementation part. Instances of opaque record based ADTs are therefore statically allocatable.
Example:
IMPORT Pascal String?; VAR str : Pascal String?; (* allocated on the stack *)
Fields that are not export restricted are directly accessible in any scope into which an opaque record type has been imported, but export restricted fields are only accessible within the implementation part and extension modules of the library that defines the opaque record type. They may only be operated on by clients through facilities provided in the library's public interface.
Example:
IMPORT Pascal String?; VAR str : Pascal String?; str.length := 0; (* compile time error: access of a restricted field *) Terminal.Write Octets?(str.data); (* compile time error: access of a restricted field *) Pascal String?.copy(str, "foobar"); (* proper use: operation through public interface *)
An opaque type is a type whose internal composition and structure is not accessible outside of the implementation part of the library in which it is defined. Instances of an opaque type may only be operated on by clients of its exporting library through the operations exported by the public interface of the library. There are two kinds of opaque types:
An opaque pointer type is a special pointer type used for the construction of ADTs. The definition and declaration of such an ADT is divided between the definition and implementation part of its library. The identifier of the opaque type is defined in the library's definition part and it may be imported from there by clients. It is defined using the OPAQUE
type constructor.
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
Examples:
TYPE Celsius = REAL; Fahrenheit = REAL;
Due to strict name equivalence, derived types and their base types are incompatible because their identifiers are different.
DEFINITION MODULE Tree; TYPE Tree = OPAQUE; (* opaque pointer *) (* public interface *) END Tree.
VAR celsius : Celsius; fahrenheit : Fahrenheit; celsius := fahrenheit; (* compile time error: incompatible types *)
The target type of the opaque pointer is declared in the library's corresponding implementation part and it is therefore inaccessible to clients. It is declared using the PPOINTER
TO
type constructor.
To assign values across type boundaries, type conversion is required.
IMPLEMENTATION MODULE Tree; TYPE Tree = POINTER TO TreeDescriptor; (* target type specification *) TYPE TreeDescriptor = RECORD left, right : Tree; value : ValueType END; (* TreeDescriptor *) (* implementation *) END Tree.
celsius := (fahrenheit :: Celsius - 32.0) * 100.0/180.0; (* type conversion *)
Instances of an opaque pointer based ADT may only be allocated dynamically at runtime.
ALIAS
TypesAn ALIAS
type is a derived type specifically defined to be compatible with its base type even though their identifiers are different. An ALIAS
type is defined using the ALIAS
OF
type constructor.
IMPORT Tree; VAR tree : Tree; NEW tree := { foo, bar, baz };
TYPE INT = ALIAS OF INTEGER;
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
An ALIAS
type and its base type are compatible in every aspect. They may therefore be used interchangeably.
Examples:
TYPE Celsius = REAL; Fahrenheit = REAL;
Example:
VAR i : INT; j : INTEGER; i := j; (* i and j are compatible *)
Due to strict name equivalence, derived types and their base types are incompatible because their identifiers are different.
A subrange type is a type defined as a subset of a scalar or ordinal type. A subrange type is upwards compatible with its base type, but the base type is not downwards compatible with any subrange types derived from it. A subrange type inherits all its properties from its base type, except for its lower and upper bound. A subrange type's lower and upper bound must be specified in its type definition. Both lower and upper bound must be compatible with the base type and they must be legal values of the base type.
Example:
VAR celsius : Celsius; fahrenheit : Fahrenheit; celsius := fahrenheit; (* compile time error: incompatible types *)
Examples:
TYPE Radian = [0.0 .. tau] OF REAL; TYPE Natural = [1 .. TMAX(CARDINAL)] OF CARDINAL;
To assign values across type boundaries, type conversion is required.
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol. An open bound of a subrange type is not a legal value of the type.
Example:
celsius := (fahrenheit :: Celsius - 32.0) * 100.0/180.0; (* type conversion *)
Examples:
TYPE PosReal = [>0.0 .. TMAX(REAL)] OF REAL; TYPE NegReal = [TMIN(REAL) .. <0.0] OF REAL;
ALIAS
TypesAn ALIAS
type is a derived type specifically defined to be compatible with its base type even though their identifiers are different. An ALIAS
type is defined using the ALIAS
OF
type constructor.
A CONST
type is a type defined to be an immutable alias type of a mutable ADT. A CONST
type is defined using the CONST
type constructor.
TYPE INT = ALIAS OF INTEGER;
TYPE ImmutableFooArray = CONST FooArray;
An ALIAS
type and its base type are compatible in every aspect. They may therefore be used interchangeably.
A CONST
type is compatible with its base type, except where such compatibility would violate the type's immutability.
VAR i : INT; j : INTEGER; i := j; (* i and j are compatible *)
VAR array : FooArray; immArray : ImmutableFooArray; NEW array; (* initialisation not required *) NEW immArray := { foo, bar, baz }; (* initialisation required *) COPY array := immArray; (* copying from immutable to mutable *) COPY immArray := array; (* compile time error: attempt to modify immutable instance *)
A subrange type is a type defined as a subset of a scalar or ordinal type. A subrange type is upwards compatible with its base type, but the base type is not downwards compatible with any subrange types derived from it. A subrange type inherits all its properties from its base type, except for its lower and upper bound. A subrange type's lower and upper bound must be specified in its type definition. Both lower and upper bound must be compatible with the base type and they must be legal values of the base type.
An enumeration type is an ordinal type whose legal values are defined by a list of identifiers. The identifiers are assigned ordinal values from left to right as they appear in the type definition. The ordinal value assigned to the leftmost identifier is always zero.
Examples:
TYPE Radian = [0.0 .. tau] OF REAL; TYPE Natural = [1 .. TMAX(CARDINAL)] OF CARDINAL;
Example:
TYPE Colour = ( red, green, blue ); (* ORD(red) => 0 *)
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol. An open bound of a subrange type is not a legal value of the type.
When referencing an enumerated value, its identifier must be qualified with its type identifier, except within a subrange type constructor. This requirement fixes a flaw in classic Modula-2 where the import of an enumeration type could cause name conflicts.
Examples:
TYPE PosReal = [>0.0 .. TMAX(REAL)] OF REAL; TYPE NegReal = [TMIN(REAL) .. <0.0] OF REAL;
Example:
TYPE BaseColour = [red .. green] OF Colour; (* unqualified *) VAR colour : Colour; colour := Colour.green; (* qualified *)
A CONST
type is a type defined to be an immutable alias type of a mutable ADT. A CONST
type is defined using the CONST
type constructor.
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type. The base type is downwards compatible with any extended types derived from it, but extensions are not upwards compatible with their base type. This restriction exists because any value of the base type is always a legal value of any extension type derived from it, but not every value of an extension type is also a legal value of the base type.
TYPE ImmutableFooArray = CONST FooArray;
TYPE MoreColour = ( +Colour, orange, magenta, cyan ); (* equivalent to: MoreColour = ( red, green, blue, orange, magenta, cyan );
A CONST
type is compatible with its base type, except where such compatibility would violate the type's immutability.
The allocation size of an enumeration type is always 16 bit. Its maximum value range is 65536 values.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type of up to 256 values. The values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
VAR array : FooArray; immArray : ImmutableFooArray; NEW array; (* initialisation not required *) NEW immArray := { foo, bar, baz }; (* initialisation required *) COPY array := immArray; (* copying from immutable to mutable *) COPY immArray := array; (* compile time error: attempt to modify immutable instance *)
TYPE ColourSet = SET OF Colour;
An enumeration type is an ordinal type whose legal values are defined by a list of identifiers. The identifiers are assigned ordinal values from left to right as they appear in the type definition. The ordinal value assigned to the leftmost identifier is always zero.
An instance of a set type may hold multiple elements but any given element may be stored at most once. An element stored in a set is said to be a member of the set. A set is represented as an array of boolean membership values, where the element is the accessor and the membership is the value. A membership value may thus be either TRUE
or FALSE
.
Example:
TYPE Colour = ( red, green, blue ); (* ORD(red) => 0 *)
Examples:
VAR colours : ColourSet; isMember : BOOLEAN; colours := { Colour.red, Colour.green }; (* assignment *) isMember := colours[Colour.green]; (* membership retrieval *) colours[Colour.blue] := TRUE; (* membership storage *)
When referencing an enumerated value, its identifier must be qualified with its type identifier, except within a subrange type constructor. This requirement fixes a flaw in classic Modula-2 where the import of an enumeration type could cause name conflicts.
An array type is an indexed collection type whose values are of a single arbitrary type, called the array's value type. The type's capacity is specified by a value count parameter in the type definition. The capacity must be a whole number value and it may not be zero. Array types are defined using the ARRAY
OF
type constructor.
TYPE BaseColour = [red .. green] OF Colour; (* unqualified *) VAR colour : Colour; colour := Colour.green; (* qualified *)
TYPE IntArray = ARRAY 10 OF INTEGER;
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type. The base type is downwards compatible with any extended types derived from it, but extensions are not upwards compatible with their base type. This restriction exists because any value of the base type is always a legal value of any extension type derived from it, but not every value of an extension type is also a legal value of the base type.
The values of an array instance are addressable by cardinal index using subscript notation. The lowest index is always zero.
Example:
TYPE MoreColour = ( +Colour, orange, magenta, cyan ); (* equivalent to: MoreColour = ( red, green, blue, orange, magenta, cyan );
Examples:
VAR array : IntArray; int : INTEGER; array := { 0 BY TLIMIT(IntArray) }; (* initialise all values with zero *) int := array[5]; (* value retrieval *) array[5] := 42; (* value storage *)
The allocation size of an enumeration type is always 16 bit. Its maximum value range is 65536 values.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type of up to 256 values. The values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it may not be zero.
TYPE ColourSet = SET OF Colour;
TYPE FlexArray = ARRAY < 10 OF INTEGER;
An instance of a set type may hold multiple elements but any given element may be stored at most once. An element stored in a set is said to be a member of the set. A set is represented as an array of boolean membership values, where the element is the accessor and the membership is the value. A membership value may thus be either TRUE
or FALSE
.
The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be appended, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be appended, inserted and removed at runtime.
VAR colours : ColourSet; isMember : BOOLEAN; colours := { Colour.red, Colour.green }; (* assignment *) isMember := colours[Colour.green]; (* membership retrieval *) colours[Colour.blue] := TRUE; (* membership storage *)
VAR array : FlexArray; array := { 42, -5, 0 }; (* initialise with three values *) APPEND(array, -35); (* append a value *) INSERT(array, 0, 11); (* value insertion *) REMOVE(array, 3, 1); (* value removal *)
An array type is an indexed collection type whose values are of a single arbitrary type, called the array's value type. The type's capacity is specified by a value count parameter in the type definition. The capacity must be a whole number value and it may not be zero. Array types are defined using the ARRAY
OF
type constructor.
Instances of flexible arrays may further be sliced and concatenated. Flexible array types and their slices are insertion and concatenation compatible as long as the respective value types are compatible.
Example:
TYPE IntArray = ARRAY 10 OF INTEGER;
The values of an array instance are addressable by cardinal index using subscript notation. The lowest index is always zero.
VAR array : IntArray; int : INTEGER; array := { 0 BY TLIMIT(IntArray) }; (* initialise all values with zero *) int := array[5]; (* value retrieval *) array[5] := 42; (* value storage *)
VAR array1, array2, array3 : FlexArray; array2 := { 1, 2, 3, 4 }; array3 := { 7, 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 4, 7, 8, 9 } *) array1[4..5] := { 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it may not be zero.
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. An attempt to define a rigid character array type shall cause a compile time error.
Example:
TYPE FlexArray = ARRAY < 10 OF INTEGER;
Examples:
TYPE String = ARRAY 100 OF CHAR; (* compile time error: unsupported definition *) TYPE String = ARRAY < 100 OF CHAR; (* OK, supported character array type definition *)
The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be appended, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be appended, inserted and removed at runtime.
The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every assign, append and concatenation operation.
A record type is a compound type whose components are of arbitrary types. The components are called fields. The number of fields is arbitrary. Record types are defined using the RECORD
type constructor.
Example:
TYPE Point = RECORD x, y : REAL END;
An instance of a record type holds exactly one value for each field. Fields are addressable by selector.
VAR array : FlexArray; array := { 42, -5, 0 }; (* initialise with three values *) APPEND(array, -35); (* append a value *) INSERT(array, 0, 11); (* value insertion *) REMOVE(array, 3, 1); (* value removal *)
VAR point : Point; r : REAL; record := { 0.0, 0.0 }; (* initialise all fields with zero *) r := point.x; (* field retrieval *) point.y := 0.75; (* field storage *)
Instances of flexible arrays may further be sliced and concatenated. Flexible array types and their slices are insertion and concatenation compatible as long as the respective value types are compatible.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. All fields of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any field of the base type is always a field of any extension type derived from it, but not every field of an extension type is also a field of the base type.
VAR array1, array2, array3 : FlexArray; array2 := { 1, 2, 3, 4 }; array3 := { 7, 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 4, 7, 8, 9 } *) array1[4..5] := { 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
TYPE ColourPoint = RECORD ( Point ) colour : Colour END; VAR cPoint : ColourPoint; cPoint := { 0.0, 0.0, Colour.red }; (* initialise all fields *) cPoint.x := 1.5; cPoint.y := 0.75;
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. An attempt to define a rigid character array type shall cause a compile time error.
A pointer type is a container for a typed reference to an entity at a memory storage location. The type of the referenced entity is called the target type. The entity referenced by an instance of a pointer type is called the pointer's target. Pointer types are defined using the POINTER
TO
type constructor.
Examples:
TYPE String = ARRAY 100 OF CHAR; (* compile time error: unsupported definition *) TYPE String = ARRAY < 100 OF CHAR; (* OK, supported character array type definition *)
Example:
TYPE IntPtr = POINTER TO INTEGER;
The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every assign, append and concatenation operation.
A record type is a compound type whose components are of arbitrary types. The components are called fields. The number of fields is arbitrary. Record types are defined using the RECORD
type constructor.
Typed references are created using predefined procedure PTR
. Instances of pointer types are dereferenced using the pointer dereferencing operator ^
.
TYPE Point = RECORD x, y : REAL END;
VAR int : INTEGER; intPtr : IntPtr; intPtr := PTR(int, IntPtr); (* obtain a typed reference to int *) intPtr^ := 0; (* write to int via dereferenced pointer intPtr *)
An instance of a record type holds exactly one value for each field. Fields are addressable by selector.
A pointer type may be defined to restrict the mutability of its target.
Examples:
VAR point : Point; r : REAL; record := { 0.0, 0.0 }; (* initialise all fields with zero *) r := point.x; (* field retrieval *) point.y := 0.75; (* field storage *)
Example:
TYPE ImmIntPtr = POINTER TO CONST INTEGER;
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. All fields of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any field of the base type is always a field of any extension type derived from it, but not every field of an extension type is also a field of the base type.
Although the instance of such a pointer itself is mutable, its target is always treated immutable. A dereferenced instance may not be used as an L-value and it may not be passed to a procedure as a VAR
parameter. Pointers to mutable and immutable targets are therefore always incompatible. Any violation shall cause a compile time error.
Examples:
TYPE ColourPoint = RECORD ( Point ) colour : Colour END; VAR cPoint : ColourPoint; cPoint := { 0.0, 0.0, Colour.red }; (* initialise all fields *) cPoint.x := 1.5; cPoint.y := 0.75;
Example:
VAR int : INTEGER; intPtr : IntPtr; immPtr : ImmIntPtr; intPtr := PTR(int, IntPtr); immPtr := PTR(int, ImmIntPtr); intPtr^ := 0; (* OK, modifying a mutable target *) immPtr^ := 0; (* compile time error due to attempt to modify an immutable target *)
A pointer type is a container for a typed reference to an entity at a memory storage location. The type of the referenced entity is called the target type. The entity referenced by an instance of a pointer type is called the pointer's target. Pointer types are defined using the POINTER
TO
type constructor.
A coroutine type is a special purpose pointer type whose target is a coroutine. An associated procedure type is part of the type definition. A coroutine procedure is compatible with a coroutine type when it matches the signature of the type's associated procedure type. Coroutine types are defined using the COROUTINE
type constructor.
Example:
TYPE IntPtr = POINTER TO INTEGER;
Examples:
TYPE Iterator = COROUTINE ( IteratorProc );
Typed references are created using predefined procedure PTR
. Instances of pointer types are dereferenced using the pointer dereferencing operator ^
.
A procedure type is a special purpose pointer type whose target is a procedure. The procedure's signature is part of the type definition. A procedure is compatible with a procedure type when their signatures match. Procedure types are defined using the PROCEDURE
type constructor.
Example:
VAR int : INTEGER; intPtr : IntPtr; intPtr := PTR(int, IntPtr); (* obtain a typed reference to int *) intPtr^ := 0; (* write to int via dereferenced pointer intPtr *)
Examples:
TYPE WriteStrProc = PROCEDURE ( CONST ARRAY OF CHAR ); TYPE FSM = PROCEDURE ( CONST ARRAY OF CHAR, FSM );
A pointer type may be defined to restrict the mutability of its target.
An opaque type is a type whose internal composition and structure is not accessible outside of the implementation part of the library in which it is defined. Instances of an opaque type may only be operated on by clients of its exporting library through the operations exported by the public interface of the library. There are two kinds of opaque types:
An opaque pointer type is a special pointer type used for the construction of ADTs. The definition and declaration of such an ADT is divided between the definition and implementation part of its library. The identifier of the opaque type is defined in the library's definition part and it may be imported from there by clients. It is defined using the OPAQUE
type constructor.
TYPE ImmIntPtr = POINTER TO CONST INTEGER;
DEFINITION MODULE Tree; TYPE Tree = OPAQUE; (* opaque pointer *) (* public interface *) END Tree.
Although the instance of such a pointer itself is mutable, its target is always treated immutable. A dereferenced instance may not be used as an L-value and it may not be passed to a procedure as a VAR
parameter. Pointers to mutable and immutable targets are therefore always incompatible. Any violation shall cause a compile time error.
The target type of the opaque pointer is declared in the library's corresponding implementation part and it is therefore inaccessible to clients. It is declared using the PPOINTER
TO
type constructor.
VAR int : INTEGER; intPtr : IntPtr; immPtr : ImmIntPtr; intPtr := PTR(int, IntPtr); immPtr := PTR(int, ImmIntPtr); intPtr^ := 0; (* OK, modifying a mutable target *) immPtr^ := 0; (* compile time error due to attempt to modify an immutable target *)
IMPLEMENTATION MODULE Tree; TYPE Tree = POINTER TO TreeDescriptor; (* target type specification *) TYPE TreeDescriptor = RECORD left, right : Tree; value : ValueType END; (* TreeDescriptor *) (* implementation *) END Tree.
A coroutine type is a special purpose pointer type whose target is a coroutine. An associated procedure type is part of the type definition. A coroutine procedure is compatible with a coroutine type when it matches the signature of the type's associated procedure type. Coroutine types are defined using the COROUTINE
type constructor.
Instances of an opaque pointer based ADT may only be allocated dynamically at runtime.
Examples:
TYPE Iterator = COROUTINE ( IteratorProc );
Example:
IMPORT Tree; VAR tree : Tree; NEW tree := { foo, bar, baz };
A procedure type is a special purpose pointer type whose target is a procedure. The procedure's signature is part of the type definition. A procedure is compatible with a procedure type when their signatures match. Procedure types are defined using the PROCEDURE
type constructor.
Examples:
TYPE WriteStrProc = PROCEDURE ( CONST ARRAY OF CHAR ); TYPE FSM = PROCEDURE ( CONST ARRAY OF CHAR, FSM );
An opaque pointer type is a special pointer type used for the construction of ADTs. The definition and declaration of such an ADT is divided between the definition and implementation part of its library. The identifier of the opaque type is defined in the library's definition part and may be imported from there by clients.
The identifier of an opaque pointer type is available in the library that defines it and in modules that import it. It is defined using the OPAQUE
type constructor.
An opaque pointer type is a special pointer type used for the construction of ADTs. The definition and declaration of such an ADT is divided between the definition and implementation part of its library. The identifier of the opaque type is defined in the library's definition part and it may be imported from there by clients. It is defined using the OPAQUE
type constructor.
TYPE Tree = POINTER TO Tree Descriptor?; (* target type specification *) TYPE Tree Descriptor? = RECORD
TYPE Tree = POINTER TO TreeDescriptor; (* target type specification *) TYPE TreeDescriptor = RECORD
END; (* Tree Descriptor? *)
END; (* TreeDescriptor *)
NEW
Statement
RETAIN
Statement
RELEASE
Statement
COPY
Statement
IF
Statement
CASE
Statement
WHILE
Statement
REPEAT
Statement
LOOP
Statement
FOR
Statement
RETURN
Statement
YIELD
Statement
EXIT
Statement
NEW
Statement
RETAIN
Statement
RELEASE
Statement
COPY
Statement
IF
Statement
CASE
Statement
WHILE
Statement
REPEAT
Statement
LOOP
Statement
FOR
Statement
RETURN
Statement
YIELD
Statement
EXIT
Statement
NOT
Operator
DIV
Operator
MOD
Operator
AND
Operator
OR
Operator
>
Operator
>=
Operator
<
Operator
<=
Operator
IN
Operator
NOT
Operator
DIV
Operator
MOD
Operator
AND
Operator
OR
Operator
>
Operator
>=
Operator
<
Operator
<=
Operator
IN
Operator
An opaque type is a type whose internal composition and structure is not accessible outside of the implementation part of the library in which it is defined. Instances of an opaque type may only be operated on by clients of its exporting library through the operations exported by the public interface of the library. There are two kinds of opaque types:
An opaque pointer type is a special pointer type used for the construction of ADTs. The definition and declaration of such an ADT is divided between the definition and implementation part of its library. The identifier of the opaque type is defined in the library's definition part and may be imported from there by clients.
The identifier of an opaque pointer type is available in the library that defines it and in modules that import it. It is defined using the OPAQUE
type constructor.
Example:
DEFINITION MODULE Tree; TYPE Tree = OPAQUE; (* opaque pointer *) (* public interface *) END Tree.
The target type of the opaque pointer is declared in the library's corresponding implementation part and it is therefore inaccessible to clients. It is declared using the PPOINTER
TO
type constructor.
Example:
IMPLEMENTATION MODULE Tree; TYPE Tree = POINTER TO Tree Descriptor?; (* target type specification *) TYPE Tree Descriptor? = RECORD left, right : Tree; value : Value Type? END; (* Tree Descriptor? *) (* implementation *) END Tree.
Instances of an opaque pointer based ADT may only be allocated dynamically at runtime.
Example:
IMPORT Tree; VAR tree : Tree; NEW tree := { foo, bar, baz };
TYPE Immutable Foo Array? = CONST Foo Array?;
TYPE ImmutableFooArray = CONST FooArray;
VAR array : Foo Array?; immArray : Immutable Foo Array?;
VAR array : FooArray; immArray : ImmutableFooArray;
to do
An enumeration type is an ordinal type whose legal values are defined by a list of identifiers. The identifiers are assigned ordinal values from left to right as they appear in the type definition. The ordinal value assigned to the leftmost identifier is always zero.
A CONST
type is a type defined to be an immutable alias type of a mutable ADT. A CONST
type is defined using the CONST
type constructor.
Example:
TYPE Immutable Foo Array? = CONST Foo Array?;
A CONST
type is compatible with its base type, except where such compatibility would violate the type's immutability.
Example:
VAR array : Foo Array?; immArray : Immutable Foo Array?; NEW array; (* initialisation not required *) NEW immArray := { foo, bar, baz }; (* initialisation required *) COPY array := immArray; (* copying from immutable to mutable *) COPY immArray := array; (* compile time error: attempt to modify immutable instance *)
An ALIAS
type is a derived type specifically defined to be compatible with its base type. An ALIAS
type is defined using the ALIAS
OF
type constructor.
An ALIAS
type is a derived type specifically defined to be compatible with its base type even though their identifiers are different. An ALIAS
type is defined using the ALIAS
OF
type constructor.
A derived type is a type defined to inherit all its properties from another type, except for its identifier. A derived type is defined using the =
symbol followed by the base type in the type constructor.
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 *)
to do
An ALIAS
type is a derived type specifically defined to be compatible with its base type. An ALIAS
type is defined using the ALIAS
OF
type constructor.
Example:
TYPE INT = ALIAS OF INTEGER;
An ALIAS
type and its base type are compatible in every aspect. They may therefore be used interchangeably.
Example:
VAR i : INT; j : INTEGER; i := j; (* i and j are compatible *)
Primitive SUBSET
is a polymorphic primitive to test whether a set is a subset of another. It has one signature:
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:
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.
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.
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 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.
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.
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.
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.
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.
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.
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 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.
To overwrite one or more consecutive values starting at a given index in an array of 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.
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.
An Invocation of TAMX
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:
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:
To overwrite multiple 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.
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.
To overwrite one of more consecutive values starting at a given index in an array of 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.
To overwrite one or more consecutive values starting at a given index in an array of 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.
To overwrite the element counters of multiple given elements in a set, the primitive is called passing the set as its first operand and the 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 the set's counter type.
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.
To overwrite multiple values for given keys in a dictionary, the primitive is called passing the dictionary as its first operand and the 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 the dictionary's value type.
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.
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.
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.
To overwrite multiple 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.
To overwrite one of more consecutive values starting at a given index in an array of 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.
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.
To overwrite the element counters of multiple given elements in a set, the primitive is called passing the set as its first operand and the 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 the set's counter type.
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.
To overwrite multiple values for given keys in a dictionary, the primitive is called passing the dictionary as its first operand and the 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 the dictionary's value type.
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.
A CASE
statement is a flow-control statement that passes control to one of a number of labeled statements or statement sequences depending on the value of an ordinal expression.
A CASE
statement is a flow-control statement that passes control to one of a number of labeled statements or statement sequences depending on the value of an ordinal expression. Control is passed to the first statement following the case label that matches the ordinal expression. If no label matches, control is passed to the ELSE
block.
A case label shall be listed at most once. If a case is encountered at runtime that is not listed in the case label list and if there is no ELSE clause, no case label statements shall be executed and no error shall result.
A case label shall be listed at most once. If a case is encountered at runtime that is not listed in the case label list and if there is no ELSE
block, no case label statements shall be executed and no error shall result.
( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
( c : <DictionaryType>; entries : ARGLIST >0 OF { key : <KeyType >; value : <ValueType> );
Primitive STORE
is a polymorphic primitive to overwrite one or more values in a collection. It has eight signatures:
Primitive STORE
is a polymorphic primitive to overwrite one or more values in a collection. It has nine signatures:
PROCEDURE STORE ( c : <SeqType>; atIndex : <IndexType>; value : <ValueType> );
PROCEDURE STORE ( c : <ArrayType>; atIndex : <IndexType>; value : <ValueType> );
PROCEDURE STORE ( c : <SeqType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
PROCEDURE STORE ( c : <ListType>; p : <AccessorType>; value : <ValueType> );
( c : <SeqType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
( c : <SeqType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
PROCEDURE STORE ( c : <SetType>; element : <ElementType>; counter : <CounterType> );
PROCEDURE STORE ( c : <SeqType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
PROCEDURE STORE ( c : <SetType>; entries : ARGLIST >0 OF { element : <ElementType>; counter : <CounterType> } );
PROCEDURE STORE ( c : <SetType>; element : <ElementType>; counter : <CounterType> );
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; value : <ValueType> );
PROCEDURE STORE ( c : <SetType>; entries : ARGLIST >0 OF { element : <ElementType>; counter : <CounterType> } );
PROCEDURE STORE ( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; value : <ValueType> );
( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
PROCEDURE VALUE ( VAR c : <ListType>; accessor : <AccessorType> ) : <ValueType>;
PROCEDURE VALUE ( VAR c : <ListType>; p : <AccessorType> ) : <ValueType>;
PROCEDURE SEEK ( c : <ListType>; index : LONGCARD ) : <AccessorType> );
PROCEDURE SEEK ( c : <ListType>; index : LONGCARD ) : <AccessorType>;
( c : <ListType>; current : <AccessorType>; plusOrMinus : <CharLiteral> ) : <AccessorType> );
( c : <ListType>; current : <AccessorType>; plusOrMinus : <CharLiteral> ) : <AccessorType>;
SEEK
Primitive SEEK
is a polymorphic primitive to obtain accessors to list elements for list traversal. It has two signatures:
PROCEDURE SEEK ( c : <ListType>; index : LONGCARD ) : <AccessorType> );
PROCEDURE SEEK ( c : <ListType>; current : <AccessorType>; plusOrMinus : <CharLiteral> ) : <AccessorType> );
Primitive STORE
is a polymorphic macro to overwrite one or more values in a collection. It has eight signatures:
Primitive STORE
is a polymorphic primitive to overwrite one or more values in a collection. It has eight signatures:
VALUE
Primitive VALUE
is a polymorphic primitive to retrieve a value from a collection. It has five signatures:
PROCEDURE VALUE ( VAR c : <ArrayType>; atIndex : <IndexType> ) : <ValueType>;
PROCEDURE VALUE ( VAR c : <ListType>; accessor : <AccessorType> ) : <ValueType>;
PROCEDURE VALUE ( VAR c : <SetType>; element : <ElementType> ) : <CounterType>;
PROCEDURE VALUE ( VAR c : <DictionaryType>; key : <KeyType> ) : <ValueType>;
PROCEDURE VALUE ( VAR c : <DictionaryType>; key : <KeyType>; index : CARDINAL ) : <ValueType>;
( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
Primitive STORE
is a polymorphic macro to overwrite one or more values in a collection. It has X signatures:
Primitive STORE
is a polymorphic macro to overwrite one or more values in a collection. It has eight signatures:
PROCEDURE STORE ( c : <ArrayType>; atIndex : <IndexType>; value : <ValueType> );
PROCEDURE STORE ( c : <SeqType>; atIndex : <IndexType>; value : <ValueType> );
( c : <ArrayType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
( c : <SeqType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
( c : <ArrayType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
( c : <SeqType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
Primitive SXF
is a polymorphic macro 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:
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:
Primitive VAL
is a polymorphic macro 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:
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:
STORE
Primitive STORE
is a polymorphic macro to overwrite one or more values in a collection. It has X signatures:
PROCEDURE STORE ( c : <ArrayType>; atIndex : <IndexType>; value : <ValueType> );
PROCEDURE STORE ( c : <ArrayType>; fromIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
PROCEDURE STORE ( c : <ArrayType>; fromIndex : <IndexType>; valueCount : LONGCARD; fillValue : <ValueType> );
PROCEDURE STORE ( c : <SetType>; element : <ElementType>; counter : <CounterType> );
PROCEDURE STORE ( c : <SetType>; entries : ARGLIST >0 OF { element : <ElementType>; counter : <CounterType> } );
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; value : <ValueType> );
PROCEDURE STORE ( c : <DictionaryType>; key : <KeyType>; index : CARDINAL; value : <ValueType> );
PROCEDURE STORE ( c : <DictionaryType>; entries : ARGLIST >1 OF { key : <KeyType >; value : <ValueType> );
Primitives are built-in polymorphic macros for internal use by the compiler to synthesise various operations for library defined AD Ts?. 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 AD Ts? may be required to provide specific implementations and bind them to their respective primitives.
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
Primitive SXF
is a polymorphic macro 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 macro 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> );
Primitives are built-in polymorphic macros for internal use by the compiler to synthesise various operations for library defined AD Ts?. 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 AD Ts? may be required to provide specific implementations and bind them to their respective primitives.
SXF
VAL
STORE
VALUE
SEEK
SUBSET
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. The type of its replacement value is of the type denoted by its operand. It has one signature:
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:
An Invocation of TAMX
is replaced by the largest legal value of its operand. Its operand shall be the type identifier of a scalar or ordinal type. The type of its replacement value is of the type denoted by its operand. It has one signature:
An Invocation of TAMX
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:
An Invocation of TLIMIT
is replaced by the capacity limit of its operand. Its operand shall be the type identifier of a collection type. The type of its replacement value is type LONGCARD
. It has one signature:
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:
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:
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:
Function ABS
is a polymorphic function to return the absolute value of its operand. It is strictly limited to scalar operands. Its operand shall be of a scalar or ordinal type. Its return type is the operand type. It has one signature:
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 : <ScalarOrOrdinalType> ) : <OperandType>;
PROCEDURE ABS ( value : <ScalarType> ) : <OperandType>;
Function ABS
is a polymorphic function to return the absolute value of its operand. Its operand shall be of a scalar or ordinal type. Its return type is the operand type. It has one signature:
Function ABS
is a polymorphic function to return the absolute value of its operand. It is strictly limited to scalar operands. Its operand shall be of a scalar or ordinal type. Its return type is the operand type. It has one signature:
Function LENGTH
is a polymorphic function to return the number of values stored in a character string. It has one signature:
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:
Function PTR
is a polymorphic function to return a typed pointer to a variable provided its type is compatible with the target type of a passed in pointer type. It has one signature:
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 : <PointerType> ) : <T>;
PROCEDURE PTR ( v : <AnyType>; T : <TypeIdentifier> ) : <T>;
Function FIRST
is a polymorphic function to return the first value of an ordered collection. It has one signature:
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 : <CollectionType> ) : <ValueType>;
PROCEDURE FIRST ( c : <OrderedCollectionType> ) : <ValueType>;
Function LAST
is a polymorphic function to return the last value of an ordered collection. It has one signature:
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 : <CollectionType> ) : <ValueType>;
PROCEDURE LAST ( c : <OrderedCollectionType> ) : <ValueType>;
Function MIN
is a polymorphic function to return the smallest value from a list of scalar or ordinal values. It has one signature:
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:
Function MAX
is a polymorphic function to return the largest value from a list of scalar or ordinal values. It has one signature:
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:
An Invocation of TMIN
is replaced by the smallest legal value of a scalar or ordinal type given as its argument. It has one signature:
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. The type of its replacement value is of the type denoted by its operand. It has one signature:
An Invocation of TMAX
is replaced by the largest legal value of a scalar or ordinal type given as its argument. It has one signature:
An Invocation of TAMX
is replaced by the largest legal value of its operand. Its operand shall be the type identifier of a scalar or ordinal type. The type of its replacement value is of the type denoted by its operand. It has one signature:
An Invocation of TLIMIT
is replaced by the capacity limit of the collection type given as its argument. It has one signature:
An Invocation of TLIMIT
is replaced by the capacity limit of its operand. Its operand shall be the type identifier of a collection type. The type of its replacement value is type LONGCARD
. It has one signature:
An Invocation of TSIZE
is replaced by the allocation size required for an instance of the type given as its argument. It has one signature:
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:
Function ABS
is a polymorphic function to return the absolute value of a scalar or ordinal value. It has one signature:
Function ABS
is a polymorphic function to return the absolute value of its operand. Its operand shall be of a scalar or ordinal type. Its return type is the operand type. It has one signature:
Function ODD
is a polymorphic function to test whether a given whole number value is odd. It returns TRUE
if it is, otherwise FALSE
. It has one signature:
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:
Function PRED
is a polymorphic function to return the n-th predecessor of an ordinal value. It has two signatures:
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:
Function SUCC
is a polymorphic function to return the n-th successor of an ordinal value. It has two signatures:
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:
Function ORD
is a polymorphic function to return the ordinal value of a character or enumerated value. It has one signature:
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:
Function CHR
is a polymorphic function to return the character whose code point matches its parameter. It has one signature:
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:
Function EXISTS
is a polymorphic function to test whether a given value for a given key is already present in a dictionary. It returns TRUE
if the value is present, otherwise FALSE
. It has one signature:
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:
Function COUNT
is a polymorphic function to return the number of values stored in a collection. It has two signatures:
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.
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.
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;
Status: 2015-09-25
Status: 2015-09-25 (update in progress)
Copyright © 2010-2015 B.Kowarsch & R.Sutcliffe. All rights reserved. Reproduction requires written permission.
Copyright © 2010-2015 B.Kowarsch & R.Sutcliffe. All rights reserved. Reproduction requires written permission.
Copyright © 2010-2015 B.Kowarsch & R.Sutcliffe. All rights reserved. Reproduction requires written permission.
NEW
Statement
RETAIN
Statement
The RELEASE
Statement
COPY
Statement
IF
Statement
CASE
Statement
WHILE
Statement
REPEAT
Statement
LOOP
Statement
FOR
Statement
RETURN
Statement
YIELD
Statement
EXIT
Statement
NOT
Operator
DIV
Operator
MOD
Operator
AND
Operator
OR
Operator
>
Operator
>=
Operator
<
Operator
<=
Operator
IN
Operator
NOT
Operator
DIV
Operator
MOD
Operator
AND
Operator
OR
Operator
>
Operator
>=
Operator
<
Operator
<=
Operator
IN
Operator
BOOLEAN
OCTET
CARDINAL
LONGCARD
INTEGER
LONGINT
REAL
LONGREAL
INSERT
APPEND
REMOVE
SORT
SORTNEW
READ
READNEW
WRITE
WRITEF
TODO
ABS
ODD
PRED
SUCC
CHR
ORD
EXISTS
COUNT
LENGTH
PTR
FIRST
LAST
MIN
MAX
NOT
Operator
DIV
Operator
MOD
Operator
AND
Operator
OR
Operator
>
Operator
>=
Operator
<
Operator
<=
Operator
IN
Operator
NEW
Statement
RETAIN
Statement
RELEASE
Statement
COPY
Statement
IF
Statement
CASE
Statement
WHILE
Statement
REPEAT
Statement
LOOP
Statement
FOR
Statement
RETURN
Statement
YIELD
Statement
EXIT
Statement
(To do: move and merge content)
(To do: enter from PDF version and update)
(To do: move and merge content)
(To do: enter from PDF version and update)
PROCEDURE ABS ( value : <ScalarOrOrdinalType> ) : <Operand Type?>;
PROCEDURE ABS ( value : <ScalarOrOrdinalType> ) : <OperandType>;
PROCEDURE PRED ( value : <OrdinalType> ) : <Operand Type?>;
PROCEDURE PRED ( value : <OrdinalType> ) : <OperandType>;
PROCEDURE PRED ( value : <OrdinalType>; n : CARDINAL ) : <Operand Type?>;
PROCEDURE PRED ( value : <OrdinalType>; n : CARDINAL ) : <OperandType>;
PROCEDURE SUCC ( value : <OrdinalType> ) : <Operand Type?>;
PROCEDURE SUCC ( value : <OrdinalType> ) : <OperandType>;
PROCEDURE SUCC ( value : <OrdinalType>; n : CARDINAL ) : <Operand Type?>;
PROCEDURE SUCC ( value : <OrdinalType>; n : CARDINAL ) : <OperandType>;
PROCEDURE CHR ( codePoint : <OctetOrCardinalOrLongcard> ) : <Char Or Unichar?>;
PROCEDURE CHR ( codePoint : <OctetOrCardinalOrLongcard> ) : <CharOrUnichar>;
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 message. It has one signature:
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:
An Invocation of TSIZZE
is replaced by the allocation size required for an instance of the type given as its argument. It has one signature:
An Invocation of TSIZE
is replaced by the allocation size required for an instance of the type given as its argument. It has one signature:
Function ABS
is a polymorphic function to return the absolute value of a scalar or ordinal value. It has one signature:
PROCEDURE ABS ( value : <ScalarOrOrdinalType> ) : <Operand Type?>;
Function ODD
is a polymorphic function to test whether a given whole number value is odd. It returns TRUE
if it is, otherwise FALSE
. It has one signature:
PROCEDURE ODD ( value : <WholeNumberType> ) : BOOLEAN;
Function PRED
is a polymorphic function to return the n-th predecessor of an ordinal value. It has two signatures:
PROCEDURE PRED ( value : <OrdinalType> ) : <Operand Type?>;
PROCEDURE PRED ( value : <OrdinalType>; n : CARDINAL ) : <Operand Type?>;
Function SUCC
is a polymorphic function to return the n-th successor of an ordinal value. It has two signatures:
PROCEDURE SUCC ( value : <OrdinalType> ) : <Operand Type?>;
PROCEDURE SUCC ( value : <OrdinalType>; n : CARDINAL ) : <Operand Type?>;
Function ORD
is a polymorphic function to return the ordinal value of a character or enumerated value. It has one signature:
PROCEDURE ORD ( value : <CharOrEnumType> ) : CARDINAL;
Function CHR
is a polymorphic function to return the character whose code point matches its parameter. It has one signature:
PROCEDURE CHR ( codePoint : <OctetOrCardinalOrLongcard> ) : <Char Or Unichar?>;
Function EXISTS
is a polymorphic function to test whether a given value for a given key is already present in a dictionary. It returns TRUE
if the value is present, otherwise FALSE
. It has one signature:
PROCEDURE EXISTS ( dict : <DictionaryType>; key : <KeyType>; value : <ValueType> ) : BOOLEAN;
Function COUNT
is a polymorphic function to return the number of values stored in a collection. It has two signatures:
PROCEDURE COUNT ( c : <CollectionType> ) : LONGCARD;
PROCEDURE COUNT ( c : <DictionaryType>; key : <KeyType> ) : LONGCARD;
Function LENGTH
is a polymorphic function to return the number of values stored in a character string. It has one signature:
PROCEDURE LENGTH ( s : <CharacterStringType> ) : LONGCARD;
Function PTR
is a polymorphic function to return a typed pointer to a variable provided its type is compatible with the target type of a passed in pointer type. It has one signature:
PROCEDURE PTR ( v : <AnyType>; T : <PointerType> ) : <T>;
Function FIRST
is a polymorphic function to return the first value of an ordered collection. It has one signature:
PROCEDURE FIRST ( c : <CollectionType> ) : <ValueType>;
Function LAST
is a polymorphic function to return the last value of an ordered collection. It has one signature:
PROCEDURE LAST ( c : <CollectionType> ) : <ValueType>;
Function MIN
is a polymorphic function to return the smallest value from a list of scalar or ordinal values. It has one signature:
PROCEDURE MIN ( values : ARGLIST >0 OF <ScalarOrOrdinalType> ) : <OperandType>;
Function MAX
is a polymorphic function to return the largest value from a list of scalar or ordinal values. It has one signature:
PROCEDURE MAX ( values : ARGLIST >0 OF <ScalarOrOrdinalType> ) : <OperandType>;
An Invocation of TMIN
is replaced by the smallest legal value of a scalar or ordinal type given as its argument. It has one signature:
PROCEDURE TMIN ( T : <ScalarOrOrdinalTypeIdentifier> ) : <T>;
An Invocation of TMAX
is replaced by the largest legal value of a scalar or ordinal type given as its argument. It has one signature:
PROCEDURE TMAX ( T : <ScalarOrOrdinalTypeIdentifier> ) : <T>;
An Invocation of TLIMIT
is replaced by the capacity limit of the collection type given as its argument. It has one signature:
PROCEDURE TLIMIT ( T : <CollectionTypeIdentifier> ) : LONGCARD;
An Invocation of TSIZZE
is replaced by the allocation size required for an instance of the type given as its argument. It has one signature:
PROCEDURE TSIZE ( T : <TypeIdentifier> ) : LONGCARD;
PROCEDURE TODO ( msg : <String Literal?> );
PROCEDURE TODO ( msg : <StringLiteral> );
PROCEDURE REMOVE ( VAR set : <SetType>; elements : ARGLIST OF <ElementType> );
PROCEDURE REMOVE ( VAR set : <SetType>; elements : ARGLIST >0 OF <ElementType> );
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 message. It has one signature:
PROCEDURE TODO ( msg : <String Literal?> );
PROCEDURE INSERT ( VAR set : <SetType>; elements : ARGLIST OF <ElementType> );
PROCEDURE INSERT ( VAR set : <SetType>; elements : ARGLIST >0 OF <ElementType> );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST OF { key : <KeyType>; value : <ValueType> } );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST >0 OF { key : <KeyType>; value : <ValueType> } );
PROCEDURE INSERT ( VAR seq : <SeqType>; atIndex : <IndexType>; values : ARGLIST OF <ValueType> );
PROCEDURE INSERT ( VAR seq : <SeqType>; atIndex : <IndexType>; values : ARGLIST >0 OF <ValueType> );
PROCEDURE APPEND ( VAR seq : <SeqType>; values : ARGLIST OF <ValueType> );
PROCEDURE APPEND ( VAR seq : <SeqType>; values : ARGLIST >0 OF <ValueType> );
PROCEDURE REMOVE ( VAR dict : <DictType>; values : ARGLIST OF <KeyType> } );
PROCEDURE REMOVE ( VAR dict : <DictType>; values : ARGLIST >0 OF <KeyType> } );
PROCEDURE WRITEF ( CONST fmt : ARRAY OF CHAR; CONST source : ARGLIST OF <SourceType> );
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 OF <SourceType> );
PROCEDURE WRITE ( f : FILE; CONST fmt : ARRAY OF CHAR; CONST source : ARGLIST >0 OF <SourceType> );
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 four signatures:
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 array : <ArrayType>; atIndex : <IndexType>; values : ARGLIST OF <ValueType> );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST OF { key : <KeyType>; value : <ValueType> } );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST OF { key : <KeyType>; value : <ValueType> } );
PROCEDURE INSERT ( VAR seq : <SeqType>; atIndex : <IndexType>; values : ARGLIST OF <ValueType> );
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 OF <ValueType> );
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 OF <ElementType> );
PROCEDURE REMOVE ( VAR dict : <DictType>; values : ARGLIST OF <KeyType> } );
PROCEDURE REMOVE ( VAR seq : <SeqType>; startIndex, endIndex : <IndexType>; );
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 );
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 );
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> );
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> );
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> );
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 OF <SourceType> );
PROCEDURE WRITE ( f : FILE; CONST fmt : ARRAY OF CHAR; CONST source : ARGLIST OF <SourceType> );
PROCEDURE INSERT ( VAR set : <Set Type>; elements : ARGLIST OF <Element Type?> );
PROCEDURE INSERT ( VAR set : <SetType>; elements : ARGLIST OF <ElementType> );
PROCEDURE INSERT ( VAR array : <Array Type>; atIndex : <Index Type?>; values : ARGLIST OF <Value Type?> );
PROCEDURE INSERT ( VAR array : <ArrayType>; atIndex : <IndexType>; values : ARGLIST OF <ValueType> );
PROCEDURE INSERT ( VAR dict : <Dict Type?>; values : ARGLIST OF { key : <Key Type?>; value : <Value Type?> } );
PROCEDURE INSERT ( VAR dict : <DictType>; values : ARGLIST OF { key : <KeyType>; value : <ValueType> } );
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 four signatures:
PROCEDURE INSERT ( VAR set : <Set Type>; elements : ARGLIST OF <Element Type?> );
PROCEDURE INSERT ( VAR array : <Array Type>; atIndex : <Index Type?>; values : ARGLIST OF <Value Type?> );
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
APPEND
REMOVE
SORT
SORTNEW
READ
READNEW
WRITE
WRITEF
ABS
ODD
PRED
SUCC
ORD
CHR
EXISTS
COUNT
LENGTH
PTR
FIRST
LAST
MIN
MAX
TMIN
TMAX
TLIMIT
TSIZE
TSIZE(BOOLEAN) = 1 (* one octet *)@]
TSIZE(BOOLEAN) = 2 (* 2 octets *)@]
TO DO
Type UNICHAR
is a container type for Unicode character values. Its size is always 32-bit. 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
.
Type OCTET
is an unsigned integer type that represents a storage unit of eight bits. The type is defined as:
Type OCTET
is an unsigned whole number type that represents a storage unit of eight bits. Its parameters are:
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 is defined as:
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:
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.
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) = 1 (* one octet *)
CHAR
Type CHAR
is an ordinal type for 7-bit character values. It is defined as:
TYPE CHAR = ( CHR(0) .. CHR(127) ); TMIN(CHAR) = CHR(0) TMAX(CHAR) = CHR(127) TSIZE(CHAR) = 1 (* 1 octet *)
UNICHAR
TO DO
OCTET
Type OCTET
is an unsigned integer type that represents a storage unit of eight bits. The type is defined as:
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 is defined as:
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
TO DO
LONGREAL
TO DO
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
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
SORTNEW
(t, s, order)
sorts values of source collection s
into newly allocated target collection t
SORTNEW
(t, s, order)
sorts values of source collection s
into newly allocated target collection t
WRITEF
(f, fmtStr, x, ...)
writes x
formatted to file or channel f
WRITEF
(f, fmtStr, x, ...)
writes one or more values formatted to file or channel f
READ
(f, x)
invokes TypeOf(x).Read(f, x)
READNEW
(f, x)
invokes TypeOf(x).Read(f, x)
WRITE
(f, x)
invokes TypeOf(x).Write(f, x)
WRITEF
(f, fmtStr, x, ...)
invokes TypeOf(x).WriteF(f, fmtStr, x, ...)
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 x
formatted to file or channel f
where TypeOf(x)
means the identifier of type x.
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)
invokes TypeOf(x).Read(f, x)
READNEW
(f, x)
invokes TypeOf(x).Read(f, x)
WRITE
(f, x)
invokes TypeOf(x).Write(f, x)
WRITEF
(f, fmtStr, x, ...)
invokes TypeOf(x).WriteF(f, fmtStr, x, ...)
TODO
(str)
prints str
to console, causes warning in DEBUG mode, or error otherwise
where TypeOf(x)
means the identifier of type x.
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
A coroutine type is a special purpose pointer type whose target is a coroutine procedure. An associated procedure type is part of the type definition. A procedure is compatible with a coroutine type when it matches the signature of the type's associated procedure type. Coroutine types are defined using the COROUTINE
type constructor.
A coroutine type is a special purpose pointer type whose target is a coroutine. An associated procedure type is part of the type definition. A coroutine procedure is compatible with a coroutine type when it matches the signature of the type's associated procedure type. Coroutine types are defined using the COROUTINE
type constructor.
TYPE Iterator = COROUTINE ( Iterator Proc? );
TYPE Iterator = COROUTINE ( IteratorProc );
to do
A coroutine type is a special purpose pointer type whose target is a coroutine procedure. An associated procedure type is part of the type definition. A procedure is compatible with a coroutine type when it matches the signature of the type's associated procedure type. Coroutine types are defined using the COROUTINE
type constructor.
Examples:
TYPE Iterator = COROUTINE ( Iterator Proc? );
to do
A procedure type is a special purpose pointer type whose target is a procedure. The procedure's signature is part of the type definition. A procedure is compatible with a procedure type when their signatures match. Procedure types are defined using the PROCEDURE
type constructor.
Examples:
TYPE WriteStrProc = PROCEDURE ( CONST ARRAY OF CHAR ); TYPE FSM = PROCEDURE ( CONST ARRAY OF CHAR, FSM );
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it must not be zero.
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it may not be zero.
TYPE `String = ARRAY 100 OF CHAR; (* compile time error *) TYPE `String = ARRAY < 100 OF CHAR; (* supported definition *)
TYPE String = ARRAY 100 OF CHAR; (* compile time error: unsupported definition *) TYPE String = ARRAY < 100 OF CHAR; (* OK, supported character array type definition *)
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every assign, append and concatenation operation.
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. An attempt to define a rigid character array type shall cause a compile time error.
Examples:
TYPE `String = ARRAY 100 OF CHAR; (* compile time error *) TYPE `String = ARRAY < 100 OF CHAR; (* supported definition *)
The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every assign, append and concatenation operation.
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it must not be zero.
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it must not be zero.
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every append and concatenation operation.
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every assign, append and concatenation operation.
For security reasons, array types with value types CHAR
and UNICHAR
may only be defined as flexible array types. Rigid character array types are not supported. The instances of character array types are initialised with a single NUL character and compliant implementations must ensure that they are NUL terminated after every append and concatenation operation.
Instances of flexible arrays may further be sliced and concatenated. Flexible array types are slice and concatenation compatible as long as their value types are compatible.
Instances of flexible arrays may further be sliced and concatenated. Flexible array types and their slices are insertion and concatenation compatible as long as the respective value types are compatible.
array1[4..6] := { 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array1[4..5] := { 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array2 := { 1, 2, 3, 4 }; array3 := { 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 4, 8, 9 } *) array1[4..6] := { 5, 6, 7 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array2 := { 1, 2, 3, 4 }; array3 := { 7, 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 4, 7, 8, 9 } *) array1[4..6] := { 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array2 := { 1, 2, 3 }; array3 := { 7, 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 7, 8, 9 } *) array1[3..5] := { 4, 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array2 := { 1, 2, 3, 4 }; array3 := { 8, 9 }; array1 := array2 & array3; (* concatenation : { 1, 2, 3, 4, 8, 9 } *) array1[4..6] := { 5, 6, 7 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array1 := array2 & array3; (* concatenation results in { 1, 2, 3, 7, 8, 9 } *) array1[3..5] := { 4, 5, 6 }; (* sliced insertion results in { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
array1 := array2 & array3; (* concatenation : { 1, 2, 3, 7, 8, 9 } *) array1[3..5] := { 4, 5, 6 }; (* sliced insert : { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
An array type may be defined either rigid or flexible. The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be added, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be added, inserted and removed at runtime. A flexible array is defined by prefixing the value count parameter in the type definition with the <
symbol.
An array type may be defined to hold a variable number of values by prefixing the value count parameter in the type's definition with the <
symbol. The type's capacity is one less than the specified value count and it must not be zero.
The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be appended, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be appended, inserted and removed at runtime.
Examples:
VAR array : FlexArray; array := { 42, -5, 0 }; (* initialise with three values *) APPEND(array, -35); (* append a value *) INSERT(array, 0, 11); (* value insertion *) REMOVE(array, 3, 1); (* value removal *)
Instances of flexible arrays may further be sliced and concatenated. Flexible array types are slice and concatenation compatible as long as their value types are compatible.
Examples:
VAR array1, array2, array3 : FlexArray; array2 := { 1, 2, 3 }; array3 := { 7, 8, 9 }; array1 := array2 & array3; (* concatenation results in { 1, 2, 3, 7, 8, 9 } *) array1[3..5] := { 4, 5, 6 }; (* sliced insertion results in { 1, 2, 3, 4, 5, 6, 7, 8, 9 } *)
An array type is defined to be rigid or flexible. The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be added, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be added, inserted and removed at runtime. A flexible array is defined with an upper open bound by prefixing the value count parameter in the type definition with the <
symbol.
An array type may be defined either rigid or flexible. The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be added, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be added, inserted and removed at runtime. A flexible array is defined by prefixing the value count parameter in the type definition with the <
symbol.
An array type is an indexed collection type whose values are of a single arbitrary type, called the array's value type. The type's capacity is specified by a value count parameter in the type definition. The capacity must be whole number value and it may not be zero. Array types are defined using the ARRAY
OF
type constructor.
An array type is an indexed collection type whose values are of a single arbitrary type, called the array's value type. The type's capacity is specified by a value count parameter in the type definition. The capacity must be a whole number value and it may not be zero. Array types are defined using the ARRAY
OF
type constructor.
An instance of an array type holds exactly the number of values given by the value count parameter in the type definition. Values are addressable by cardinal index using subscript notation. The lowest index is always zero.
The values of an array instance are addressable by cardinal index using subscript notation. The lowest index is always zero.
An array type is defined to be rigid or flexible. The instance of a rigid array type always holds exactly the number of values that equals the type's capacity. No values may be added, inserted or removed at runtime. By contrast, the instance of a flexible array type may hold a variable number of values. Within the limits of the type's capacity, values may be added, inserted and removed at runtime. A flexible array is defined with an upper open bound by prefixing the value count parameter in the type definition with the <
symbol.
Example:
TYPE FlexArray = ARRAY < 10 OF INTEGER;
An array type is an indexed collection type whose values are all of the same type and addressable by cardinal index. The lowest index is always zero. Array types are defined using the ARRAY
OF
type constructor. The type's capacity is specified by the component count parameter which shall be of an unsigned whole number type and its value shall never be zero.
An array type is an indexed collection type whose values are of a single arbitrary type, called the array's value type. The type's capacity is specified by a value count parameter in the type definition. The capacity must be whole number value and it may not be zero. Array types are defined using the ARRAY
OF
type constructor.
An instance of an array type may hold multiple values up to its capacity. Values are addressable by cardinal index.
An instance of an array type holds exactly the number of values given by the value count parameter in the type definition. Values are addressable by cardinal index using subscript notation. The lowest index is always zero.
VAR array : IntArray; int : INTEGER;
VAR array : IntArray; int : INTEGER;
A pointer type may be defined to have an immutable target.
A pointer type may be defined to restrict the mutability of its target.
Although the instance of such a pointer itself is mutable, its target is not. A dereferenced instance may not be used as an L-value and it may not be passed to a procedure as a VAR parameter. Pointers to mutable and immutable targets are therefore always incompatible. Any violation shall cause a compile time error.
Although the instance of such a pointer itself is mutable, its target is always treated immutable. A dereferenced instance may not be used as an L-value and it may not be passed to a procedure as a VAR
parameter. Pointers to mutable and immutable targets are therefore always incompatible. Any violation shall cause a compile time error.
to do
A pointer type is a container for a typed reference to an entity at a memory storage location. The type of the referenced entity is called the target type. The entity referenced by an instance of a pointer type is called the pointer's target. Pointer types are defined using the POINTER
TO
type constructor.
Example:
TYPE IntPtr = POINTER TO INTEGER;
Typed references are created using predefined procedure PTR
. Instances of pointer types are dereferenced using the pointer dereferencing operator ^
.
Example:
VAR int : INTEGER; intPtr : IntPtr; intPtr := PTR(int, IntPtr); (* obtain a typed reference to int *) intPtr^ := 0; (* write to int via dereferenced pointer intPtr *)
A pointer type may be defined to have an immutable target.
Example:
TYPE ImmIntPtr = POINTER TO CONST INTEGER;
Although the instance of such a pointer itself is mutable, its target is not. A dereferenced instance may not be used as an L-value and it may not be passed to a procedure as a VAR parameter. Pointers to mutable and immutable targets are therefore always incompatible. Any violation shall cause a compile time error.
Example:
VAR int : INTEGER; intPtr : IntPtr; immPtr : ImmIntPtr; intPtr := PTR(int, IntPtr); immPtr := PTR(int, ImmIntPtr); intPtr^ := 0; (* OK, modifying a mutable target *) immPtr^ := 0; (* compile time error due to attempt to modify an immutable target *)
The RETAIN
statement is used to retain a reference to an instance of a reference counted dynamically allocatable type to prevent its premature deallocation. The RETAIN
statement may only be used for instances of reference counted types. Non-compliance shall cause a compile time error.
The RETAIN
statement is used to retain a reference to an instance of a reference counted dynamically allocatable type to prevent its premature deallocation. The RETAIN
statement may therefore only be used for instances of reference counted types. Non-compliance shall cause a compile time error.
The RETAIN
statement is used to retain a reference to an instance of a reference counted dynamically allocatable type to prevent its premature deallocation.
The RETAIN
statement is used to retain a reference to an instance of a reference counted dynamically allocatable type to prevent its premature deallocation. The RETAIN
statement may only be used for instances of reference counted types. Non-compliance shall cause a compile time error.
The NEW
statement is used to dynamically allocate storage at runtime.
The NEW
statement is used to dynamically allocate storage for a new instance of a dynamically allocatable type.
The NEW
statement is used to retain a dynamically allocated entity to prevent its premature deallocation.
The RETAIN
statement is used to retain a reference to an instance of a reference counted dynamically allocatable type to prevent its premature deallocation.
Example:
RETAIN dict;
The RELEASE
statement is used to cancel a previous RETAIN
operation for a dynamically allocated entity and deallocate the entity if no further retains are outstanding.
The RELEASE
statement is used to release a reference for an instance of a reference counted dynamically allocatable type and thereby cancel an earlier retain operation. If no further retains are outstanding or if the target is not reference counted, the target is deallocated.
Example:
RELEASE dict;
to do
The NEW
statement is used to dynamically allocate storage at runtime.
to do
The NEW
statement is used to retain a dynamically allocated entity to prevent its premature deallocation.
to do
The RELEASE
statement is used to cancel a previous RETAIN
operation for a dynamically allocated entity and deallocate the entity if no further retains are outstanding.
The RETURN
statement is used within a procedure body to return control to its caller and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance with these requirements shall cause a compile time error.
The RETURN
statement is used within a procedure body to return control to its caller and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance shall cause a compile time error.
The YIELD
statement is used within a coroutine procedure body to suspend the coroutine and pass control to its caller. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When yielding from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance with these requirements shall cause a compile time error.
The YIELD
statement is used within a coroutine procedure body to suspend the coroutine and pass control to its caller. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When yielding from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance shall cause a compile time error.
EXIT
StatementThe EXIT
statement is used within the body of a WHILE
, REPEAT
, LOOP
or FOR
statement to terminate execution of the statement's body and transfer control to the first statement after the loop body. The EXIT
statement may only occur within the body of loop statements. Non-compliance shall cause a compile time error.
Example:
LOOP ch := nextChar(stdIn); CASE ch OF | ASCII.ESC : EXIT | (* other case labels ... *)
The RETURN
statement is used within a procedure body to return control to the calling procedure and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance with these requirements shall cause a compile time error.
The RETURN
statement is used within a procedure body to return control to its caller and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance with these requirements shall cause a compile time error.
The YIELD
statement is used within a coroutine procedure body to suspend itself and pass control to the calling procedure. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When returning from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance with these requirements shall cause a compile time error.
The YIELD
statement is used within a coroutine procedure body to suspend the coroutine and pass control to its caller. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When yielding from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance with these requirements shall cause a compile time error.
PROCEDURE successor ( x : CARDINAL ) : CARDINAL;
PROCEDURE successor ( n : CARDINAL ) : CARDINAL;
RETURN x + 1
RETURN n + 1
RETURN -1;
RETURN -1
RETURN
StatementThe RETURN
statement is used within a procedure body to return control to the calling procedure and in the main body of the program to return control to the operating environment that activated the program. A RETURN
statement may or may not return a value, depending on the type of the procedure in which it is invoked. When returning from a regular procedure, no value may be returned. When returning from a function procedure a value of the procedure's return type must be returned. Non-compliance with these requirements shall cause a compile time error.
Example:
PROCEDURE successor ( x : CARDINAL ) : CARDINAL; BEGIN RETURN x + 1 END successor;
YIELD
StatementThe YIELD
statement is used within a coroutine procedure body to suspend itself and pass control to the calling procedure. A YIELD
statement may or may not yield a value, depending on the type of the coroutine procedure in which it is invoked. When yielding from a regular procedure, no value may be yielded. When returning from a function procedure a value of the procedure's return type must be yielded. The YIELD
statement may only occur within the body of coroutine procedures. Non-compliance with these requirements shall cause a compile time error.
Example:
PROCEDURE [COROUTINE] iterator ( CONST array : ARRAY OF INTEGER ) : INTEGER; BEGIN FOR value IN array DO YIELD value END; RETURN -1; END iterator;
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any field of the base type is always a field of any extension type derived from it, but not every field of an extension type is also a field of the base type.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. All fields of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any field of the base type is always a field of any extension type derived from it, but not every field of an extension type is also a field of the base type.
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
TYPE Colour = ( red, green, blue ); (* ORD(red) => 0 *)
TYPE BaseColour = [red .. blue] OF Colour; (* unqualified *)
TYPE BaseColour = [red .. green] OF Colour; (* unqualified *)
TYPE Colour = ( red, green, blue ); TYPE MoreColour = ( +MoreColour, orange, magenta, cyan );
TYPE MoreColour = ( +Colour, orange, magenta, cyan );
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any value set of the base type is always a legal value set of any extension type derived from it, but value sets of an extension type are not legal values of the base type.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any field of the base type is always a field of any extension type derived from it, but not every field of an extension type is also a field of the base type.
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type. The base type is downwards compatible with any extended types derived from it, but extensions are not upwards compatible with their base type. This restriction is imposed because any value of the base type is always a legal value of any extension type derived from it, but not every value of an extension type is also a legal value of the base type.
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type. The base type is downwards compatible with any extended types derived from it, but extensions are not upwards compatible with their base type. This restriction exists because any value of the base type is always a legal value of any extension type derived from it, but not every value of an extension type is also a legal value of the base type.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction is imposed because any value set of the base type is always a legal value set of any extension type derived from it, but value sets of an extension type are not legal values of the base type.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction exists because any value set of the base type is always a legal value set of any extension type derived from it, but value sets of an extension type are not legal values of the base type.
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type.
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type. The base type is downwards compatible with any extended types derived from it, but extensions are not upwards compatible with their base type. This restriction is imposed because any value of the base type is always a legal value of any extension type derived from it, but not every value of an extension type is also a legal value of the base type.
A record type may be defined as an extension of another by giving the identifier of the base type in parentheses before the field list declaration. The field declarations of of the base type become fields of the new type. The field names of the base type may therefore not be reused in the extension type's own field list declaration. The base type is downwards compatible with any extended types derived from it, but type extensions are not upwards compatible with their base type. This restriction is imposed because any value set of the base type is always a legal value set of any extension type derived from it, but value sets of an extension type are not legal values of the base type.
Examples:
TYPE ColourPoint = RECORD ( Point ) colour : Colour END; VAR cPoint : ColourPoint; cPoint := { 0.0, 0.0, Colour.red }; (* initialise all fields *) cPoint.x := 1.5; cPoint.y := 0.75;
to do
A record type is a compound type whose components are of arbitrary types. The components are called fields. The number of fields is arbitrary. Record types are defined using the RECORD
type constructor.
Example:
TYPE Point = RECORD x, y : REAL END;
An instance of a record type holds exactly one value for each field. Fields are addressable by selector.
Examples:
VAR point : Point; r : REAL; record := { 0.0, 0.0 }; (* initialise all fields with zero *) r := point.x; (* field retrieval *) point.y := 0.75; (* field storage *)
array := { 0 BY TLIMIT(IntArray) }; (* initialise all values with zero *)
array := { 0 BY 10 }; (* initialise all values with zero *)
colours[Colour.blue] := TRUE; (* membership modification *)
colours[Colour.blue] := TRUE; (* membership storage *)
An array type is an indexed collection type whose values are all of the same type and addressable by cardinal index. The lowest index is always zero. Array types are defined using the ARRAY
OF
type constructor. Its capacity is specified by the component count parameter which shall be of an unsigned whole number type and its value shall never be zero.
An array type is an indexed collection type whose values are all of the same type and addressable by cardinal index. The lowest index is always zero. Array types are defined using the ARRAY
OF
type constructor. The type's capacity is specified by the component count parameter which shall be of an unsigned whole number type and its value shall never be zero.
An instance of an array type may hold multiple values up to its capacity. Values are addressable by cardinal index.
Examples:
VAR array : IntArray; int : INTEGER; array := { 0 BY 10 }; (* initialise all values with zero *) int := array[5]; (* value retrieval *) array[5] := 42; (* value storage *)
Example:
Examples:
to do
An array type is an indexed collection type whose values are all of the same type and addressable by cardinal index. The lowest index is always zero. Array types are defined using the ARRAY
OF
type constructor. Its capacity is specified by the component count parameter which shall be of an unsigned whole number type and its value shall never be zero.
Example:
TYPE IntArray = ARRAY 10 OF INTEGER;
The allocation size of an enumeration type is always 16 bit. Its maximum value range is 65536 values.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type of up to 256 values. The values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type of up to 256 values. The values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type. Values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type of up to 256 values. The values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
to do
A set type is a collection type whose storable values are defined by the legal values of an associated enumeration type. Values stored in a set are also called elements of the set and the associated enumeration type is called its element type. A set type is defined using the SET
OF
type constructor.
Example:
TYPE ColourSet = SET OF Colour;
An instance of a set type may hold multiple elements but any given element may be stored at most once. An element stored in a set is said to be a member of the set. A set is represented as an array of boolean membership values, where the element is the accessor and the membership is the value. A membership value may thus be either TRUE
or FALSE
.
Example:
VAR colours : ColourSet; isMember : BOOLEAN; colours := { Colour.red, Colour.green }; (* assignment *) isMember := colours[Colour.green]; (* membership retrieval *) colours[Colour.blue] := TRUE; (* membership modification *)
VAR colour : Colour; colour := Colour.green; (* qualified *)
VAR colour : Colour; colour := Colour.green; (* qualified *)
An enumeration type may be defined as an extension of another by listing the identifier of the base type as the first item in the enumerated value list prefixed by the +
symbol. All enumerated values of the base type become legal values of the new type.
Example:
TYPE Colour = ( red, green, blue ); TYPE MoreColour = ( +MoreColour, orange, magenta, cyan ); (* equivalent to: MoreColour = ( red, green, blue, orange, magenta, cyan );
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
TYPE Base Colour? = [red .. blue] OF Colour; (* unqualified *)
TYPE BaseColour = [red .. blue] OF Colour; (* unqualified *)
to do
to do
to do
An enumeration type is an ordinal type whose legal values are defined by a list of identifiers. The identifiers are assigned ordinal values from left to right as they appear in the type definition. The ordinal value assigned to the leftmost identifier is always zero.
Example:
TYPE Colour = ( red, green, blue, orange, magenta, cyan ); (* ORD(red) => 0 *)
When referencing an enumerated value, its identifier must be qualified with its type identifier, except within a subrange type constructor. This requirement fixes a flaw in classic Modula-2 where the import of an enumeration type could cause name conflicts.
Example:
TYPE Base Colour? = [red .. blue] OF Colour; (* unqualified *)
VAR colour : Colour; colour := Colour.green; (* qualified *)
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol.
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol. An open bound of a subrange type is not a legal value of the type.
TYPE CoreColours = [red .. blue] OF Colours;
TYPE CoreColours = [red .. blue] OF Colours;
TYPE BaseColours = [red .. blue] OF Colours;
TYPE CoreColours = [red .. blue] OF Colours; TYPE Radian = [0.0 .. tau] OF REAL;
For subrange types of non-countable scalar types, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol.
For subrange types of scalar types that represent real numbers, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol.
TYPE Radian = [0.0 .. tau] OF REAL;
TYPE Base Colours? = [red .. blue] OF Colours;
TYPE BaseColours = [red .. blue] OF Colours;
TYPE PosReal = [>0.0 .. TMAX(REAL)] OF REAL; TYPE NegReal = [TMIN(REAL) .. <0.0] OF REAL;
A subrange type is a type defined as a subset of a scalar or ordinal type. A subrange type is upwards compatible with its base type, but the base type is not downwards compatible with any subrange types derived from it. A subrange type inherits all its properties from its base type, except for its lower and upper bound. A subrange type's lower and upper bound must be specified in its type definition. Both lower and upper bound must be compatible with the base type and they must be legal values of the base type.
Examples:
TYPE Base Colours? = [red .. blue] OF Colours;
TYPE Natural = [1 .. TMAX(CARDINAL)] OF CARDINAL;
For subrange types of non-countable scalar types, lower and upper bounds may be specified as open bounds. An open lower bound is prefixed by the >
symbol. An open upper bound is prefixed by the <
symbol.
to do
to do
to do
to do
to do
to do
to do
to do
to do
ALIAS
Typesto do
to do
to do
to do
to do
to do
to do
to do
FOR key IN dict DO dict[key] := EMPTY END;
FOR key IN dict DO WRITE(key) END;
The iterable is an instance of an ARRAY OF
type or array ADT.
The iterable is an instance of an ARRAY
OF
type or array ADT.
The iterable is an instance of a SET OF
type or set ADT.
The iterable is an instance of a SET
OF
type or set ADT.
The iterable is an instance of an array ADT or ARRAY OF
type.
The iterable is an instance of an ARRAY OF
type or array ADT.
The iterable is an instance of a SET OF
type or set ADT.
Example:
FOR elem IN set DO WRITE(elem) END; FOR elem, counter IN countedSet DO WRITE(elem); WRITE(" : "); WRITE(counter); WriteLn END;
FOR index, value IN array DO value := source[index] END;
FOR index, value IN target DO value := source[index] END;
FOR key, value IN dict DO WRITE(key); WRITE(" : "); WRITE(value); WriteLn END;
FOR listNode IN list DO WRITE(listNode^.item) END; FOR VALUE item IN list DO WRITE(listElem) END;
FOR listNode IN list DO WRITE(listNode) END; FOR VALUE item IN list DO item := foo END;
FOR listNode IN list DO WRITE(`listNode^.item) END; FOR VALUE item IN list DO WRITE(`listElem) END;
FOR listNode IN list DO WRITE(listNode^.item) END; FOR VALUE item IN list DO WRITE(listElem) END;
The iterable is an instance of a list ADT.
Example:
FOR listNode IN list DO WRITE(`listNode^.item) END; FOR VALUE item IN list DO WRITE(`listElem) END;
The iterable is an instance of an array ADT or ARRAY OF
type.
Example:
FOR index IN array DO array[index] := 0 END; FOR index, value IN array DO value := source[index] END;
The iterable is an instance of a dictionary ADT.
A statement is an action that can be executed to cause a transformation of the computational state of a program. Statements are used for their effects only, they do not return any values and they may not be used within expressions. There are twelve kinds of statements:
A statement is an action that can be executed to cause a transformation of the computational state of a program. Statements are used for their effects only, they do not return any values and they may not occur within expressions. There are twelve kinds of statements:
IF
StatementIF
StatementCASE
StatementCASE
StatementWHILE
StatementWHILE
StatementREPEAT
StatementREPEAT
StatementLOOP
StatementLOOP
StatementFOR
StatementFOR
StatementIf the iterable supports directional iteration, the prevailing iteration order may be imposed by an ascender or descender following the first loop variant. An ascender imposes ascending order and is denoted by the ++
symbol. A descender imposes descending order and is denoted by the --
symbol. When no ascender nor descender is given, the prevailing iteration order is ascending. However, if the iterable does not support directional iteration, no ascender and no descender may be given and the prevailing iteration order is implementation dependent.
If the iterable supports directional iteration, the prevailing iteration order may be imposed by an ascender or descender following the first loop variant. An ascender imposes ascending order and is denoted by the ++
symbol. A descender imposes descending order and is denoted by the --
symbol. When no ascender nor descender is given, the prevailing iteration order is ascending. However, if the iterable does not support directional iteration, the prevailing iteration order is implementation dependent and no ascender and no descender may be given.
If the iterable supports directional iteration, ascending or descending iteration order may be imposed by an ascender or descender following the first loop variant. An ascender is denoted by the ++
symbol. A descender is denoted by the --
symbol. The default iteration order — when no ascender nor descender is given — is always ascending. However, if the iterable does not support directional iteration, no ascender and no descender may be given and the iteration order is implementation dependent.
If the iterable supports directional iteration, the prevailing iteration order may be imposed by an ascender or descender following the first loop variant. An ascender imposes ascending order and is denoted by the ++
symbol. A descender imposes descending order and is denoted by the --
symbol. When no ascender nor descender is given, the prevailing iteration order is ascending. However, if the iterable does not support directional iteration, no ascender and no descender may be given and the prevailing iteration order is implementation dependent.
If the iterable entity is an ordinal type or a subrange thereof, only one loop variant may be given. The loop variant is immutable. Its type is the ordinal type or subrange given as iterable entity in the loop header and the loop iterates over all values of the given iterable entity. There are three use cases:
If the iterable is an ordinal type or a subrange thereof, only one loop variant may be given. The loop variant is immutable. Its type is the ordinal type or subrange given as iterable and the loop iterates over all values of the given iterable. There are three use cases:
The iterable entity is type CHAR or a subrange thereof.
The iterable is type CHAR or a subrange thereof.
The iterable entity is an enumeration type or a subrange thereof.
The iterable is an enumeration type or a subrange thereof.
The iterable entity is a whole number type or a subrange thereof.
The iterable is a whole number type or a subrange thereof.
If the iterable entity is an instance of a collection type, one or two loop variants may be given. The accessor is always immutable. Its type is the accessor type of the iterable entity. If the iterable entity is mutable, the value is mutable, otherwise immutable. Its type is the value type of the iterable entity. The loop iterates over all accessor/value pairs of the given iterable entity. There are four use cases:
If the iterable is an instance of a collection type, one or two loop variants may be given. The accessor is always immutable. Its type is the accessor type of the iterable entity. If the iterable entity is mutable, the value is mutable, otherwise immutable. Its type is the value type of the iterable. The loop iterates over all accessor/value pairs of the given iterable. There are four use cases:
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. During the first iteration cycle the loop variant or variants reference that accessor, value or accessor/value pair which is first for the prevailing iteration order. Before each subsequent iteration cycle the loop variant or variants are advanced to its current successor for the prevailing iteration order. Iteration continues until all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop. During the first iteration cycle the loop variant or variants reference that accessor, value or accessor/value pair which is first for the prevailing iteration order. Before each subsequent iteration cycle the loop variant or variants are advanced to its current successor for the prevailing iteration order. Iteration continues until all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. During the first iteration cycle the loop variant or variants reference that accessor, value or accessor/value pair which is first for the prevailing iteration order. Upon each iteration cycle the loop variant or variants are advanced to its current successor for the prevailing iteration order until all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. During the first iteration cycle the loop variant or variants reference that accessor, value or accessor/value pair which is first for the prevailing iteration order. Before each subsequent iteration cycle the loop variant or variants are advanced to its current successor for the prevailing iteration order. Iteration continues until all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until all accessor/value pairs have been visited.
The composition of the loop variant section depends on the iterable. If it is an ordinal type or subrange, the loop variant section may only contain a single variant and it is always immutable within the loop body. If the iterable is a collection instance, the loop variant section may contain one or two loop variants representing the collection's accessor, its value or both. If the accessor is to be omitted, the loop variant must be prefixed with VALUE
. An accessor is always immutable within the loop body. For mutable collections, the value is mutable, for immutable collections it is immutable.
The composition of the loop variant section depends on the iterable. If it is an ordinal type or subrange, the loop variant section may only contain a single variant and it is always immutable within the loop body. If the iterable is a collection instance, the loop variant section may contain one or two loop variants representing the collection's accessor, its value or both. If the accessor is to be omitted, the loop variant must be prefixed with VALUE
. An accessor is always immutable within the loop body. A value is mutable within the loop body if the iterable is mutable, otherwise immutable.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. During the first iteration cycle the loop variant or variants reference that accessor, value or accessor/value pair which is first for the prevailing iteration order. Upon each iteration cycle the loop variant or variants are advanced to its current successor for the prevailing iteration order until all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body, once the loop has terminated, the variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body. Once a FOR
loop has terminated, its loop variants are no longer in scope.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited. Loop variant identifiers are only in scope within the loop header and body, once the loop has terminated, the variants are no longer in scope.
The composition of the loop variant section depends on the iterable. If it is an ordinal type or subrange, the loop variant section may only contain a single variant and it is always immutable within the loop body. If the iterable is a collection instance, the loop variant section may contain one or two loop variants representing the collection's accessor, value or both. An accessor is always immutable within the loop body. For mutable collections, the value is mutable, for immutable collections it is immutable.
The composition of the loop variant section depends on the iterable. If it is an ordinal type or subrange, the loop variant section may only contain a single variant and it is always immutable within the loop body. If the iterable is a collection instance, the loop variant section may contain one or two loop variants representing the collection's accessor, its value or both. If the accessor is to be omitted, the loop variant must be prefixed with VALUE
. An accessor is always immutable within the loop body. For mutable collections, the value is mutable, for immutable collections it is immutable.
If the iterable entity supports directional iteration, ascending or descending iteration order may be imposed by an ascender or descender following the first loop variant. An ascender is denoted by the ++
symbol. A descender is denoted by the --
symbol. The default iteration order — when no ascender nor descender is given — is always ascending. However, if the iterable entity does not support directional iteration, no ascender and no descender may be used and the iteration order is implementation dependent.
If the iterable supports directional iteration, ascending or descending iteration order may be imposed by an ascender or descender following the first loop variant. An ascender is denoted by the ++
symbol. A descender is denoted by the --
symbol. The default iteration order — when no ascender nor descender is given — is always ascending. However, if the iterable does not support directional iteration, no ascender and no descender may be given and the iteration order is implementation dependent.
The iterable entity — or iterable in short – is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. If it is an ordinal type or subrange, the iterable is always immutable. If it is a collection, the iterable may be either mutable or immutable.
The iterable entity — or iterable in short – is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. An ordinal type or subrange iterable is always immutable. A collection iterable may be either mutable or immutable.
The iterable entity is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. If it is an ordinal type or subrange, the iterable entity is always immutable. If it is a collection, the iterable entity may be either mutable or immutable.
The iterable entity — or iterable in short – is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. If it is an ordinal type or subrange, the iterable is always immutable. If it is a collection, the iterable may be either mutable or immutable.
The composition of the loop variant section depends on the iterable entity. If the iterable entity is an ordinal type or subrange, the loop variant section may only contain a single variant which is always immutable within the loop body. If the iterable entity is a collection instance, the loop variant section may contain one or two loop variants denoting the accessor, the value or both. The accessor is always immutable within the loop body. For mutable collections, the value is mutable. For immutable collections the value is immutable.
The loop variant section contains one or two identifiers through which accessors and values of the iterable are referenced within the loop body. Upon each iteration cycle, the loop variant or variants are advanced to the next accessor, value or accessor/value pair. Iteration stops when all accessors and/or values have been visited.
The composition of the loop variant section depends on the iterable. If it is an ordinal type or subrange, the loop variant section may only contain a single variant and it is always immutable within the loop body. If the iterable is a collection instance, the loop variant section may contain one or two loop variants representing the collection's accessor, value or both. An accessor is always immutable within the loop body. For mutable collections, the value is mutable, for immutable collections it is immutable.
The FOR
statement is used to iterate over an iterable entity and execute a statement or statement sequence during each iteration cycle. It consists of a loop header and a loop body. The loop header consists of one or two loop variants, optionally the iteration order, and the iterable entity. The loop body consists of a statement or statement sequence.
The FOR
statement is used to iterate over an iterable entity and execute a statement or statement sequence during each iteration cycle. It consists of a loop header and a loop body. The loop header consists of one or two loop variants, an optional iteration order, and the iterable entity. The loop body consists of a statement or statement sequence.
The iterable entity is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type.
The iterable entity is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type. If it is an ordinal type or subrange, the iterable entity is always immutable. If it is a collection, the iterable entity may be either mutable or immutable.
The composition of the loop variant section depends on the iterable entity. If the iterable entity is an ordinal type or subrange, the loop variant section may only contain a single variant which is always immutable. If the iterable entity is a collection instance, the loop variant section may contain one or two loop variants denoting the accessor, the value or both.
The composition of the loop variant section depends on the iterable entity. If the iterable entity is an ordinal type or subrange, the loop variant section may only contain a single variant which is always immutable within the loop body. If the iterable entity is a collection instance, the loop variant section may contain one or two loop variants denoting the accessor, the value or both. The accessor is always immutable within the loop body. For mutable collections, the value is mutable. For immutable collections the value is immutable.
The FOR
statement is used to repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until all accessor/value pairs have been visited.
to do: paragraph on loop variants and iterable entities
If the iterable entity is ordered and bidirectionally iterable, an ascender or descender may be given in the loop header to impose ascending or descending iteration order. The default iteration order — when no ascender nor descender is given — is ascending. If the iterable entity is unordered or if it is only unidirectionally iterable, no ascender and no descender may be given in the loop header. In this case, if ordered, the iteration order is ascending, and if unordered, the iteration order is implementation defined.
The FOR
statement is used to iterate over an iterable entity and execute a statement or statement sequence during each iteration cycle. It consists of a loop header and a loop body. The loop header consists of one or two loop variants, optionally the iteration order, and the iterable entity. The loop body consists of a statement or statement sequence.
The iterable entity is denoted by an identifier of an ordinal type or subrange, an anonymous subrange of an ordinal type, or a designator of an instance of a collection type.
The composition of the loop variant section depends on the iterable entity. If the iterable entity is an ordinal type or subrange, the loop variant section may only contain a single variant which is always immutable. If the iterable entity is a collection instance, the loop variant section may contain one or two loop variants denoting the accessor, the value or both.
If the iterable entity supports directional iteration, ascending or descending iteration order may be imposed by an ascender or descender following the first loop variant. An ascender is denoted by the ++
symbol. A descender is denoted by the --
symbol. The default iteration order — when no ascender nor descender is given — is always ascending. However, if the iterable entity does not support directional iteration, no ascender and no descender may be used and the iteration order is implementation dependent.
repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until all accessor/value pairs have been visited.
If the iterable entity is an instance of a collection type, one or two loop variants may be given. The accessor is always immutable. Its type is the accessor type of the iterable entity. If the iterable entity is mutable, the value is mutable, otherwise immutable. Its type is the value type of the iterable entity. The loop iterates over all accessor/value pairs of the given iterable entity. There are four use cases:
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is immutable. Its type is the ordinal type or subrange given as iterable entity in the loop header and the loop iterates over all values of the given iterable entity. There are three use cases:
If the iterable entity is an ordinal type or a subrange thereof, only one loop variant may be given. The loop variant is immutable. Its type is the ordinal type or subrange given as iterable entity in the loop header and the loop iterates over all values of the given iterable entity. There are three use cases:
The iterable entity is type CHAR or an anonymous subrange thereof.
The iterable entity is type CHAR or a subrange thereof.
The iterable entity is an enumeration type or an anonymous subrange thereof.
The iterable entity is an enumeration type or a subrange thereof.
The iterable entity is a whole number type or an anonymous subrange thereof.
The iterable entity is a whole number type or a subrange thereof.
to do: paragraph on loop variants and iterable entities
to do: paragraph on loop variants and iterable entities
FOR char IN CHAR DO WRITE(char) END; FOR char IN ["a".."z"] OF CHAR DO WRITE(char) END;
FOR ch IN CHAR DO WRITE(ch) END; FOR ch IN ["a".."z"] OF CHAR DO WRITE(ch) END;
value := pointer^^; (* pointer to pointer dereference *)
value := pointer^^; (* double pointer dereference *)
TYPE Colours = ( red, green, blue, orange, cyan, magenta );
TYPE Colours = ( red, green, blue, cyan, magenta, ... );
TYPE Colours = ( red, green, blue, orange, cyan, magenta, yellow );
TYPE Colours = ( red, green, blue, orange, cyan, magenta );
When iterating over the CHAR
type, the loop variant is of type CHAR.
The iterable entity is type CHAR or an anonymous subrange thereof.
When iterating over an enumeration type, the loop variant is of the enumeration type.
The iterable entity is an enumeration type or an anonymous subrange thereof.
When iterating over an enumeration type, the loop variant is of the whole number type.
The iterable entity is a whole number type or an anonymous subrange thereof.
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the ordinal type or subrange and it is immutable. The loop iterates over all values of the ordinal type or subrange.
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is immutable. Its type is the ordinal type or subrange given as iterable entity in the loop header and the loop iterates over all values of the given iterable entity. There are three use cases:
CHAR
type
CHAR
TypeWhen iterating over the CHAR
type, the loop variant is of type CHAR.
Example:
TYPE Colours = ( red, green, blue ); FOR colour IN Colours DO WRITE(NameOfColour(colour)) END;
Examples:
FOR char IN CHAR DO WRITE(char) END; FOR char IN ["a".."z"] OF CHAR DO WRITE(char) END;
If the iterable entity is a whole number type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the whole number type or subrange and it is immutable. The loop iterates over all values of the whole number type or subrange.
When iterating over an enumeration type, the loop variant is of the enumeration type.
Example:
TYPE Colours = ( red, green, blue, orange, cyan, magenta, yellow ); FOR colour IN Colours DO WRITE(NameOfColour(colour)) END; FOR colour IN [red..blue] OF Colours DO WRITE(NameOfColour(colour)) END;
When iterating over an enumeration type, the loop variant is of the whole number type.
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the ordinal type or subrange and the loop iterates over all values of the ordinal type or subrange.
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the ordinal type or subrange and it is immutable. The loop iterates over all values of the ordinal type or subrange.
If the iterable entity is a whole number type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the whole number type or subrange and it is immutable. The loop iterates over all values of the whole number type or subrange.
Example:
FOR number IN CARDINAL DO WRITE(BottlesOfBeer(number)) END; FOR n IN [0..9] OF CARDINAL DO array[2*n+1] := odd END; (* indices 1, 3, 5, 7, 9 *)
FOR colour IN Colours DO WRITE(Name Of Colour?(colour)) END;
FOR colour IN Colours DO WRITE(NameOfColour(colour)) END;
to do: paragraph on loop variants and iterable entities
If the iterable entity is an ordinal type or an anonymous subrange thereof, only one loop variant may be given. The loop variant is of the ordinal type or subrange and the loop iterates over all values of the ordinal type or subrange.
Example:
TYPE Colours = ( red, green, blue );
FOR colour IN Colours DO WRITE(Name Of Colour?(colour)) END;
An IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. IF
-statements must always be terminated with an END
. At most one block in the statement is executed.
An IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. At most one block in the statement is executed. IF
-statements must always be terminated with an END
.
An IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's boolean condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. IF
-statements must always be terminated with an END
. At most one block in the statement is executed.
An IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. IF
-statements must always be terminated with an END
. At most one block in the statement is executed.
The FOR
statement is used to repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until no more successor is available.
The FOR
statement is used to repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until all accessor/value pairs have been visited.
FOR
StatementThe FOR
statement is used to repeatedly execute a statement or statement sequence while iterating over all accessor/value pairs of an iterable entity. A reference to the current accessor or value or both is declared in the loop header followed by the entity to be iterated. An iterable entity may be an ordinal or whole number type, or a subrange of an ordinal or whole number type, or a collection type. Before each iteration, the current accessor/value pair is advanced to its successor until no more successor is available.
If the iterable entity is ordered and bidirectionally iterable, an ascender or descender may be given in the loop header to impose ascending or descending iteration order. The default iteration order — when no ascender nor descender is given — is ascending. If the iterable entity is unordered or if it is only unidirectionally iterable, no ascender and no descender may be given in the loop header. In this case, if ordered, the iteration order is ascending, and if unordered, the iteration order is implementation defined.
depending on a condition in form of a boolean expression. The expression is evaluated each time after the REPEAT
block has executed. the expression evaluates to TRUE
the REPEAT
block is executed, otherwise not.
IF ch IN Terminator Set? THEN
IF ch IN TerminatorSet THEN
LOOP{
StatementA LOOP
statement is used to repeat a statement or statement sequence indefinitely unless explicitly terminated by an EXIT
statement.
depending on a condition in form of a boolean expression. The expression is evaluated each time after the REPEAT
block has executed. the expression evaluates to TRUE
the REPEAT
block is executed, otherwise not.
Example:
LOOP
READ(file, ch);
IF ch IN Terminator Set? THEN
EXIT
END (* IF *)
END; (* LOOP *)
WHILE
StatementA WHILE
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time before the DO
block is executed. The DO
block is repeated as long as the expression evaluates to TRUE
.
Example:
WHILE NOT EOF(file) DO READ(file, ch) END;
REPEAT
StatementA REPEAT
statement is used to repeat a statement or statement sequence depending on a condition in form of a boolean expression. The expression is evaluated each time after the REPEAT
block has executed. the expression evaluates to TRUE
the REPEAT
block is executed, otherwise not.
Example:
REPEAT READ(file, ch) UNTIL ch = terminator END;
CASE
StatementA CASE
statement is a flow-control statement that passes control to one of a number of labeled statements or statement sequences depending on the value of an ordinal expression.
Example:
CASE colour OF | colour.red : WRITE("Red") | colour.green : WRITE("Green") | colour.blue : WRITE("Blue") ELSE UNSAFE.HALT(1) (* fatal error -- abort *) END;
A case label shall be listed at most once. If a case is encountered at runtime that is not listed in the case label list and if there is no ELSE clause, no case label statements shall be executed and no error shall result.
IF
StatementAn IF
statement is a conditional flow-control statement. It evaluates a condition in form of a boolean expression. If the condition is true then program control passes to its THEN
block. If the condition is false and an ELSIF
branch follows, then program control passes to the ELSIF
branch to evaluate that branch's boolean condition. Again, if the condition is true then program control passes to the THEN
block of the ELSIF
branch. If there are no ELSIF
branches, or if the conditions of all ELSIF
branches are false, and if an ELSE
branch follows, then program control passes to the ELSE
block. IF
-statements must always be terminated with an END
. At most one block in the statement is executed.
Example:
IF i > 0 THEN WRITE("Positive") ELSIF i = 0 THEN WRITE("Zero") ELSE WRITE("Negative") END;
Insert( tree, "Fred Flintstone", 42 ); Clear Buffers?;
Insert( tree, "Fred Flintstone", 42 ); ClearBuffers;
A procedure call statement is used to invoke a procedure. It consists of the procedure's identifier, optionally followed by a list of parameters enclosed in parentheses to be passed to the called procedure. Parameters passed are called actual parameters, those defined in the procedure's header are called formal parameters. In every procedure call, the types of actual and formal parameters must match. If these conditions are not met, a compile time error shall occur. Procedure calls may be recursive, that is, a procedure may call itself within its body. Recursive calls shall be optimised by eliminating tail call recursion.
Examples:
Insert( tree, "Fred Flintstone", 42 ); Clear Buffers?;
int := 42; (* assignment of a whole number value to a variable of a whole number type *) str := "foobar"; (* assignment of a quoted string value to a variable of a string type *)
ch := "a"; str := "foo"; i := -12345; r := 3.1415926; z := { 1.2, 3.4 }; array[5] := 0;
The assignment statement is used to assign a value to an instance of a mutable type. It consists of a designator, followed by the assignment symbol :=
, followed by an expression. The designator is called the L-value, the expression is called the R-value. The L-value must be mutable and the types of L-value and R-value must be assignment compatible. If these conditions are not met, a compile time error shall occur.
The assignment statement is used to assign a value to an instance of a mutable type. It consists of a designator followed by the assignment symbol :=
, followed by an expression. The designator is called the L-value, the expression is called the R-value. The L-value must be mutable and the types of L-value and R-value must be assignment compatible. If these conditions are not met, a compile time error shall occur.
...
The increment statement is used to increment the current value of an instance of a whole number type. It consists of a designator followed by the postfix increment symbol ++
. The designator is an L-value. It must be mutable and of a whole number type. If these conditions are not met, a compile time error shall occur.
Examples:
lineCounter++; index++;
...
The decrement statement is used to decrement the current value of an instance of a whole number type. It consists of a designator followed by the postfix decrement symbol --
. The designator is an L-value. It must be mutable and of a whole number type. If these conditions are not met, a compile time error shall occur.
Examples:
lineCounter--; index--;
Examples:
int := 42; (* assignment of a whole number value to a variable of a whole number type *) str := "foobar"; (* assignment of a quoted string value to a variable of a string type *)
A statement is an action that can be executed to cause a transformation of the computational state of a program. Statements are used for their effects only, they do not return any values and they may not be used within expressions. There are twelve kinds of statements:
IF
statement
CASE
statement
LOOP
statement
WHILE
statement
REPEAT
statement
FOR
statement
RETURN
statement
YIELD
statement
EXIT
statement
Memory management statements are used to allocate, initialise, retain and release instances of dynamic data types at runtime. There are three kinds of memory management statements:
NEW
statement
RETAIN
statement
RELEASE
statement
NEW
Statementto do
RETAIN
Statementto do
RELEASE
Statementto do
Destructive update statements are used to destructively update instances of mutable data types. There are four kinds:
COPY
statement
The assignment statement is used to assign a value to an instance of a mutable type. It consists of a designator, followed by the assignment symbol :=
, followed by an expression. The designator is called the L-value, the expression is called the R-value. The L-value must be mutable and the types of L-value and R-value must be assignment compatible. If these conditions are not met, a compile time error shall occur.
...
...
COPY
Statementto do
Operator | Represented Operation | Arity | Associativity | Precedence |
---|---|---|---|---|
^ | Pointer Dereference | unary | left | 6 (highest) |
:: | Type Conversion | binary | left | 5 |
NOT | Logical Negation | unary | none | 4 |
* | Multiplication, Set Intersection | binary | left | 3 |
/ | Real Division, Symmetric Set Difference | binary | left | 3 |
DIV | Euclidean Integer Division | binary | left | 3 |
MOD | Modulus of Euclidean Integer Division | binary | left | 3 |
AND | Logical Conjunction | binary | left | 3 |
\ | Set Difference | binary | left | 3 |
+ | Arithmetic Identity | unary | none | 2 |
Addition, Set Union | binary | left | 2 | |
- | Sign Inversion | unary | none | 2 |
Addition, Set Union | binary | left | 2 | |
OR | Logical Disjunction | binary | left | 2 |
& | Concatenation | binary | left | 2 |
= | Equality Test | binary | none | 1 |
# | Inequality Test | binary | none | 1 |
> | Greater-Than Test, Proper Superset Test | binary | none | 1 |
>= | Greater-Than-Or-Equal Test, Superset Test | binary | none | 1 |
< | Less-Than Test, Proper Subset Test | binary | none | 1 |
<= | Less-Than-Or-Equal Test, Subset Test | binary | none | 1 |
IN | Membership Test | binary | none | 1 |
== | Identity Test | binary | none | 1 |
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 |
+ | Arithmetic Identity | prefix | unary | none | 2 |
Addition, Set Union | infix | binary | left | 2 | |
- | Sign Inversion | prefix | unary | none | 2 |
Addition, Set Union | 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 |
Operators are special symbols or reserved words that represent an operation. An operator may be unary or binary. Unary operators are prefix, binary operators are infix. An operator may be either left-associative or non-associative and it has a precedence level between one and five, where five represents the highest level. Arity, associativity and precedence determine the order of evaluations in expressions that consist of multiple sub-expressions and may contain different operators.
Operators are special symbols or reserved words that represent an operation within an expression. An operator may be unary or binary. Unary operators are prefix or postfix, binary operators are always infix. An operator may be either left-associative or non-associative and it has a precedence level between one and six, where six represents the highest level. Arity, associativity and precedence determine the order of evaluations in expressions that consist of multiple sub-expressions and may contain different operators.
Symbol \
denotes the set difference operator. It is left associative and requires two operands.
AND
OperatorReserved word AND
denotes the logical AND
operator. It is left-associative and requires two operands.
setDiff := { foo, bar, baz } \ { baz }; (* set difference *)
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 *)
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 a multi-purpose operator. It is left associative and requires two operands.
NOT
OperatorReserved word NOT
denotes the logical NOT
operator. It is non-associative and requires one operand. The operator precedes its operand.
Examples:
product := 3.0 * 5.5; (* real multiplication *) intersect := { foo, bar, baz } * { bar, baz, bam }; (* set intersection *)
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 *)
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 the pointer dereferencing operator. It is left associative and requires one operand. The operator follows its operand.
Examples:
int := intPointer^; (* pointer dereference *) value := pointer^^; (* pointer to 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.
^ | Pointer Dereference | binary | left | 6 (highest) |
^ | Pointer Dereference | unary | left | 6 (highest) |
:: | Type Conversion | binary | left | 5 (highest) |
^ | Pointer Dereference | binary | left | 6 (highest) |
:: | Type Conversion | binary | left | 5 |
*. | Dot Product | binary | left | 3 |
Symbol *.
denotes the dot product operator. It is left associative and requires two operands.
Example:
dotProduct := v1 *. v2; (* dot product *)
The operator always represents the dot product operation. Its operands must be of a vector type with a cardinality of three and they must be type compatible. Its result type is the vector's component type. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The dot product 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.
Symbol &
denotes the concatenation operator. It is left-associative and requires two operands.
inverse := NOT condition; (* logical negation *)
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.
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 *)
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.
& | Concatenation | binary | left | 2 |
& | Concatenation | binary | none | 1 |
Symbol *.
denotes the dot product operator. It is left associative and requires two operands.
Example:
dotProduct := v1 *. v2; (* dot product *)
The operator always represents the dot product operation. Its operands must be of a vector type with a cardinality of three and they must be type compatible. Its result type is the vector's component type. Any use of the operator with operands that do not meet these conditions shall cause a compile time error. The dot product operator is 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 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.
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.
isGreaterOrEqual := 10 >= 5; (* greater-or-equal test *) isSuperset := { foo, bar, baz } >= { foo, baz }; (* superset test *)
isGreaterOrEqual := 5 <= 10; (* less-or-equal test *) isSuperset := { foo, bar, baz } <= { foo, baz }; (* subset test *)
Symbol >
denotes a dual-purpose operator. It is non-associative and requires two operands.
Symbol >
denotes a dual-purpose relational operator. It is non-associative and requires two operands.
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 collection 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.
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 := 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 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.
>
OperatorSymbol >
denotes a dual-purpose 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 collection 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.
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.
setDiff := { foo, bar , baz } \ { baz }; (* set difference *)
setDiff := { foo, bar, baz } \ { baz }; (* set difference *)
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.
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 operator is bindable using the +/-
binding symbol.
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 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 -
operator is bindable.
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.
Example:
Examples:
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.
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.
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.
The operator always represents the modulus of 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 MOD
operator is bindable.
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.
nSum := 100 + 42; (* integer addition *)
nSum := 100 + 42; (* whole number addition *)
nDiff := 100 - 42; (* integer subtraction *)
nDiff := 100 - 42; (* whole number subtraction *)
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 operator is bindable using the +/-
binding symbol.
The binary minus operator is left-associative and requires two operands.
Example:
nDiff := 100 - 42; (* integer 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 -
operator is bindable.
The binary plus operator is left-associative and requires two operands.
Example:
nSum := 100 + 42; (* integer 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.
Examples:
Example:
Symbol +
denotes a multi-purpose operator. There are two variants:
The unary plus operator is non-associative and requires one operand. The operator precedes its operand.
Example:
n := +42; (* arithmetic identity *)
The operator always represents the arithmetic identity operation. Its operands must be of a numeric type. Its result type is the operand type. Any use of the operator with an operand that is not a numeric type shall cause a compile time error. The unary plus operator is not bindable.
Examples:
quotient := 7.5 / 3.0; (* real division *) symDiff := { foo, bar, baz } / { bar, baz, bam }; (* symmetric set difference *)
Example:
quotient := 7 DIV 3; (* Euclidean integer division *)
quotient := 7.5 / 3.0; (* real division *) symDiff := { foo, bar, baz } / { bar, baz, bam }; (* symmetric set difference *)
modulus := 7 MOD 3; (* Euclidean modulus *)
DIV | Euclidian Integer Division | binary | left | 3 |
MOD | Modulus of Euclidian Integer Division | binary | left | 3 |
DIV | Euclidean Integer Division | binary | left | 3 |
MOD | Modulus of Euclidean Integer Division | binary | left | 3 |
DIV
OperatorReserved word DIV
denotes the Euclidean division 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 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.
Examples:
quotient := 7.5 / 3.0; (* real division *) symDiff := { foo, bar, baz } / { bar, baz, bam }; (* symmetric set difference *)
The operator always represents the modulus of 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 MOD
operator is bindable.
quotient := 7.5 * 3.0; (* real division *)
quotient := 7.5 / 3.0; (* real division *)
r := 3.0 * 5.5; (* real multiplication *)
product := 3.0 * 5.5; (* real multiplication *)
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.
Symbol *
denotes a multi-purpose operator. It is left associative and requires two operands.
Examples:
r := 3.0 * 5.5; (* real multiplication *) intersect := { foo, bar, baz } * { bar, baz, bam }; (* set intersection *)
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.
- -- | Sign Inversion | unary | none | 2 |
- | Sign Inversion | unary | none | 2 |
[___________ | Addition, Set Union | binary | left | 2 |
Addition, Set Union | binary | left | 2 |
[___________ | Addition, Set Union | binary | left | 2 |
Addition, Set Union | binary | left | 2 |
Operators are special symbols or reserved words that represent an operation. An operator may be unary or binary. Unary operators are prefix, binary operators are infix. An operator may be either left-associative or non-associative and it has a precedence level between one and five, where five represents the highest level. Arity, associativity and precedence determine the order of evaluations in expressions that consist of multiple sub-expressions and may contain different operators.
An overview of operators with their operations, arity, associativity and precedence is given below:
Operator | Represented Operation | Arity | Associativity | Precedence |
---|---|---|---|---|
:: | Type Conversion | binary | left | 5 (highest) |
NOT | Logical Negation | unary | none | 4 |
* | Multiplication, Set Intersection | binary | left | 3 |
/ | Real Division, Symmetric Set Difference | binary | left | 3 |
DIV | Euclidian Integer Division | binary | left | 3 |
MOD | Modulus of Euclidian Integer Division | binary | left | 3 |
AND | Logical Conjunction | binary | left | 3 |
\ | Set Difference | binary | left | 3 |
*. | Dot Product | binary | left | 3 |
+ | Arithmetic Identity | unary | none | 2 |
[___________ | Addition, Set Union | binary | left | 2 |
- -- | Sign Inversion | unary | none | 2 |
[___________ | Addition, Set Union | binary | left | 2 |
OR | Logical Disjunction | binary | left | 2 |
= | Equality Test | binary | none | 1 |
# | Inequality Test | binary | none | 1 |
> | Greater-Than Test, Proper Superset Test | binary | none | 1 |
>= | Greater-Than-Or-Equal Test, Superset Test | binary | none | 1 |
< | Less-Than Test, Proper Subset Test | binary | none | 1 |
<= | Less-Than-Or-Equal Test, Subset Test | binary | none | 1 |
IN | Membership Test | binary | none | 1 |
& | Concatenation | binary | none | 1 |
== | Identity Test | binary | none | 1 |
(To do: enter from PDF and update)
(To do: enter from PDF version and update)
(Content to be moved)
(To do: move and merge content)