fixed typos in documentation
This commit is contained in:
parent
63e9a88c1f
commit
281609c358
6 changed files with 316 additions and 248 deletions
|
|
@ -24,8 +24,8 @@ ast type definitions of the abstract syntax tree (AST) and
|
||||||
node constructors
|
node constructors
|
||||||
astalgo algorithms for containers of AST nodes; converting the
|
astalgo algorithms for containers of AST nodes; converting the
|
||||||
AST to YAML; the symbol table
|
AST to YAML; the symbol table
|
||||||
passes implement the passes managemer for passes over the AST
|
passes implement the passes manager for passes over the AST
|
||||||
trees few algorithms for nodes; this module is less important
|
trees some algorithms for nodes; this module is less important
|
||||||
types module for traversing type graphs; also contain several
|
types module for traversing type graphs; also contain several
|
||||||
helpers for dealing with types
|
helpers for dealing with types
|
||||||
|
|
||||||
|
|
|
||||||
167
doc/manual.txt
167
doc/manual.txt
|
|
@ -8,8 +8,8 @@ Nimrod Manual
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
"Complexity" seems to be a lot like "energy": you can transfer it from the end
|
"Complexity" seems to be a lot like "energy": you can transfer it from the end
|
||||||
user to one/some of the other players, but the total amount seems to remain
|
user to one/some of the other players, but the total amount seems to remain
|
||||||
pretty much constant for a given task. -- Ran
|
pretty much constant for a given task. -- Ran
|
||||||
|
|
||||||
About this document
|
About this document
|
||||||
|
|
@ -102,7 +102,7 @@ The terminals ``IND`` (indentation), ``DED`` (dedentation) and ``SAD``
|
||||||
These terminals are only generated for lines that are not empty.
|
These terminals are only generated for lines that are not empty.
|
||||||
|
|
||||||
The parser and the scanner communicate over a stack which indentation terminal
|
The parser and the scanner communicate over a stack which indentation terminal
|
||||||
should be generated: The stack consists of integers counting the spaces. The
|
should be generated: the stack consists of integers counting the spaces. The
|
||||||
stack is initialized with a zero on its top. The scanner reads from the stack:
|
stack is initialized with a zero on its top. The scanner reads from the stack:
|
||||||
If the current indentation token consists of more spaces than the entry at the
|
If the current indentation token consists of more spaces than the entry at the
|
||||||
top of the stack, a ``IND`` token is generated, else if it consists of the same
|
top of the stack, a ``IND`` token is generated, else if it consists of the same
|
||||||
|
|
@ -168,10 +168,10 @@ language.
|
||||||
Nimrod is a `style-insensitive`:idx: language. This means that it is not
|
Nimrod is a `style-insensitive`:idx: language. This means that it is not
|
||||||
case-sensitive and even underscores are ignored:
|
case-sensitive and even underscores are ignored:
|
||||||
**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind
|
**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind
|
||||||
this is that this allows programmers to use their own prefered spelling style
|
this is that this allows programmers to use their own preferred spelling style
|
||||||
and libraries written by different programmers cannot use incompatible
|
and libraries written by different programmers cannot use incompatible
|
||||||
conventions. A Nimrod-aware editor or IDE can show the identifiers as
|
conventions. A Nimrod-aware editor or IDE can show the identifiers as
|
||||||
preferred. Another advantage is that it frees the programmer from remembering
|
preferred. Another advantage is that it frees the programmer from remembering
|
||||||
the exact spelling of an identifier.
|
the exact spelling of an identifier.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -214,7 +214,7 @@ String literals can also be delimited by three double quotes
|
||||||
``"""`` ... ``"""``.
|
``"""`` ... ``"""``.
|
||||||
Literals in this form may run for several lines, may contain ``"`` and do not
|
Literals in this form may run for several lines, may contain ``"`` and do not
|
||||||
interpret any escape sequences.
|
interpret any escape sequences.
|
||||||
For convenience, when the opening ``"""`` is immediately followed by a newline,
|
For convenience, when the opening ``"""`` is immediately followed by a newline,
|
||||||
the newline is not included in the string.
|
the newline is not included in the string.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ Character literals are enclosed in single quotes ``''`` and can contain the
|
||||||
same escape sequences as strings - with one exception: ``\n`` is not allowed
|
same escape sequences as strings - with one exception: ``\n`` is not allowed
|
||||||
as it may be wider than one character (often it is the pair CR/LF for example).
|
as it may be wider than one character (often it is the pair CR/LF for example).
|
||||||
A character is not an Unicode character but a single byte. The reason for this
|
A character is not an Unicode character but a single byte. The reason for this
|
||||||
is efficiency: For the overwhelming majority of use-cases, the resulting
|
is efficiency: for the overwhelming majority of use-cases, the resulting
|
||||||
programs will still handle UTF-8 properly as UTF-8 was specially designed for
|
programs will still handle UTF-8 properly as UTF-8 was specially designed for
|
||||||
this.
|
this.
|
||||||
Another reason is that Nimrod can thus support ``array[char, int]`` or
|
Another reason is that Nimrod can thus support ``array[char, int]`` or
|
||||||
|
|
@ -284,13 +284,13 @@ Numerical constants
|
||||||
FLOAT64_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '64'
|
FLOAT64_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '64'
|
||||||
|
|
||||||
|
|
||||||
As can be seen in the productions, numerical constants can contain unterscores
|
As can be seen in the productions, numerical constants can contain underscores
|
||||||
for readability. Integer and floating point literals may be given in decimal (no
|
for readability. Integer and floating point literals may be given in decimal (no
|
||||||
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
|
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
|
||||||
(prefix ``0x``) notation.
|
(prefix ``0x``) notation.
|
||||||
|
|
||||||
There exists a literal for each numerical type that is
|
There exists a literal for each numerical type that is
|
||||||
defined. The suffix starting with an apostophe ('\'') is called a
|
defined. The suffix starting with an apostrophe ('\'') is called a
|
||||||
`type suffix`:idx:. Literals without a type prefix are of the type ``int``,
|
`type suffix`:idx:. Literals without a type prefix are of the type ``int``,
|
||||||
unless the literal contains a dot or an ``E`` in which case it is of
|
unless the literal contains a dot or an ``E`` in which case it is of
|
||||||
type ``float``.
|
type ``float``.
|
||||||
|
|
@ -385,7 +385,7 @@ have no side-effect can be used in constant expressions too:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
import strutils
|
import strutils
|
||||||
const
|
const
|
||||||
constEval = contains("abc", 'b') # computed at compile time!
|
constEval = contains("abc", 'b') # computed at compile time!
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ Pre-defined numerical types
|
||||||
These integer types are pre-defined:
|
These integer types are pre-defined:
|
||||||
|
|
||||||
``int``
|
``int``
|
||||||
the generic signed integer type; its size is platform dependant
|
the generic signed integer type; its size is platform dependent
|
||||||
(the compiler chooses the processor's fastest integer type)
|
(the compiler chooses the processor's fastest integer type)
|
||||||
this type should be used in general. An integer literal that has no type
|
this type should be used in general. An integer literal that has no type
|
||||||
suffix is of this type.
|
suffix is of this type.
|
||||||
|
|
@ -450,7 +450,7 @@ they cannot lead to over- or underflow errors. Unsigned operations use the
|
||||||
operation meaning
|
operation meaning
|
||||||
====================== ======================================================
|
====================== ======================================================
|
||||||
``a +% b`` unsigned integer addition
|
``a +% b`` unsigned integer addition
|
||||||
``a -% b`` unsigned integer substraction
|
``a -% b`` unsigned integer subtraction
|
||||||
``a *% b`` unsigned integer multiplication
|
``a *% b`` unsigned integer multiplication
|
||||||
``a /% b`` unsigned integer division
|
``a /% b`` unsigned integer division
|
||||||
``a %% b`` unsigned integer modulo operation
|
``a %% b`` unsigned integer modulo operation
|
||||||
|
|
@ -472,7 +472,7 @@ operation meaning
|
||||||
The following floating point types are pre-defined:
|
The following floating point types are pre-defined:
|
||||||
|
|
||||||
``float``
|
``float``
|
||||||
the generic floating point type; its size is platform dependant
|
the generic floating point type; its size is platform dependent
|
||||||
(the compiler chooses the processor's fastest floating point type)
|
(the compiler chooses the processor's fastest floating point type)
|
||||||
this type should be used in general
|
this type should be used in general
|
||||||
|
|
||||||
|
|
@ -488,7 +488,7 @@ loses information, the `EOutOfRange`:idx: exception is raised (if the error
|
||||||
cannot be detected at compile time).
|
cannot be detected at compile time).
|
||||||
|
|
||||||
Automatic type conversion in expressions with different kinds
|
Automatic type conversion in expressions with different kinds
|
||||||
of floating point types is performed: The smaller type is
|
of floating point types is performed: the smaller type is
|
||||||
converted to the larger. Arithmetic performed on floating point types
|
converted to the larger. Arithmetic performed on floating point types
|
||||||
follows the IEEE standard. Integer types are not converted to floating point
|
follows the IEEE standard. Integer types are not converted to floating point
|
||||||
types automatically and vice versa.
|
types automatically and vice versa.
|
||||||
|
|
@ -522,7 +522,7 @@ Character type
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
The `character type`:idx: is named ``char`` in Nimrod. Its size is one byte.
|
The `character type`:idx: is named ``char`` in Nimrod. Its size is one byte.
|
||||||
Thus it cannot represent an UTF-8 character, but a part of it.
|
Thus it cannot represent an UTF-8 character, but a part of it.
|
||||||
The reason for this is efficiency: For the overwhelming majority of use-cases,
|
The reason for this is efficiency: for the overwhelming majority of use-cases,
|
||||||
the resulting programs will still handle UTF-8 properly as UTF-8 was specially
|
the resulting programs will still handle UTF-8 properly as UTF-8 was specially
|
||||||
designed for this.
|
designed for this.
|
||||||
Another reason is that Nimrod can support ``array[char, int]`` or
|
Another reason is that Nimrod can support ``array[char, int]`` or
|
||||||
|
|
@ -559,12 +559,12 @@ types can be assigned an explicit ordinal value. However, the ordinal values
|
||||||
have to be in ascending order. A field whose ordinal value is not
|
have to be in ascending order. A field whose ordinal value is not
|
||||||
explicitly given is assigned the value of the previous field + 1.
|
explicitly given is assigned the value of the previous field + 1.
|
||||||
|
|
||||||
An explicit ordered enum can have *wholes*:
|
An explicit ordered enum can have *holes*:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
TTokenType = enum
|
TTokenType = enum
|
||||||
a = 2, b = 4, c = 89 # wholes are valid
|
a = 2, b = 4, c = 89 # holes are valid
|
||||||
|
|
||||||
However, it is then not an ordinal anymore, so it is not possible to use these
|
However, it is then not an ordinal anymore, so it is not possible to use these
|
||||||
enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ``
|
enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ``
|
||||||
|
|
@ -598,6 +598,7 @@ similar to a sequence of characters. However, strings in Nimrod are both
|
||||||
zero-terminated and have a length field. One can retrieve the length with the
|
zero-terminated and have a length field. One can retrieve the length with the
|
||||||
builtin ``len`` procedure; the length never counts the terminating zero.
|
builtin ``len`` procedure; the length never counts the terminating zero.
|
||||||
The assignment operator for strings always copies the string.
|
The assignment operator for strings always copies the string.
|
||||||
|
The ``&`` operator concatenates strings.
|
||||||
|
|
||||||
Strings are compared by their lexicographical order. All comparison operators
|
Strings are compared by their lexicographical order. All comparison operators
|
||||||
are available. Strings can be indexed like arrays (lower bound is 0). Unlike
|
are available. Strings can be indexed like arrays (lower bound is 0). Unlike
|
||||||
|
|
@ -614,18 +615,18 @@ Per convention, all strings are UTF-8 strings, but this is not enforced. For
|
||||||
example, when reading strings from binary files, they are merely a sequence of
|
example, when reading strings from binary files, they are merely a sequence of
|
||||||
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
||||||
i-th *unichar*. The iterator ``runes`` from the ``unicode``
|
i-th *unichar*. The iterator ``runes`` from the ``unicode``
|
||||||
module can be used for iteration over all unicode characters.
|
module can be used for iteration over all Unicode characters.
|
||||||
|
|
||||||
|
|
||||||
Structured types
|
Structured types
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
A variable of a `structured type`:idx: can hold multiple values at the same
|
A variable of a `structured type`:idx: can hold multiple values at the same
|
||||||
time. Stuctured types can be nested to unlimited levels. Arrays, sequences,
|
time. Structured types can be nested to unlimited levels. Arrays, sequences,
|
||||||
tuples, objects and sets belong to the structured types.
|
tuples, objects and sets belong to the structured types.
|
||||||
|
|
||||||
Array and sequence types
|
Array and sequence types
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
`Arrays`:idx: are a homogenous type, meaning that each element in the array
|
`Arrays`:idx: are a homogeneous type, meaning that each element in the array
|
||||||
has the same type. Arrays always have a fixed length which is specified at
|
has the same type. Arrays always have a fixed length which is specified at
|
||||||
compile time (except for open arrays). They can be indexed by any ordinal type.
|
compile time (except for open arrays). They can be indexed by any ordinal type.
|
||||||
A parameter ``A`` may be an *open array*, in which case it is indexed by
|
A parameter ``A`` may be an *open array*, in which case it is indexed by
|
||||||
|
|
@ -658,6 +659,8 @@ The lower bound of an array or sequence may be received by the built-in proc
|
||||||
``low()``, the higher bound by ``high()``. The length may be
|
``low()``, the higher bound by ``high()``. The length may be
|
||||||
received by ``len()``. ``low()`` for a sequence or an open array always returns
|
received by ``len()``. ``low()`` for a sequence or an open array always returns
|
||||||
0, as this is the first valid index.
|
0, as this is the first valid index.
|
||||||
|
One can append elements to a sequence with the ``add()`` proc or the ``&`` operator,
|
||||||
|
and remove (and get) the last element of a sequence with the ``pop()`` proc.
|
||||||
|
|
||||||
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
||||||
|
|
||||||
|
|
@ -686,10 +689,10 @@ support nested open arrays.
|
||||||
|
|
||||||
Tuples and object types
|
Tuples and object types
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
A variable of a `tuple`:idx: or `object`:idx: type is a heterogenous storage
|
A variable of a `tuple`:idx: or `object`:idx: type is a heterogeneous storage
|
||||||
container.
|
container.
|
||||||
A tuple or object defines various named *fields* of a type. A tuple also
|
A tuple or object defines various named *fields* of a type. A tuple also
|
||||||
defines an *order* of the fields. Tuples are meant for heterogenous storage
|
defines an *order* of the fields. Tuples are meant for heterogeneous storage
|
||||||
types with no overhead and few abstraction possibilities. The constructor ``()``
|
types with no overhead and few abstraction possibilities. The constructor ``()``
|
||||||
can be used to construct tuples. The order of the fields in the constructor
|
can be used to construct tuples. The order of the fields in the constructor
|
||||||
must match the order of the tuple's definition. Different tuple-types are
|
must match the order of the tuple's definition. Different tuple-types are
|
||||||
|
|
@ -736,7 +739,7 @@ the ``is`` operator can be used to determine the object's type.
|
||||||
assert(student is TStudent) # is true
|
assert(student is TStudent) # is true
|
||||||
|
|
||||||
Object fields that should be visible from outside the defining module, have to
|
Object fields that should be visible from outside the defining module, have to
|
||||||
marked by ``*``. In contrast to tuples, different object types are
|
be marked by ``*``. In contrast to tuples, different object types are
|
||||||
never *equivalent*.
|
never *equivalent*.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -760,9 +763,9 @@ An example:
|
||||||
nkIf # an if statement
|
nkIf # an if statement
|
||||||
PNode = ref TNode
|
PNode = ref TNode
|
||||||
TNode = object
|
TNode = object
|
||||||
case kind: TNodeKind # the ``kind`` field is the discriminant
|
case kind: TNodeKind # the ``kind`` field is the discriminator
|
||||||
of nkInt: intVal: int
|
of nkInt: intVal: int
|
||||||
of nkFloat: floavVal: float
|
of nkFloat: floatVal: float
|
||||||
of nkString: strVal: string
|
of nkString: strVal: string
|
||||||
of nkAdd, nkSub:
|
of nkAdd, nkSub:
|
||||||
leftOp, rightOp: PNode
|
leftOp, rightOp: PNode
|
||||||
|
|
@ -796,7 +799,7 @@ can also be used to include elements (and ranges of elements) in the set:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
{'a'..'z', '0'..'9'} # This constructs a set that conains the
|
{'a'..'z', '0'..'9'} # This constructs a set that contains the
|
||||||
# letters from 'a' to 'z' and the digits
|
# letters from 'a' to 'z' and the digits
|
||||||
# from '0' to '9'
|
# from '0' to '9'
|
||||||
|
|
||||||
|
|
@ -821,7 +824,7 @@ operation meaning
|
||||||
|
|
||||||
Reference and pointer types
|
Reference and pointer types
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
References (similiar to `pointers`:idx: in other programming languages) are a
|
References (similar to `pointers`:idx: in other programming languages) are a
|
||||||
way to introduce many-to-one relationships. This means different references can
|
way to introduce many-to-one relationships. This means different references can
|
||||||
point to and modify the same location in memory.
|
point to and modify the same location in memory.
|
||||||
|
|
||||||
|
|
@ -864,7 +867,7 @@ further information.
|
||||||
If a reference points to *nothing*, it has the value ``nil``.
|
If a reference points to *nothing*, it has the value ``nil``.
|
||||||
|
|
||||||
Special care has to be taken if an untraced object contains traced objects like
|
Special care has to be taken if an untraced object contains traced objects like
|
||||||
traced references, strings or sequences: In order to free everything properly,
|
traced references, strings or sequences: in order to free everything properly,
|
||||||
the built-in procedure ``GCunref`` has to be called before freeing the
|
the built-in procedure ``GCunref`` has to be called before freeing the
|
||||||
untraced memory manually!
|
untraced memory manually!
|
||||||
|
|
||||||
|
|
@ -891,7 +894,7 @@ Example:
|
||||||
forEach(printItem) # this will NOT work because calling conventions differ
|
forEach(printItem) # this will NOT work because calling conventions differ
|
||||||
|
|
||||||
A subtle issue with procedural types is that the calling convention of the
|
A subtle issue with procedural types is that the calling convention of the
|
||||||
procedure influences the type compability: Procedural types are only compatible
|
procedure influences the type compatibility: procedural types are only compatible
|
||||||
if they have the same calling convention.
|
if they have the same calling convention.
|
||||||
|
|
||||||
Nimrod supports these `calling conventions`:idx:, which are all incompatible to
|
Nimrod supports these `calling conventions`:idx:, which are all incompatible to
|
||||||
|
|
@ -916,7 +919,7 @@ each other:
|
||||||
The inline convention means the the caller should not call the procedure,
|
The inline convention means the the caller should not call the procedure,
|
||||||
but inline its code directly. Note that Nimrod does not inline, but leaves
|
but inline its code directly. Note that Nimrod does not inline, but leaves
|
||||||
this to the C compiler. Thus it generates ``__inline`` procedures. This is
|
this to the C compiler. Thus it generates ``__inline`` procedures. This is
|
||||||
only a hint for the compiler: It may completely ignore it and
|
only a hint for the compiler: it may completely ignore it and
|
||||||
it may inline procedures that are not marked as ``inline``.
|
it may inline procedures that are not marked as ``inline``.
|
||||||
|
|
||||||
`fastcall`:idx:
|
`fastcall`:idx:
|
||||||
|
|
@ -930,7 +933,7 @@ each other:
|
||||||
`closure`:idx:
|
`closure`:idx:
|
||||||
indicates that the procedure expects a context, a closure that needs
|
indicates that the procedure expects a context, a closure that needs
|
||||||
to be passed to the procedure. The calling convention ``nimcall`` is
|
to be passed to the procedure. The calling convention ``nimcall`` is
|
||||||
compatible to ``closure``.
|
compatible to ``closure``.
|
||||||
|
|
||||||
`syscall`:idx:
|
`syscall`:idx:
|
||||||
The syscall convention is the same as ``__syscall`` in C. It is used for
|
The syscall convention is the same as ``__syscall`` in C. It is used for
|
||||||
|
|
@ -944,11 +947,11 @@ each other:
|
||||||
|
|
||||||
Most calling conventions exist only for the Windows 32-bit platform.
|
Most calling conventions exist only for the Windows 32-bit platform.
|
||||||
|
|
||||||
Assigning/passing a procedure to a procedural variable is only allowed if one
|
Assigning/passing a procedure to a procedural variable is only allowed if one
|
||||||
of the following conditions hold:
|
of the following conditions hold:
|
||||||
1) The procedure that is accessed resists in the current module.
|
1) The procedure that is accessed resists in the current module.
|
||||||
2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_).
|
2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_).
|
||||||
3) The procedure has a calling convention that differs from ``nimcall``.
|
3) The procedure has a calling convention that differs from ``nimcall``.
|
||||||
4) The procedure is anonymous.
|
4) The procedure is anonymous.
|
||||||
|
|
||||||
The rules' purpose is to prevent the case that extending a non-``procvar``
|
The rules' purpose is to prevent the case that extending a non-``procvar``
|
||||||
|
|
@ -961,14 +964,14 @@ Distinct type
|
||||||
A distinct type is new type derived from a `base type`:idx: that is
|
A distinct type is new type derived from a `base type`:idx: that is
|
||||||
incompatible with its base type. In particular, it is an essential property
|
incompatible with its base type. In particular, it is an essential property
|
||||||
of a distinct type that it **does not** imply a subtype relation between it
|
of a distinct type that it **does not** imply a subtype relation between it
|
||||||
and its base type. Explict type conversions from a distinct type to its
|
and its base type. Explicit type conversions from a distinct type to its
|
||||||
base type and vice versa are allowed.
|
base type and vice versa are allowed.
|
||||||
|
|
||||||
A distinct type can be used to model different physical `units`:idx: with a
|
A distinct type can be used to model different physical `units`:idx: with a
|
||||||
numerical base type, for example. The following example models currencies.
|
numerical base type, for example. The following example models currencies.
|
||||||
|
|
||||||
Different currencies should not be mixed in monetary calculations. Distinct
|
Different currencies should not be mixed in monetary calculations. Distinct
|
||||||
types are a perfect tool to model different currencies:
|
types are a perfect tool to model different currencies:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
|
|
@ -978,33 +981,33 @@ types are a perfect tool to model different currencies:
|
||||||
var
|
var
|
||||||
d: TDollar
|
d: TDollar
|
||||||
e: TEuro
|
e: TEuro
|
||||||
|
|
||||||
echo d + 12
|
echo d + 12
|
||||||
# Error: cannot add a number with no unit and a ``TDollar``
|
# Error: cannot add a number with no unit and a ``TDollar``
|
||||||
|
|
||||||
Unfortunetaly, ``d + 12.TDollar`` is not allowed either,
|
Unfortunately, ``d + 12.TDollar`` is not allowed either,
|
||||||
because ``+`` is defined for ``int`` (among others), not for ``TDollar``. So
|
because ``+`` is defined for ``int`` (among others), not for ``TDollar``. So
|
||||||
a ``+`` for dollars needs to be defined:
|
a ``+`` for dollars needs to be defined:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
proc `+` (x, y: TDollar): TDollar =
|
proc `+` (x, y: TDollar): TDollar =
|
||||||
result = TDollar(int(x) + int(y))
|
result = TDollar(int(x) + int(y))
|
||||||
|
|
||||||
It does not make sense to multiply a dollar with a dollar, but with a
|
It does not make sense to multiply a dollar with a dollar, but with a
|
||||||
number without unit; and the same holds for division:
|
number without unit; and the same holds for division:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
proc `*` (x: TDollar, y: int): TDollar =
|
proc `*` (x: TDollar, y: int): TDollar =
|
||||||
result = TDollar(int(x) * y)
|
result = TDollar(int(x) * y)
|
||||||
|
|
||||||
proc `*` (x: int, y: TDollar): TDollar =
|
proc `*` (x: int, y: TDollar): TDollar =
|
||||||
result = TDollar(x * int(y))
|
result = TDollar(x * int(y))
|
||||||
|
|
||||||
proc `div` ...
|
proc `div` ...
|
||||||
|
|
||||||
This quickly gets tedious. The implementations are trivial and the compiler
|
This quickly gets tedious. The implementations are trivial and the compiler
|
||||||
should not generate all this code only to optimize it away later - after all
|
should not generate all this code only to optimize it away later - after all
|
||||||
``+`` for dollars should produce the same binary code as ``+`` for ints.
|
``+`` for dollars should produce the same binary code as ``+`` for ints.
|
||||||
The pragma ``borrow`` has been designed to solve this problem; in principle
|
The pragma ``borrow`` has been designed to solve this problem; in principle
|
||||||
it generates the above trivial implementations:
|
it generates the above trivial implementations:
|
||||||
|
|
||||||
|
|
@ -1013,7 +1016,7 @@ it generates the above trivial implementations:
|
||||||
proc `*` (x: int, y: TDollar): TDollar {.borrow.}
|
proc `*` (x: int, y: TDollar): TDollar {.borrow.}
|
||||||
proc `div` (x: TDollar, y: int): TDollar {.borrow.}
|
proc `div` (x: TDollar, y: int): TDollar {.borrow.}
|
||||||
|
|
||||||
The ``borrow`` pragma makes the compiler use the same implementation as
|
The ``borrow`` pragma makes the compiler use the same implementation as
|
||||||
the proc that deals with the distinct type's base type, so no code is
|
the proc that deals with the distinct type's base type, so no code is
|
||||||
generated.
|
generated.
|
||||||
|
|
||||||
|
|
@ -1028,19 +1031,19 @@ currency. This can be solved with templates_.
|
||||||
# unary operators:
|
# unary operators:
|
||||||
proc `+` *(x: typ): typ {.borrow.}
|
proc `+` *(x: typ): typ {.borrow.}
|
||||||
proc `-` *(x: typ): typ {.borrow.}
|
proc `-` *(x: typ): typ {.borrow.}
|
||||||
|
|
||||||
template Multiplicative(typ, base: typeDesc): stmt =
|
template Multiplicative(typ, base: typeDesc): stmt =
|
||||||
proc `*` *(x: typ, y: base): typ {.borrow.}
|
proc `*` *(x: typ, y: base): typ {.borrow.}
|
||||||
proc `*` *(x: base, y: typ): typ {.borrow.}
|
proc `*` *(x: base, y: typ): typ {.borrow.}
|
||||||
proc `div` *(x: typ, y: base): typ {.borrow.}
|
proc `div` *(x: typ, y: base): typ {.borrow.}
|
||||||
proc `mod` *(x: typ, y: base): typ {.borrow.}
|
proc `mod` *(x: typ, y: base): typ {.borrow.}
|
||||||
|
|
||||||
template Comparable(typ: typeDesc): stmt =
|
template Comparable(typ: typeDesc): stmt =
|
||||||
proc `<` * (x, y: typ): bool {.borrow.}
|
proc `<` * (x, y: typ): bool {.borrow.}
|
||||||
proc `<=` * (x, y: typ): bool {.borrow.}
|
proc `<=` * (x, y: typ): bool {.borrow.}
|
||||||
proc `==` * (x, y: typ): bool {.borrow.}
|
proc `==` * (x, y: typ): bool {.borrow.}
|
||||||
|
|
||||||
template DefineCurrency(typ, base: expr): stmt =
|
template DefineCurrency(typ, base: expr): stmt =
|
||||||
type
|
type
|
||||||
typ* = distinct base
|
typ* = distinct base
|
||||||
Additive(typ)
|
Additive(typ)
|
||||||
|
|
@ -1070,7 +1073,7 @@ algorithm determines type equality:
|
||||||
s: var set[tuple[PType, PType]]): bool =
|
s: var set[tuple[PType, PType]]): bool =
|
||||||
if (a,b) in s: return true
|
if (a,b) in s: return true
|
||||||
incl(s, (a,b))
|
incl(s, (a,b))
|
||||||
if a.kind == b.kind:
|
if a.kind == b.kind:
|
||||||
case a.kind
|
case a.kind
|
||||||
of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil:
|
of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil:
|
||||||
# leaf type: kinds identical; nothing more to check
|
# leaf type: kinds identical; nothing more to check
|
||||||
|
|
@ -1109,7 +1112,7 @@ If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype
|
||||||
relation is extended to the types ``var``, ``ref``, ``ptr``:
|
relation is extended to the types ``var``, ``ref``, ``ptr``:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc isSubtype(a, b: PType): bool =
|
proc isSubtype(a, b: PType): bool =
|
||||||
if a.kind == b.kind:
|
if a.kind == b.kind:
|
||||||
case a.kind
|
case a.kind
|
||||||
of object:
|
of object:
|
||||||
|
|
@ -1124,12 +1127,12 @@ relation is extended to the types ``var``, ``ref``, ``ptr``:
|
||||||
|
|
||||||
Convertible relation
|
Convertible relation
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
A type ``a`` is **implicitely** convertible to type ``b`` iff the following
|
A type ``a`` is **implicitly** convertible to type ``b`` iff the following
|
||||||
algorithm returns true:
|
algorithm returns true:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# XXX range types?
|
# XXX range types?
|
||||||
proc isImplicitelyConvertible(a, b: PType): bool =
|
proc isImplicitlyConvertible(a, b: PType): bool =
|
||||||
case a.kind
|
case a.kind
|
||||||
of proc:
|
of proc:
|
||||||
if b.kind == proc:
|
if b.kind == proc:
|
||||||
|
|
@ -1155,16 +1158,16 @@ algorithm returns true:
|
||||||
result = b.kind == pointer
|
result = b.kind == pointer
|
||||||
of string:
|
of string:
|
||||||
result = b.kind == cstring
|
result = b.kind == cstring
|
||||||
|
|
||||||
A type ``a`` is **explicitely** convertible to type ``b`` iff the following
|
A type ``a`` is **explicitly** convertible to type ``b`` iff the following
|
||||||
algorithm returns true:
|
algorithm returns true:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc isIntegralType(t: PType): bool =
|
proc isIntegralType(t: PType): bool =
|
||||||
result = isOrdinal(t) or t.kind in {float, float32, float64}
|
result = isOrdinal(t) or t.kind in {float, float32, float64}
|
||||||
|
|
||||||
proc isExplicitelyConvertible(a, b: PType): bool =
|
proc isExplicitlyConvertible(a, b: PType): bool =
|
||||||
if isImplicitelyConvertible(a, b): return true
|
if isImplicitlyConvertible(a, b): return true
|
||||||
if isIntegralType(a) and isIntegralType(b): return true
|
if isIntegralType(a) and isIntegralType(b): return true
|
||||||
if isSubtype(a, b) or isSubtype(b, a): return true
|
if isSubtype(a, b) or isSubtype(b, a): return true
|
||||||
if a.kind == distinct and typeEquals(a.baseType, b): return true
|
if a.kind == distinct and typeEquals(a.baseType, b): return true
|
||||||
|
|
@ -1176,7 +1179,7 @@ Assignment compability
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an
|
An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an
|
||||||
`l-value` and ``isImplicitelyConvertible(b.typ, a.typ)`` holds.
|
`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds.
|
||||||
|
|
||||||
|
|
||||||
Overloading resolution
|
Overloading resolution
|
||||||
|
|
@ -1251,7 +1254,7 @@ Syntax::
|
||||||
|
|
||||||
|
|
||||||
`Var`:idx: statements declare new local and global variables and
|
`Var`:idx: statements declare new local and global variables and
|
||||||
initialize them. A comma seperated list of variables can be used to specify
|
initialize them. A comma separated list of variables can be used to specify
|
||||||
variables of the same type:
|
variables of the same type:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -1260,7 +1263,7 @@ variables of the same type:
|
||||||
a: int = 0
|
a: int = 0
|
||||||
x, y, z: int
|
x, y, z: int
|
||||||
|
|
||||||
If an initializer is given the type can be omitted: The variable is of the
|
If an initializer is given the type can be omitted: the variable is of the
|
||||||
same type as the initializing expression. Variables are always initialized
|
same type as the initializing expression. Variables are always initialized
|
||||||
with a default value if there is no initializing expression. The default
|
with a default value if there is no initializing expression. The default
|
||||||
value depends on the type and is always a zero in binary.
|
value depends on the type and is always a zero in binary.
|
||||||
|
|
@ -1401,7 +1404,7 @@ exceptions:
|
||||||
semantics! However, each ``expr`` is checked for semantics.
|
semantics! However, each ``expr`` is checked for semantics.
|
||||||
|
|
||||||
The ``when`` statement enables conditional compilation techniques. As
|
The ``when`` statement enables conditional compilation techniques. As
|
||||||
a special syntatic extension, the ``when`` construct is also available
|
a special syntactic extension, the ``when`` construct is also available
|
||||||
within ``object`` definitions.
|
within ``object`` definitions.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1469,7 +1472,7 @@ The statements following the ``except`` clauses are called
|
||||||
`exception handlers`:idx:.
|
`exception handlers`:idx:.
|
||||||
|
|
||||||
The empty `except`:idx: clause is executed if there is an exception that is
|
The empty `except`:idx: clause is executed if there is an exception that is
|
||||||
in no list. It is similiar to an ``else`` clause in ``if`` statements.
|
in no list. It is similar to an ``else`` clause in ``if`` statements.
|
||||||
|
|
||||||
If there is a `finally`:idx: clause, it is always executed after the
|
If there is a `finally`:idx: clause, it is always executed after the
|
||||||
exception handlers.
|
exception handlers.
|
||||||
|
|
@ -1508,7 +1511,7 @@ variables, ``result`` is initialized to (binary) zero:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc returnZero(): int =
|
proc returnZero(): int =
|
||||||
# implicitely returns 0
|
# implicitly returns 0
|
||||||
|
|
||||||
|
|
||||||
Yield statement
|
Yield statement
|
||||||
|
|
@ -1741,8 +1744,8 @@ type `var`).
|
||||||
Operators with one parameter are prefix operators, operators with two
|
Operators with one parameter are prefix operators, operators with two
|
||||||
parameters are infix operators. (However, the parser distinguishes these from
|
parameters are infix operators. (However, the parser distinguishes these from
|
||||||
the operators position within an expression.) There is no way to declare
|
the operators position within an expression.) There is no way to declare
|
||||||
postfix operators: All postfix operators are built-in and handled by the
|
postfix operators: all postfix operators are built-in and handled by the
|
||||||
grammar explicitely.
|
grammar explicitly.
|
||||||
|
|
||||||
Any operator can be called like an ordinary proc with the '`opr`'
|
Any operator can be called like an ordinary proc with the '`opr`'
|
||||||
notation. (Thus an operator can have more than two parameters):
|
notation. (Thus an operator can have more than two parameters):
|
||||||
|
|
@ -1870,11 +1873,11 @@ dispatching:
|
||||||
collide(a, b) # output: 2
|
collide(a, b) # output: 2
|
||||||
|
|
||||||
|
|
||||||
Invokation of a multi-method cannot be ambiguous: Collide 2 is prefered over
|
Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over
|
||||||
collide 1 because the resolution works from left to right.
|
collide 1 because the resolution works from left to right.
|
||||||
In the example ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
|
In the example ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
|
||||||
|
|
||||||
**Perfomance note**: Nimrod does not produce a virtual method table, but
|
**Performance note**: Nimrod does not produce a virtual method table, but
|
||||||
generates dispatch trees. This avoids the expensive indirect branch for method
|
generates dispatch trees. This avoids the expensive indirect branch for method
|
||||||
calls and enables inlining. However, other optimizations like compile time
|
calls and enables inlining. However, other optimizations like compile time
|
||||||
evaluation or dead code elimination do not work with methods.
|
evaluation or dead code elimination do not work with methods.
|
||||||
|
|
@ -2166,7 +2169,7 @@ Macros
|
||||||
`Macros`:idx: are the most powerful feature of Nimrod. They can be used
|
`Macros`:idx: are the most powerful feature of Nimrod. They can be used
|
||||||
to implement `domain specific languages`:idx:.
|
to implement `domain specific languages`:idx:.
|
||||||
|
|
||||||
While macros enable advanced compile-time code tranformations, they
|
While macros enable advanced compile-time code transformations, they
|
||||||
cannot change Nimrod's syntax. However, this is no real restriction because
|
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||||
Nimrod's syntax is flexible enough anyway.
|
Nimrod's syntax is flexible enough anyway.
|
||||||
|
|
||||||
|
|
@ -2190,7 +2193,7 @@ variable number of arguments:
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro debug(n: expr): stmt =
|
macro debug(n: expr): stmt =
|
||||||
# `n` is a Nimrod AST that contains the whole macro invokation
|
# `n` is a Nimrod AST that contains the whole macro invocation
|
||||||
# this macro returns a list of statements:
|
# this macro returns a list of statements:
|
||||||
result = newNimNode(nnkStmtList, n)
|
result = newNimNode(nnkStmtList, n)
|
||||||
# iterate over any argument that is passed to this macro:
|
# iterate over any argument that is passed to this macro:
|
||||||
|
|
@ -2239,14 +2242,14 @@ invoked by an expression following a colon::
|
||||||
| 'except' exceptList ':' stmt )*
|
| 'except' exceptList ':' stmt )*
|
||||||
['else' ':' stmt]
|
['else' ':' stmt]
|
||||||
|
|
||||||
The following example outlines a macro that generates a lexical analyser from
|
The following example outlines a macro that generates a lexical analyzer from
|
||||||
regular expressions:
|
regular expressions:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro case_token(n: stmt): stmt =
|
macro case_token(n: stmt): stmt =
|
||||||
# creates a lexical analyser from regular expressions
|
# creates a lexical analyzer from regular expressions
|
||||||
# ... (implementation is an exercise for the reader :-)
|
# ... (implementation is an exercise for the reader :-)
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
|
@ -2268,7 +2271,7 @@ Nimrod supports splitting a program into pieces by a `module`:idx: concept.
|
||||||
Each module needs to be in its own file. Modules enable
|
Each module needs to be in its own file. Modules enable
|
||||||
`information hiding`:idx: and `separate compilation`:idx:. A module may gain
|
`information hiding`:idx: and `separate compilation`:idx:. A module may gain
|
||||||
access to symbols of another module by the `import`:idx: statement.
|
access to symbols of another module by the `import`:idx: statement.
|
||||||
`Recursive module dependancies`:idx: are allowed, but slightly subtle. Only
|
`Recursive module dependencies`:idx: are allowed, but slightly subtle. Only
|
||||||
top-level symbols that are marked with an asterisk (``*``) are exported.
|
top-level symbols that are marked with an asterisk (``*``) are exported.
|
||||||
|
|
||||||
The algorithm for compiling modules is:
|
The algorithm for compiling modules is:
|
||||||
|
|
@ -2327,7 +2330,7 @@ following places:
|
||||||
|
|
||||||
* To the end of the tuple/object definition.
|
* To the end of the tuple/object definition.
|
||||||
* Field designators of a variable of the given tuple/object type.
|
* Field designators of a variable of the given tuple/object type.
|
||||||
* In all descendent types of the object type.
|
* In all descendant types of the object type.
|
||||||
|
|
||||||
Module scope
|
Module scope
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
@ -2336,8 +2339,8 @@ the end of the module. Identifiers from indirectly dependent modules are *not*
|
||||||
available. The `system`:idx: module is automatically imported in every other
|
available. The `system`:idx: module is automatically imported in every other
|
||||||
module.
|
module.
|
||||||
|
|
||||||
If a module imports an identifier by two different modules, each occurance of
|
If a module imports an identifier by two different modules, each occurrence of
|
||||||
the identifier has to be qualified, unless it is an overloaded procedure or
|
the identifier has to be qualified, unless it is an overloaded procedure or
|
||||||
iterator in which case the overloading resolution takes place:
|
iterator in which case the overloading resolution takes place:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -2394,8 +2397,8 @@ verify this.
|
||||||
|
|
||||||
procvar pragma
|
procvar pragma
|
||||||
--------------
|
--------------
|
||||||
The `procvar`:idx: pragma is used to mark a proc so that it can be passed to a
|
The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
||||||
procedural variable.
|
procedural variable.
|
||||||
|
|
||||||
|
|
||||||
compileTime pragma
|
compileTime pragma
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,6 @@ There are two ways to construct a PEG in Nimrod code:
|
||||||
`peg` proc.
|
`peg` proc.
|
||||||
(2) Constructing the AST directly with proc calls. This method does not
|
(2) Constructing the AST directly with proc calls. This method does not
|
||||||
support constructing rules, only simple expressions and is not as
|
support constructing rules, only simple expressions and is not as
|
||||||
convenient. It's only advantage is that it does not pull in the whole PEG
|
convenient. Its only advantage is that it does not pull in the whole PEG
|
||||||
parser into your executable.
|
parser into your executable.
|
||||||
|
|
||||||
|
|
|
||||||
169
doc/tut1.txt
169
doc/tut1.txt
|
|
@ -15,13 +15,13 @@ Introduction
|
||||||
This document is a tutorial for the programming language *Nimrod*. After this
|
This document is a tutorial for the programming language *Nimrod*. After this
|
||||||
tutorial you will have a decent knowledge about Nimrod. This tutorial assumes
|
tutorial you will have a decent knowledge about Nimrod. This tutorial assumes
|
||||||
that you are familiar with basic programming concepts like variables, types
|
that you are familiar with basic programming concepts like variables, types
|
||||||
or statements.
|
or statements.
|
||||||
|
|
||||||
|
|
||||||
The first program
|
The first program
|
||||||
=================
|
=================
|
||||||
|
|
||||||
We start the tour with a modified "hallo world" program:
|
We start the tour with a modified "hello world" program:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
# This is a comment
|
# This is a comment
|
||||||
|
|
@ -45,23 +45,23 @@ The most used commands and switches have abbreviations, so you can also use::
|
||||||
nimrod c -r greetings.nim
|
nimrod c -r greetings.nim
|
||||||
|
|
||||||
Though it should be pretty obvious what the program does, I will explain the
|
Though it should be pretty obvious what the program does, I will explain the
|
||||||
syntax: Statements which are not indented are executed when the program
|
syntax: statements which are not indented are executed when the program
|
||||||
starts. Indentation is Nimrod's way of grouping statements. Indentation is
|
starts. Indentation is Nimrod's way of grouping statements. Indentation is
|
||||||
done with spaces only, tabulators are not allowed.
|
done with spaces only, tabulators are not allowed.
|
||||||
|
|
||||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||||
a new variable named ``name`` of type ``string`` with the value that is
|
a new variable named ``name`` of type ``string`` with the value that is
|
||||||
returned by the ``readline`` procedure. Since the compiler knows that
|
returned by the ``readline`` procedure. Since the compiler knows that
|
||||||
``readline`` returns a string, you can leave out the type in the declaration
|
``readline`` returns a string, you can leave out the type in the declaration
|
||||||
(this is called `local type inference`:idx:). So this will work too:
|
(this is called `local type inference`:idx:). So this will work too:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
var name = readline(stdin)
|
var name = readline(stdin)
|
||||||
|
|
||||||
Note that this is basically the only form of type inference that exists in
|
Note that this is basically the only form of type inference that exists in
|
||||||
Nimrod: It is a good compromise between brevity and readability.
|
Nimrod: it is a good compromise between brevity and readability.
|
||||||
|
|
||||||
The "hallo world" program contains several identifiers that are already
|
The "hello world" program contains several identifiers that are already
|
||||||
known to the compiler: ``echo``, ``readLine``, etc. These built-in items are
|
known to the compiler: ``echo``, ``readLine``, etc. These built-in items are
|
||||||
declared in the system_ module which is implicitly imported by any other
|
declared in the system_ module which is implicitly imported by any other
|
||||||
module.
|
module.
|
||||||
|
|
@ -70,12 +70,12 @@ module.
|
||||||
Lexical elements
|
Lexical elements
|
||||||
================
|
================
|
||||||
|
|
||||||
Let us look at Nimrod's lexical elements in more detail: Like other
|
Let us look at Nimrod's lexical elements in more detail: like other
|
||||||
programming languages Nimrod consists of (string) literals, identifiers,
|
programming languages Nimrod consists of (string) literals, identifiers,
|
||||||
keywords, comments, operators, and other punctation marks. Case is
|
keywords, comments, operators, and other punctuation marks. Case is
|
||||||
*insignificant* in Nimrod and even underscores are ignored:
|
*insignificant* in Nimrod and even underscores are ignored:
|
||||||
``This_is_an_identifier`` and this is the same identifier
|
``This_is_an_identifier`` and ``ThisIsAnIdentifier`` are the same identifier.
|
||||||
``ThisIsAnIdentifier``. This feature enables you to use other
|
This feature enables you to use other
|
||||||
people's code without bothering about a naming convention that conflicts with
|
people's code without bothering about a naming convention that conflicts with
|
||||||
yours. It also frees you from remembering the exact spelling of an identifier
|
yours. It also frees you from remembering the exact spelling of an identifier
|
||||||
(was it ``parseURL`` or ``parseUrl`` or ``parse_URL``?).
|
(was it ``parseURL`` or ``parseUrl`` or ``parse_URL``?).
|
||||||
|
|
@ -86,7 +86,7 @@ String and character literals
|
||||||
|
|
||||||
String literals are enclosed in double quotes; character literals in single
|
String literals are enclosed in double quotes; character literals in single
|
||||||
quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t``
|
quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t``
|
||||||
means tabulator, etc. There exist also *raw* string literals:
|
means tabulator, etc. There are also *raw* string literals:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
r"C:\program files\nim"
|
r"C:\program files\nim"
|
||||||
|
|
@ -123,11 +123,11 @@ Comments are tokens; they are only allowed at certain places in the input file
|
||||||
as they belong to the syntax tree! This feature enables perfect source-to-source
|
as they belong to the syntax tree! This feature enables perfect source-to-source
|
||||||
transformations (such as pretty-printing) and superior documentation generators.
|
transformations (such as pretty-printing) and superior documentation generators.
|
||||||
A nice side-effect is that the human reader of the code always knows exactly
|
A nice side-effect is that the human reader of the code always knows exactly
|
||||||
which code snippet the comment refers to. Since comments are a proper part of
|
which code snippet the comment refers to. Since comments are a proper part of
|
||||||
the syntax, watch their indentation:
|
the syntax, watch their indentation:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
Echo("Hallo!")
|
Echo("Hello!")
|
||||||
# comment has the same indentation as above statement -> fine
|
# comment has the same indentation as above statement -> fine
|
||||||
Echo("Hi!")
|
Echo("Hi!")
|
||||||
# comment has not the right indentation -> syntax error!
|
# comment has not the right indentation -> syntax error!
|
||||||
|
|
@ -155,7 +155,7 @@ The var statement declares a new local or global variable:
|
||||||
var x, y: int # declares x and y to have the type ``int``
|
var x, y: int # declares x and y to have the type ``int``
|
||||||
|
|
||||||
Indentation can be used after the ``var`` keyword to list a whole section of
|
Indentation can be used after the ``var`` keyword to list a whole section of
|
||||||
variables:
|
variables:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
var
|
var
|
||||||
|
|
@ -190,7 +190,7 @@ constant declaration at compile time:
|
||||||
const x = "abc" # the constant x contains the string "abc"
|
const x = "abc" # the constant x contains the string "abc"
|
||||||
|
|
||||||
Indentation can be used after the ``const`` keyword to list a whole section of
|
Indentation can be used after the ``const`` keyword to list a whole section of
|
||||||
constants:
|
constants:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
const
|
const
|
||||||
|
|
@ -204,7 +204,7 @@ Control flow statements
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
The greetings program consists of 3 statements that are executed sequentially.
|
The greetings program consists of 3 statements that are executed sequentially.
|
||||||
Only the most primitive programs can get away with that: Branching and looping
|
Only the most primitive programs can get away with that: branching and looping
|
||||||
are needed too.
|
are needed too.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -245,7 +245,7 @@ a multi-branch:
|
||||||
else:
|
else:
|
||||||
Echo("Hi, ", name, "!")
|
Echo("Hi, ", name, "!")
|
||||||
|
|
||||||
As can be seen, for an ``of`` branch a comma separated list of values is also
|
As it can be seen, for an ``of`` branch a comma separated list of values is also
|
||||||
allowed.
|
allowed.
|
||||||
|
|
||||||
The case statement can deal with integers, other ordinal types and strings.
|
The case statement can deal with integers, other ordinal types and strings.
|
||||||
|
|
@ -262,7 +262,7 @@ For integers or other ordinal types value ranges are also possible:
|
||||||
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
||||||
of 3, 8: Echo("The number is 3 or 8")
|
of 3, 8: Echo("The number is 3 or 8")
|
||||||
|
|
||||||
However, the above code does not compile: The reason is that you have to cover
|
However, the above code does not compile: the reason is that you have to cover
|
||||||
every value that ``n`` may contain, but the code only handles the values
|
every value that ``n`` may contain, but the code only handles the values
|
||||||
``0..8``. Since it is not very practical to list every other possible integer
|
``0..8``. Since it is not very practical to list every other possible integer
|
||||||
(though it is possible thanks to the range notation), we fix this by telling
|
(though it is possible thanks to the range notation), we fix this by telling
|
||||||
|
|
@ -276,8 +276,8 @@ the compiler that for every other value nothing should be done:
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
The ``nil`` statement is a *do nothing* statement. The compiler knows that a
|
The ``nil`` statement is a *do nothing* statement. The compiler knows that a
|
||||||
case statement with an else part cannot fail and thus the error disappers. Note
|
case statement with an else part cannot fail and thus the error disappears. Note
|
||||||
that it is impossible to cover any possible string value: That is why there is
|
that it is impossible to cover all possible string values: that is why there is
|
||||||
no such check for string cases.
|
no such check for string cases.
|
||||||
|
|
||||||
In general the case statement is used for subrange types or enumerations where
|
In general the case statement is used for subrange types or enumerations where
|
||||||
|
|
@ -306,7 +306,7 @@ he types in nothing (only presses RETURN).
|
||||||
For statement
|
For statement
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The `for`:idx: statement is a construct to loop over any elements an *iterator*
|
The `for`:idx: statement is a construct to loop over any element an *iterator*
|
||||||
provides. The example uses the built-in ``countup`` iterator:
|
provides. The example uses the built-in ``countup`` iterator:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -315,7 +315,7 @@ provides. The example uses the built-in ``countup`` iterator:
|
||||||
Echo($i)
|
Echo($i)
|
||||||
|
|
||||||
The built-in ``$`` operator turns an integer (``int``) and many other types
|
The built-in ``$`` operator turns an integer (``int``) and many other types
|
||||||
into a string. The variable ``i`` is implicitely declared by the ``for`` loop
|
into a string. The variable ``i`` is implicitly declared by the ``for`` loop
|
||||||
and has the type ``int``, because that is what ``countup`` returns. ``i`` runs
|
and has the type ``int``, because that is what ``countup`` returns. ``i`` runs
|
||||||
through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
||||||
the same:
|
the same:
|
||||||
|
|
@ -335,7 +335,7 @@ Counting down can be achieved as easily (but is less often needed):
|
||||||
Echo($i)
|
Echo($i)
|
||||||
|
|
||||||
Since counting up occurs so often in programs, Nimrod has a special syntax that
|
Since counting up occurs so often in programs, Nimrod has a special syntax that
|
||||||
calls the ``countup`` iterator implicitely:
|
calls the ``countup`` iterator implicitly:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
for i in 1..10:
|
for i in 1..10:
|
||||||
|
|
@ -347,7 +347,7 @@ The syntax ``for i in 1..10`` is sugar for ``for i in countup(1, 10)``.
|
||||||
|
|
||||||
Scopes and the block statement
|
Scopes and the block statement
|
||||||
------------------------------
|
------------------------------
|
||||||
Control flow statements have a feature not covered yet: They open a
|
Control flow statements have a feature not covered yet: they open a
|
||||||
new scope. This means that in the following example, ``x`` is not accessible
|
new scope. This means that in the following example, ``x`` is not accessible
|
||||||
outside the loop:
|
outside the loop:
|
||||||
|
|
||||||
|
|
@ -358,7 +358,7 @@ outside the loop:
|
||||||
|
|
||||||
A while (for) statement introduces an implicit block. Identifiers
|
A while (for) statement introduces an implicit block. Identifiers
|
||||||
are only visible within the block they have been declared. The ``block``
|
are only visible within the block they have been declared. The ``block``
|
||||||
statement can be used to open a new block explicitely:
|
statement can be used to open a new block explicitly:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
block myblock:
|
block myblock:
|
||||||
|
|
@ -430,7 +430,7 @@ differences:
|
||||||
The ``when`` statement is useful for writing platform specific code, similar to
|
The ``when`` statement is useful for writing platform specific code, similar to
|
||||||
the ``#ifdef`` construct in the C programming language.
|
the ``#ifdef`` construct in the C programming language.
|
||||||
|
|
||||||
**Note**: The documentation generator currently always follows the first branch
|
**Note**: The documentation generator currently always follows the first branch
|
||||||
of when statements.
|
of when statements.
|
||||||
|
|
||||||
**Note**: To comment out a large piece of code, it is often better to use a
|
**Note**: To comment out a large piece of code, it is often better to use a
|
||||||
|
|
@ -442,12 +442,12 @@ Statements and indentation
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Now that we covered the basic control flow statements, let's return to Nimrod
|
Now that we covered the basic control flow statements, let's return to Nimrod
|
||||||
indentation rules.
|
indentation rules.
|
||||||
|
|
||||||
In Nimrod there is a distinction between *simple statements* and *complex
|
In Nimrod there is a distinction between *simple statements* and *complex
|
||||||
statements*. *Simple statements* cannot contain other statements:
|
statements*. *Simple statements* cannot contain other statements:
|
||||||
Assignment, procedure calls or the ``return`` statement belong to the simple
|
Assignment, procedure calls or the ``return`` statement belong to the simple
|
||||||
statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can
|
statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can
|
||||||
contain other statements. To avoid ambiguities, complex statements always have
|
contain other statements. To avoid ambiguities, complex statements always have
|
||||||
to be indented, but single simple statements do not:
|
to be indented, but single simple statements do not:
|
||||||
|
|
||||||
|
|
@ -456,30 +456,30 @@ to be indented, but single simple statements do not:
|
||||||
if x: x = false
|
if x: x = false
|
||||||
|
|
||||||
# indentation needed for nested if statement:
|
# indentation needed for nested if statement:
|
||||||
if x:
|
if x:
|
||||||
if y:
|
if y:
|
||||||
y = false
|
y = false
|
||||||
else:
|
else:
|
||||||
y = true
|
y = true
|
||||||
|
|
||||||
# indentation needed, because two statements follow the condition:
|
# indentation needed, because two statements follow the condition:
|
||||||
if x:
|
if x:
|
||||||
x = false
|
x = false
|
||||||
y = false
|
y = false
|
||||||
|
|
||||||
|
|
||||||
*Expressions* are parts of a statement which usually result in a value. The
|
*Expressions* are parts of a statement which usually result in a value. The
|
||||||
condition in an if statement is an example for an expression. Expressions can
|
condition in an if statement is an example for an expression. Expressions can
|
||||||
contain indentation at certain places for better readability:
|
contain indentation at certain places for better readability:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
if thisIsaLongCondition() and
|
if thisIsaLongCondition() and
|
||||||
thisIsAnotherLongCondition(1,
|
thisIsAnotherLongCondition(1,
|
||||||
2, 3, 4):
|
2, 3, 4):
|
||||||
x = true
|
x = true
|
||||||
|
|
||||||
As a rule of thumb, indentation within expressions is allowed after operators,
|
As a rule of thumb, indentation within expressions is allowed after operators,
|
||||||
an open parenthesis and after commas.
|
an open parenthesis and after commas.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -507,14 +507,14 @@ of a `procedure` is needed. (Some languages call them *methods* or
|
||||||
This example shows a procedure named ``yes`` that asks the user a ``question``
|
This example shows a procedure named ``yes`` that asks the user a ``question``
|
||||||
and returns true if he answered "yes" (or something similar) and returns
|
and returns true if he answered "yes" (or something similar) and returns
|
||||||
false if he answered "no" (or something similar). A ``return`` statement leaves
|
false if he answered "no" (or something similar). A ``return`` statement leaves
|
||||||
the procedure (and therefore the while loop) immediately. The
|
the procedure (and therefore the while loop) immediately. The
|
||||||
``(question: string): bool`` syntax describes that the procedure expects a
|
``(question: string): bool`` syntax describes that the procedure expects a
|
||||||
parameter named ``question`` of type ``string`` and returns a value of type
|
parameter named ``question`` of type ``string`` and returns a value of type
|
||||||
``bool``. ``Bool`` is a built-in type: The only valid values for ``bool`` are
|
``bool``. ``Bool`` is a built-in type: the only valid values for ``bool`` are
|
||||||
``true`` and ``false``.
|
``true`` and ``false``.
|
||||||
The conditions in if or while statements should be of the type ``bool``.
|
The conditions in if or while statements should be of the type ``bool``.
|
||||||
|
|
||||||
Some terminology: In the example ``question`` is called a (formal) *parameter*,
|
Some terminology: in the example ``question`` is called a (formal) *parameter*,
|
||||||
``"Should I..."`` is called an *argument* that is passed to this parameter.
|
``"Should I..."`` is called an *argument* that is passed to this parameter.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -540,8 +540,8 @@ Parameters
|
||||||
----------
|
----------
|
||||||
Parameters are constant in the procedure body. Their value cannot be changed
|
Parameters are constant in the procedure body. Their value cannot be changed
|
||||||
because this allows the compiler to implement parameter passing in the most
|
because this allows the compiler to implement parameter passing in the most
|
||||||
efficient way. If the procedure needs to modify the argument for the
|
efficient way. If the procedure needs to modify the argument for the
|
||||||
caller, a ``var`` parameter can be used:
|
caller, a ``var`` parameter can be used:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc divmod(a, b: int, res, remainder: var int) =
|
proc divmod(a, b: int, res, remainder: var int) =
|
||||||
|
|
@ -624,7 +624,7 @@ Nimrod provides the ability to overload procedures similar to C++:
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc toString(x: int): string = ...
|
proc toString(x: int): string = ...
|
||||||
proc toString(x: bool): string =
|
proc toString(x: bool): string =
|
||||||
if x: return "true"
|
if x: return "true"
|
||||||
else: return "false"
|
else: return "false"
|
||||||
|
|
||||||
Echo(toString(13)) # calls the toString(x: int) proc
|
Echo(toString(13)) # calls the toString(x: int) proc
|
||||||
|
|
@ -634,7 +634,7 @@ Nimrod provides the ability to overload procedures similar to C++:
|
||||||
The compiler chooses the most appropriate proc for the ``toString`` calls. How
|
The compiler chooses the most appropriate proc for the ``toString`` calls. How
|
||||||
this overloading resolution algorithm works exactly is not discussed here
|
this overloading resolution algorithm works exactly is not discussed here
|
||||||
(it will be specified in the manual soon).
|
(it will be specified in the manual soon).
|
||||||
However, it does not lead to nasty suprises and is based on a quite simple
|
However, it does not lead to nasty surprises and is based on a quite simple
|
||||||
unification algorithm. Ambiguous calls are reported as errors.
|
unification algorithm. Ambiguous calls are reported as errors.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -644,7 +644,7 @@ The Nimrod library makes heavy use of overloading - one reason for this is that
|
||||||
each operator like ``+`` is a just an overloaded proc. The parser lets you
|
each operator like ``+`` is a just an overloaded proc. The parser lets you
|
||||||
use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
|
use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
|
||||||
An infix operator always receives two arguments, a prefix operator always one.
|
An infix operator always receives two arguments, a prefix operator always one.
|
||||||
Postfix operators are not possible, because this would be ambiguous: Does
|
Postfix operators are not possible, because this would be ambiguous: does
|
||||||
``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means
|
``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means
|
||||||
``(a) @ (@b)``, because there are no postfix operators in Nimrod.
|
``(a) @ (@b)``, because there are no postfix operators in Nimrod.
|
||||||
|
|
||||||
|
|
@ -693,7 +693,7 @@ However, this cannot be done for mutually recursive procedures:
|
||||||
|
|
||||||
Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be
|
Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be
|
||||||
introduced to the compiler before it is completely defined. The syntax for
|
introduced to the compiler before it is completely defined. The syntax for
|
||||||
such a `forward declaration` is simple: Just omit the ``=`` and the procedure's
|
such a `forward declaration` is simple: just omit the ``=`` and the procedure's
|
||||||
body.
|
body.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -771,7 +771,7 @@ Characters
|
||||||
----------
|
----------
|
||||||
The `character type` is named ``char`` in Nimrod. Its size is one byte.
|
The `character type` is named ``char`` in Nimrod. Its size is one byte.
|
||||||
Thus it cannot represent an UTF-8 character, but a part of it.
|
Thus it cannot represent an UTF-8 character, but a part of it.
|
||||||
The reason for this is efficiency: For the overwhelming majority of use-cases,
|
The reason for this is efficiency: for the overwhelming majority of use-cases,
|
||||||
the resulting programs will still handle UTF-8 properly as UTF-8 was specially
|
the resulting programs will still handle UTF-8 properly as UTF-8 was specially
|
||||||
designed for this.
|
designed for this.
|
||||||
Character literals are enclosed in single quotes.
|
Character literals are enclosed in single quotes.
|
||||||
|
|
@ -795,7 +795,8 @@ terminating zero is no error and often leads to simpler code:
|
||||||
# no need to check whether ``i < len(s)``!
|
# no need to check whether ``i < len(s)``!
|
||||||
...
|
...
|
||||||
|
|
||||||
The assignment operator for strings copies the string.
|
The assignment operator for strings copies the string. You can use the ``&``
|
||||||
|
operator to concatenate strings.
|
||||||
|
|
||||||
Strings are compared by their lexicographical order. All comparison operators
|
Strings are compared by their lexicographical order. All comparison operators
|
||||||
are available. Per convention, all strings are UTF-8 strings, but this is not
|
are available. Per convention, all strings are UTF-8 strings, but this is not
|
||||||
|
|
@ -826,7 +827,7 @@ to mark them to be of another integer type:
|
||||||
y = 0'i8 # y is of type ``int8``
|
y = 0'i8 # y is of type ``int8``
|
||||||
z = 0'i64 # z is of type ``int64``
|
z = 0'i64 # z is of type ``int64``
|
||||||
|
|
||||||
Most often integers are used for couting objects that reside in memory, so
|
Most often integers are used for counting objects that reside in memory, so
|
||||||
``int`` has the same size as a pointer.
|
``int`` has the same size as a pointer.
|
||||||
|
|
||||||
The common operators ``+ - * div mod < <= == != > >=`` are defined for
|
The common operators ``+ - * div mod < <= == != > >=`` are defined for
|
||||||
|
|
@ -843,7 +844,7 @@ errors. Unsigned operations use the ``%`` suffix as convention:
|
||||||
operation meaning
|
operation meaning
|
||||||
====================== ======================================================
|
====================== ======================================================
|
||||||
``a +% b`` unsigned integer addition
|
``a +% b`` unsigned integer addition
|
||||||
``a -% b`` unsigned integer substraction
|
``a -% b`` unsigned integer subtraction
|
||||||
``a *% b`` unsigned integer multiplication
|
``a *% b`` unsigned integer multiplication
|
||||||
``a /% b`` unsigned integer division
|
``a /% b`` unsigned integer division
|
||||||
``a %% b`` unsigned integer modulo operation
|
``a %% b`` unsigned integer modulo operation
|
||||||
|
|
@ -877,7 +878,7 @@ The common operators ``+ - * / < <= == != > >=`` are defined for
|
||||||
floats and follow the IEEE standard.
|
floats and follow the IEEE standard.
|
||||||
|
|
||||||
Automatic type conversion in expressions with different kinds
|
Automatic type conversion in expressions with different kinds
|
||||||
of floating point types is performed: The smaller type is
|
of floating point types is performed: the smaller type is
|
||||||
converted to the larger. Integer types are **not** converted to floating point
|
converted to the larger. Integer types are **not** converted to floating point
|
||||||
types automatically and vice versa. The ``toInt`` and ``toFloat`` procs can be
|
types automatically and vice versa. The ``toInt`` and ``toFloat`` procs can be
|
||||||
used for these conversions.
|
used for these conversions.
|
||||||
|
|
@ -927,7 +928,7 @@ types can be assigned an explicit ordinal value. However, the ordinal values
|
||||||
have to be in ascending order. A symbol whose ordinal value is not
|
have to be in ascending order. A symbol whose ordinal value is not
|
||||||
explicitly given is assigned the value of the previous symbol + 1.
|
explicitly given is assigned the value of the previous symbol + 1.
|
||||||
|
|
||||||
An explicit ordered enum can have *wholes*:
|
An explicit ordered enum can have *holes*:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
|
|
@ -937,7 +938,7 @@ An explicit ordered enum can have *wholes*:
|
||||||
|
|
||||||
Ordinal types
|
Ordinal types
|
||||||
-------------
|
-------------
|
||||||
Enumerations without wholes, integer types, ``char`` and ``bool`` (and
|
Enumerations without holes, integer types, ``char`` and ``bool`` (and
|
||||||
subranges) are called `ordinal`:idx: types. Ordinal types have quite
|
subranges) are called `ordinal`:idx: types. Ordinal types have quite
|
||||||
a few special operations:
|
a few special operations:
|
||||||
|
|
||||||
|
|
@ -979,7 +980,7 @@ subrange types (and vice versa) are allowed.
|
||||||
The ``system`` module defines the important ``natural`` type as
|
The ``system`` module defines the important ``natural`` type as
|
||||||
``range[0..high(int)]`` (``high`` returns the maximal value). Other programming
|
``range[0..high(int)]`` (``high`` returns the maximal value). Other programming
|
||||||
languages mandate the usage of unsigned integers for natural numbers. This is
|
languages mandate the usage of unsigned integers for natural numbers. This is
|
||||||
often **wrong**: You don't want unsigned arithmetic (which wraps around) just
|
often **wrong**: you don't want unsigned arithmetic (which wraps around) just
|
||||||
because the numbers cannot be negative. Nimrod's ``natural`` type helps to
|
because the numbers cannot be negative. Nimrod's ``natural`` type helps to
|
||||||
avoid this common programming error.
|
avoid this common programming error.
|
||||||
|
|
||||||
|
|
@ -1024,7 +1025,7 @@ operation meaning
|
||||||
================== ========================================================
|
================== ========================================================
|
||||||
|
|
||||||
Sets are often used to define a type for the *flags* of a procedure. This is
|
Sets are often used to define a type for the *flags* of a procedure. This is
|
||||||
much cleaner (and type safe) solution than just defining integer
|
much cleaner (and type safe) solution than just defining integer
|
||||||
constants that should be ``or``'ed together.
|
constants that should be ``or``'ed together.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1100,7 +1101,7 @@ position 0. The ``len``, ``low`` and ``high`` operations are available
|
||||||
for open arrays too. Any array with a compatible base type can be passed to
|
for open arrays too. Any array with a compatible base type can be passed to
|
||||||
an openarray parameter, the index type does not matter.
|
an openarray parameter, the index type does not matter.
|
||||||
|
|
||||||
The openarray type cannot be nested: Multidimensional openarrays are not
|
The openarray type cannot be nested: multidimensional openarrays are not
|
||||||
supported because this is seldom needed and cannot be done efficiently.
|
supported because this is seldom needed and cannot be done efficiently.
|
||||||
|
|
||||||
An openarray is also a means to implement passing a variable number of
|
An openarray is also a means to implement passing a variable number of
|
||||||
|
|
@ -1156,7 +1157,7 @@ integer.
|
||||||
|
|
||||||
Reference and pointer types
|
Reference and pointer types
|
||||||
---------------------------
|
---------------------------
|
||||||
References (similiar to `pointers`:idx: in other programming languages) are a
|
References (similar to `pointers`:idx: in other programming languages) are a
|
||||||
way to introduce many-to-one relationships. This means different references can
|
way to introduce many-to-one relationships. This means different references can
|
||||||
point to and modify the same location in memory.
|
point to and modify the same location in memory.
|
||||||
|
|
||||||
|
|
@ -1170,9 +1171,9 @@ untraced references are *unsafe*. However for certain low-level operations
|
||||||
Traced references are declared with the **ref** keyword, untraced references
|
Traced references are declared with the **ref** keyword, untraced references
|
||||||
are declared with the **ptr** keyword.
|
are declared with the **ptr** keyword.
|
||||||
|
|
||||||
The ``^`` operator can be used to *derefer* a reference, meaning to retrieve
|
The ``^`` operator can be used to *derefer* a reference, meaning to retrieve
|
||||||
the item the reference points to. The ``addr`` procedure returns the address
|
the item the reference points to. The ``addr`` procedure returns the address
|
||||||
of an item. An address is always an untraced reference:
|
of an item. An address is always an untraced reference:
|
||||||
``addr`` is an *unsafe* feature.
|
``addr`` is an *unsafe* feature.
|
||||||
|
|
||||||
The ``.`` (access a tuple/object field operator)
|
The ``.`` (access a tuple/object field operator)
|
||||||
|
|
@ -1199,7 +1200,7 @@ further information.
|
||||||
If a reference points to *nothing*, it has the value ``nil``.
|
If a reference points to *nothing*, it has the value ``nil``.
|
||||||
|
|
||||||
Special care has to be taken if an untraced object contains traced objects like
|
Special care has to be taken if an untraced object contains traced objects like
|
||||||
traced references, strings or sequences: In order to free everything properly,
|
traced references, strings or sequences: in order to free everything properly,
|
||||||
the built-in procedure ``GCunref`` has to be called before freeing the untraced
|
the built-in procedure ``GCunref`` has to be called before freeing the untraced
|
||||||
memory manually:
|
memory manually:
|
||||||
|
|
||||||
|
|
@ -1221,11 +1222,11 @@ memory manually:
|
||||||
|
|
||||||
Without the ``GCunref`` call the memory allocated for the ``d.s`` string would
|
Without the ``GCunref`` call the memory allocated for the ``d.s`` string would
|
||||||
never be freed. The example also demonstrates two important features for low
|
never be freed. The example also demonstrates two important features for low
|
||||||
level programming: The ``sizeof`` proc returns the size of a type or value
|
level programming: the ``sizeof`` proc returns the size of a type or value
|
||||||
in bytes. The ``cast`` operator can circumvent the type system: The compiler
|
in bytes. The ``cast`` operator can circumvent the type system: the compiler
|
||||||
is forced to treat the result of the ``alloc0`` call (which returns an untyped
|
is forced to treat the result of the ``alloc0`` call (which returns an untyped
|
||||||
pointer) as if it would have the type ``ptr TData``. Casting should only be
|
pointer) as if it would have the type ``ptr TData``. Casting should only be
|
||||||
done if it is unavoidable: It breaks type safety and bugs can lead to
|
done if it is unavoidable: it breaks type safety and bugs can lead to
|
||||||
mysterious crashes.
|
mysterious crashes.
|
||||||
|
|
||||||
**Note**: The example only works because the memory is initialized with zero
|
**Note**: The example only works because the memory is initialized with zero
|
||||||
|
|
@ -1236,9 +1237,9 @@ details like this when mixing garbage collected data with unmanaged memory.
|
||||||
|
|
||||||
Procedural type
|
Procedural type
|
||||||
---------------
|
---------------
|
||||||
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
|
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
|
||||||
``nil`` is an allowed value for a variable of a procedural type.
|
``nil`` is an allowed value for a variable of a procedural type.
|
||||||
Nimrod uses procedural types to achieve `functional`:idx: programming
|
Nimrod uses procedural types to achieve `functional`:idx: programming
|
||||||
techniques.
|
techniques.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -1248,8 +1249,8 @@ Example:
|
||||||
type
|
type
|
||||||
TCallback = proc (x: int)
|
TCallback = proc (x: int)
|
||||||
|
|
||||||
proc echoItem(x: Int) = echo(x)
|
proc echoItem(x: Int) = echo(x)
|
||||||
|
|
||||||
proc forEach(callback: TCallback) =
|
proc forEach(callback: TCallback) =
|
||||||
const
|
const
|
||||||
data = [2, 3, 5, 7, 11]
|
data = [2, 3, 5, 7, 11]
|
||||||
|
|
@ -1259,7 +1260,7 @@ Example:
|
||||||
forEach(echoItem)
|
forEach(echoItem)
|
||||||
|
|
||||||
A subtle issue with procedural types is that the calling convention of the
|
A subtle issue with procedural types is that the calling convention of the
|
||||||
procedure influences the type compability: Procedural types are only compatible
|
procedure influences the type compatibility: procedural types are only compatible
|
||||||
if they have the same calling convention. The different calling conventions are
|
if they have the same calling convention. The different calling conventions are
|
||||||
listed in the `user guide <nimrodc.html>`_.
|
listed in the `user guide <nimrodc.html>`_.
|
||||||
|
|
||||||
|
|
@ -1268,35 +1269,35 @@ Modules
|
||||||
=======
|
=======
|
||||||
Nimrod supports splitting a program into pieces with a `module`:idx: concept.
|
Nimrod supports splitting a program into pieces with a `module`:idx: concept.
|
||||||
Each module is in its own file. Modules enable `information hiding`:idx: and
|
Each module is in its own file. Modules enable `information hiding`:idx: and
|
||||||
`separate compilation`:idx:. A module may gain access to symbols of another
|
`separate compilation`:idx:. A module may gain access to symbols of another
|
||||||
module by the `import`:idx: statement. Only top-level symbols that are marked
|
module by the `import`:idx: statement. Only top-level symbols that are marked
|
||||||
with an asterisk (``*``) are exported:
|
with an asterisk (``*``) are exported:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module A
|
# Module A
|
||||||
var
|
var
|
||||||
x*, y: int
|
x*, y: int
|
||||||
|
|
||||||
proc `*` *(a, b: seq[int]): seq[int] =
|
proc `*` *(a, b: seq[int]): seq[int] =
|
||||||
# allocate a new sequence:
|
# allocate a new sequence:
|
||||||
newSeq(result, len(a))
|
newSeq(result, len(a))
|
||||||
# multiply two int sequences:
|
# multiply two int sequences:
|
||||||
for i in 0..len(a)-1: result[i] = a[i] * b[i]
|
for i in 0..len(a)-1: result[i] = a[i] * b[i]
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
# test the new ``*`` operator for sequences:
|
# test the new ``*`` operator for sequences:
|
||||||
assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
|
assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
|
||||||
|
|
||||||
The above module exports ``x`` and ``*``, but not ``y``.
|
The above module exports ``x`` and ``*``, but not ``y``.
|
||||||
|
|
||||||
The top-level statements of a module are executed at the start of the program.
|
The top-level statements of a module are executed at the start of the program.
|
||||||
This can be used to initalize complex data structures for example.
|
This can be used to initialize complex data structures for example.
|
||||||
|
|
||||||
Each module has a special magic constant ``isMainModule`` that is true if the
|
Each module has a special magic constant ``isMainModule`` that is true if the
|
||||||
module is compiled as the main file. This is very useful to embed tests within
|
module is compiled as the main file. This is very useful to embed tests within
|
||||||
the module as shown by the above example.
|
the module as shown by the above example.
|
||||||
|
|
||||||
Modules that depend on each other are possible, but strongly discouraged,
|
Modules that depend on each other are possible, but strongly discouraged,
|
||||||
because then one module cannot be reused without the other.
|
because then one module cannot be reused without the other.
|
||||||
|
|
||||||
The algorithm for compiling modules is:
|
The algorithm for compiling modules is:
|
||||||
|
|
@ -1353,7 +1354,7 @@ imported by a third one:
|
||||||
|
|
||||||
|
|
||||||
But this rule does not apply to procedures or iterators. Here the overloading
|
But this rule does not apply to procedures or iterators. Here the overloading
|
||||||
rules apply:
|
rules apply:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module A
|
# Module A
|
||||||
|
|
@ -1378,7 +1379,7 @@ From statement
|
||||||
|
|
||||||
We have already seen the simple ``import`` statement that just imports all
|
We have already seen the simple ``import`` statement that just imports all
|
||||||
exported symbols. An alternative that only imports listed symbols is the
|
exported symbols. An alternative that only imports listed symbols is the
|
||||||
``from import`` statement:
|
``from import`` statement:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
from mymodule import x, y, z
|
from mymodule import x, y, z
|
||||||
|
|
@ -1386,16 +1387,16 @@ exported symbols. An alternative that only imports listed symbols is the
|
||||||
|
|
||||||
Include statement
|
Include statement
|
||||||
-----------------
|
-----------------
|
||||||
The `include`:idx: statement does something fundametally different than
|
The `include`:idx: statement does something fundametally different than
|
||||||
importing a module: It merely includes the contents of a file. The ``include``
|
importing a module: it merely includes the contents of a file. The ``include``
|
||||||
statement is useful to split up a large module into several files:
|
statement is useful to split up a large module into several files:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
include fileA, fileB, fileC
|
include fileA, fileB, fileC
|
||||||
|
|
||||||
**Note**: The documentation generator currently does not follow ``include``
|
**Note**: The documentation generator currently does not follow ``include``
|
||||||
statements, so exported symbols in an include file will not show up in the
|
statements, so exported symbols in an include file will not show up in the
|
||||||
generated documentation.
|
generated documentation.
|
||||||
|
|
||||||
|
|
||||||
Part 2
|
Part 2
|
||||||
|
|
|
||||||
158
doc/tut2.txt
158
doc/tut2.txt
|
|
@ -11,9 +11,9 @@ Nimrod Tutorial (Part II)
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
"With great power comes great responsibility." -- Spider-man
|
"With great power comes great responsibility." -- Spiderman
|
||||||
|
|
||||||
This document is a tutorial for the advanced constructs of the *Nimrod*
|
This document is a tutorial for the advanced constructs of the *Nimrod*
|
||||||
programming language.
|
programming language.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,17 +23,17 @@ Pragmas are Nimrod's method to give the compiler additional information/
|
||||||
commands without introducing a massive number of new keywords. Pragmas are
|
commands without introducing a massive number of new keywords. Pragmas are
|
||||||
processed during semantic checking. Pragmas are enclosed in the
|
processed during semantic checking. Pragmas are enclosed in the
|
||||||
special ``{.`` and ``.}`` curly dot brackets. This tutorial does not cover
|
special ``{.`` and ``.}`` curly dot brackets. This tutorial does not cover
|
||||||
pragmas. See the `manual <manual.html>`_ or `user guide <nimrodc.html>`_ for
|
pragmas. See the `manual <manual.html>`_ or `user guide <nimrodc.html>`_ for
|
||||||
a description of the available pragmas.
|
a description of the available pragmas.
|
||||||
|
|
||||||
|
|
||||||
Object Oriented Programming
|
Object Oriented Programming
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
While Nimrod's support for object oriented programming (OOP) is minimalistic,
|
While Nimrod's support for object oriented programming (OOP) is minimalistic,
|
||||||
powerful OOP technics can be used. OOP is seen as *one* way to design a
|
powerful OOP technics can be used. OOP is seen as *one* way to design a
|
||||||
program, not *the only* way. Often a procedural approach leads to simpler
|
program, not *the only* way. Often a procedural approach leads to simpler
|
||||||
and more efficient code. In particular, prefering aggregation over inheritance
|
and more efficient code. In particular, prefering composition over inheritance
|
||||||
is often the better design.
|
is often the better design.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,8 +84,8 @@ Mutually recursive types
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Objects, tuples and references can model quite complex data structures which
|
Objects, tuples and references can model quite complex data structures which
|
||||||
depend on each other; they are *mutually recursive*. In Nimrod
|
depend on each other; they are *mutually recursive*. In Nimrod
|
||||||
these types can only be declared within a single type section. (Anything else
|
these types can only be declared within a single type section. (Anything else
|
||||||
would require arbitrary symbol lookahead which slows down compilation.)
|
would require arbitrary symbol lookahead which slows down compilation.)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -106,22 +106,22 @@ Example:
|
||||||
Type conversions
|
Type conversions
|
||||||
----------------
|
----------------
|
||||||
Nimrod distinguishes between `type casts`:idx: and `type conversions`:idx:.
|
Nimrod distinguishes between `type casts`:idx: and `type conversions`:idx:.
|
||||||
Casts are done with the ``cast`` operator and force the compiler to
|
Casts are done with the ``cast`` operator and force the compiler to
|
||||||
interpret a bit pattern to be of another type.
|
interpret a bit pattern to be of another type.
|
||||||
|
|
||||||
Type conversions are a much more polite way to convert a type into another:
|
Type conversions are a much more polite way to convert a type into another:
|
||||||
They preserve the abstract *value*, not necessarily the *bit-pattern*. If a
|
They preserve the abstract *value*, not necessarily the *bit-pattern*. If a
|
||||||
type conversion is not possible, the compiler complains or an exception is
|
type conversion is not possible, the compiler complains or an exception is
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
The syntax for type conversions is ``destination_type(expression_to_convert)``
|
The syntax for type conversions is ``destination_type(expression_to_convert)``
|
||||||
(like an ordinary call):
|
(like an ordinary call):
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc getID(x: TPerson): int =
|
proc getID(x: TPerson): int =
|
||||||
return TStudent(x).id
|
return TStudent(x).id
|
||||||
|
|
||||||
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
|
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
|
||||||
``TStudent``.
|
``TStudent``.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -134,7 +134,7 @@ An example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
# This is an example how an abstract syntax tree could be modelled in Nimrod
|
# This is an example how an abstract syntax tree could be modeled in Nimrod
|
||||||
type
|
type
|
||||||
TNodeKind = enum # the different node types
|
TNodeKind = enum # the different node types
|
||||||
nkInt, # a leaf with an integer value
|
nkInt, # a leaf with an integer value
|
||||||
|
|
@ -171,12 +171,12 @@ object fields raises an exception.
|
||||||
|
|
||||||
Methods
|
Methods
|
||||||
-------
|
-------
|
||||||
In ordinary object oriented languages, procedures (also called *methods*) are
|
In ordinary object oriented languages, procedures (also called *methods*) are
|
||||||
bound to a class. This has disadvantages:
|
bound to a class. This has disadvantages:
|
||||||
|
|
||||||
* Adding a method to a class the programmer has no control over is
|
* Adding a method to a class the programmer has no control over is
|
||||||
impossible or needs ugly workarounds.
|
impossible or needs ugly workarounds.
|
||||||
* Often it is unclear where the method should belong to: Is
|
* Often it is unclear where the method should belong to: is
|
||||||
``join`` a string method or an array method?
|
``join`` a string method or an array method?
|
||||||
|
|
||||||
Nimrod avoids these problems by not assigning methods to a class. All methods
|
Nimrod avoids these problems by not assigning methods to a class. All methods
|
||||||
|
|
@ -192,7 +192,7 @@ The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``.
|
||||||
If there are no remaining arguments, the parentheses can be omitted:
|
If there are no remaining arguments, the parentheses can be omitted:
|
||||||
``obj.len`` (instead of ``len(obj)``).
|
``obj.len`` (instead of ``len(obj)``).
|
||||||
|
|
||||||
This `method call syntax`:idx: is not restricted to objects, it can be used
|
This `method call syntax`:idx: is not restricted to objects, it can be used
|
||||||
for any type:
|
for any type:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -217,9 +217,9 @@ So "pure object oriented" code is easy to write:
|
||||||
|
|
||||||
Properties
|
Properties
|
||||||
----------
|
----------
|
||||||
As the above example shows, Nimrod has no need for *get-properties*:
|
As the above example shows, Nimrod has no need for *get-properties*:
|
||||||
Ordinary get-procedures that are called with the *method call syntax* achieve
|
Ordinary get-procedures that are called with the *method call syntax* achieve
|
||||||
the same. But setting a value is different; for this a special setter syntax
|
the same. But setting a value is different; for this a special setter syntax
|
||||||
is needed:
|
is needed:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -229,23 +229,23 @@ is needed:
|
||||||
FHost: int # cannot be accessed from the outside of the module
|
FHost: int # cannot be accessed from the outside of the module
|
||||||
# the `F` prefix is a convention to avoid clashes since
|
# the `F` prefix is a convention to avoid clashes since
|
||||||
# the accessors are named `host`
|
# the accessors are named `host`
|
||||||
|
|
||||||
proc `host=`*(s: var TSocket, value: int) {.inline.} =
|
proc `host=`*(s: var TSocket, value: int) {.inline.} =
|
||||||
## setter of hostAddr
|
## setter of hostAddr
|
||||||
s.FHost = value
|
s.FHost = value
|
||||||
|
|
||||||
proc host*(s: TSocket): int {.inline.} =
|
proc host*(s: TSocket): int {.inline.} =
|
||||||
## getter of hostAddr
|
## getter of hostAddr
|
||||||
return s.FHost
|
return s.FHost
|
||||||
|
|
||||||
var
|
var
|
||||||
s: TSocket
|
s: TSocket
|
||||||
s.host = 34 # same as `host=`(s, 34)
|
s.host = 34 # same as `host=`(s, 34)
|
||||||
|
|
||||||
(The example also shows ``inline`` procedures.)
|
(The example also shows ``inline`` procedures.)
|
||||||
|
|
||||||
|
|
||||||
The ``[]`` array access operator can be overloaded to provide
|
The ``[]`` array access operator can be overloaded to provide
|
||||||
`array properties`:idx:\ :
|
`array properties`:idx:\ :
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -261,15 +261,15 @@ The ``[]`` array access operator can be overloaded to provide
|
||||||
of 2: v.z = value
|
of 2: v.z = value
|
||||||
else: assert(false)
|
else: assert(false)
|
||||||
|
|
||||||
proc `[]`* (v: TVector, i: int): float =
|
proc `[]`* (v: TVector, i: int): float =
|
||||||
# getter
|
# getter
|
||||||
case i
|
case i
|
||||||
of 0: result = v.x
|
of 0: result = v.x
|
||||||
of 1: result = v.y
|
of 1: result = v.y
|
||||||
of 2: result = v.z
|
of 2: result = v.z
|
||||||
else: assert(false)
|
else: assert(false)
|
||||||
|
|
||||||
The example is silly, since a vector is better modelled by a tuple which
|
The example is silly, since a vector is better modelled by a tuple which
|
||||||
already provides ``v[]`` access.
|
already provides ``v[]`` access.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -336,9 +336,9 @@ dispatching:
|
||||||
collide(a, b) # output: 2
|
collide(a, b) # output: 2
|
||||||
|
|
||||||
|
|
||||||
As the example demonstrates, invokation of a multi-method cannot be ambiguous:
|
As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
||||||
Collide 2 is prefered over collide 1 because the resolution works from left to
|
Collide 2 is preferred over collide 1 because the resolution works from left to
|
||||||
right. Thus ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
|
right. Thus ``TUnit, TThing`` is preferred over ``TThing, TUnit``.
|
||||||
|
|
||||||
**Perfomance note**: Nimrod does not produce a virtual method table, but
|
**Perfomance note**: Nimrod does not produce a virtual method table, but
|
||||||
generates dispatch trees. This avoids the expensive indirect branch for method
|
generates dispatch trees. This avoids the expensive indirect branch for method
|
||||||
|
|
@ -349,20 +349,20 @@ evaluation or dead code elimination do not work with methods.
|
||||||
Exceptions
|
Exceptions
|
||||||
==========
|
==========
|
||||||
|
|
||||||
In Nimrod `exceptions`:idx: are objects. By convention, exception types are
|
In Nimrod `exceptions`:idx: are objects. By convention, exception types are
|
||||||
prefixed with an 'E', not 'T'. The ``system`` module defines an exception
|
prefixed with an 'E', not 'T'. The ``system`` module defines an exception
|
||||||
hierarchy that you might want to stick to.
|
hierarchy that you might want to stick to.
|
||||||
|
|
||||||
Exceptions should be allocated on the heap because their lifetime is unknown.
|
Exceptions should be allocated on the heap because their lifetime is unknown.
|
||||||
|
|
||||||
A convention is that exceptions should be raised in *exceptional* cases:
|
A convention is that exceptions should be raised in *exceptional* cases:
|
||||||
For example, if a file cannot be opened, this should not raise an
|
For example, if a file cannot be opened, this should not raise an
|
||||||
exception since this is quite common (the file may not exist).
|
exception since this is quite common (the file may not exist).
|
||||||
|
|
||||||
|
|
||||||
Raise statement
|
Raise statement
|
||||||
---------------
|
---------------
|
||||||
Raising an exception is done with the ``raise`` statement:
|
Raising an exception is done with the ``raise`` statement:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
var
|
var
|
||||||
|
|
@ -371,14 +371,14 @@ Raising an exception is done with the ``raise`` statement:
|
||||||
e.msg = "the request to the OS failed"
|
e.msg = "the request to the OS failed"
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
If the ``raise`` keyword is not followed by an expression, the last exception
|
If the ``raise`` keyword is not followed by an expression, the last exception
|
||||||
is *re-raised*.
|
is *re-raised*.
|
||||||
|
|
||||||
|
|
||||||
Try statement
|
Try statement
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The `try`:idx: statement handles exceptions:
|
The `try`:idx: statement handles exceptions:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# read the first two lines of a text file that should contain numbers
|
# read the first two lines of a text file that should contain numbers
|
||||||
|
|
@ -403,11 +403,11 @@ The `try`:idx: statement handles exceptions:
|
||||||
finally:
|
finally:
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
The statements after the ``try`` are executed unless an exception is
|
The statements after the ``try`` are executed unless an exception is
|
||||||
raised. Then the appropriate ``except`` part is executed.
|
raised. Then the appropriate ``except`` part is executed.
|
||||||
|
|
||||||
The empty ``except`` part is executed if there is an exception that is
|
The empty ``except`` part is executed if there is an exception that is
|
||||||
not explicitely listed. It is similiar to an ``else`` part in ``if``
|
not explicitly listed. It is similar to an ``else`` part in ``if``
|
||||||
statements.
|
statements.
|
||||||
|
|
||||||
If there is a ``finally`` part, it is always executed after the
|
If there is a ``finally`` part, it is always executed after the
|
||||||
|
|
@ -422,9 +422,9 @@ is not executed (if an exception occurs).
|
||||||
Generics
|
Generics
|
||||||
========
|
========
|
||||||
|
|
||||||
`Generics`:idx: are Nimrod's means to parametrize procs, iterators or types
|
`Generics`:idx: are Nimrod's means to parametrize procs, iterators or types
|
||||||
with `type parameters`:idx:. They are most useful for efficient type safe
|
with `type parameters`:idx:. They are most useful for efficient type safe
|
||||||
containers:
|
containers:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
type
|
type
|
||||||
|
|
@ -434,7 +434,7 @@ containers:
|
||||||
data: T # the data stored in a node
|
data: T # the data stored in a node
|
||||||
PBinaryTree*[T] = ref TBinaryTree[T] # type that is exported
|
PBinaryTree*[T] = ref TBinaryTree[T] # type that is exported
|
||||||
|
|
||||||
proc newNode*[T](data: T): PBinaryTree[T] =
|
proc newNode*[T](data: T): PBinaryTree[T] =
|
||||||
# constructor for a node
|
# constructor for a node
|
||||||
new(result)
|
new(result)
|
||||||
result.dat = data
|
result.dat = data
|
||||||
|
|
@ -448,7 +448,7 @@ containers:
|
||||||
while it != nil:
|
while it != nil:
|
||||||
# compare the data items; uses the generic ``cmp`` proc
|
# compare the data items; uses the generic ``cmp`` proc
|
||||||
# that works for any type that has a ``==`` and ``<`` operator
|
# that works for any type that has a ``==`` and ``<`` operator
|
||||||
var c = cmp(it.data, n.data)
|
var c = cmp(it.data, n.data)
|
||||||
if c < 0:
|
if c < 0:
|
||||||
if it.le == nil:
|
if it.le == nil:
|
||||||
it.le = n
|
it.le = n
|
||||||
|
|
@ -460,13 +460,13 @@ containers:
|
||||||
return
|
return
|
||||||
it = it.ri
|
it = it.ri
|
||||||
|
|
||||||
proc add*[T](root: var PBinaryTree[T], data: T) =
|
proc add*[T](root: var PBinaryTree[T], data: T) =
|
||||||
# convenience proc:
|
# convenience proc:
|
||||||
add(root, newNode(data))
|
add(root, newNode(data))
|
||||||
|
|
||||||
iterator preorder*[T](root: PBinaryTree[T]): T =
|
iterator preorder*[T](root: PBinaryTree[T]): T =
|
||||||
# Preorder traversal of a binary tree.
|
# Preorder traversal of a binary tree.
|
||||||
# Since recursive iterators are not yet implemented,
|
# Since recursive iterators are not yet implemented,
|
||||||
# this uses an explicit stack (which is more efficient anyway):
|
# this uses an explicit stack (which is more efficient anyway):
|
||||||
var stack: seq[PBinaryTree[T]] = @[root]
|
var stack: seq[PBinaryTree[T]] = @[root]
|
||||||
while stack.len > 0:
|
while stack.len > 0:
|
||||||
|
|
@ -483,19 +483,19 @@ containers:
|
||||||
for str in preorder(root):
|
for str in preorder(root):
|
||||||
stdout.writeln(str)
|
stdout.writeln(str)
|
||||||
|
|
||||||
The example shows a generic binary tree. Depending on context, the brackets are
|
The example shows a generic binary tree. Depending on context, the brackets are
|
||||||
used either to introduce type parameters or to instantiate a generic proc,
|
used either to introduce type parameters or to instantiate a generic proc,
|
||||||
iterator or type. As the example shows, generics work with overloading: The
|
iterator or type. As the example shows, generics work with overloading: the
|
||||||
best match of ``add`` is used. The built-in ``add`` procedure for sequences
|
best match of ``add`` is used. The built-in ``add`` procedure for sequences
|
||||||
is not hidden and used in the ``preorder`` iterator.
|
is not hidden and used in the ``preorder`` iterator.
|
||||||
|
|
||||||
|
|
||||||
Templates
|
Templates
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Templates are a simple substitution mechanism that operates on Nimrod's
|
Templates are a simple substitution mechanism that operates on Nimrod's
|
||||||
abstract syntax trees. Templates are processed in the semantic pass of the
|
abstract syntax trees. Templates are processed in the semantic pass of the
|
||||||
compiler. They integrate well with the rest of the language and share none
|
compiler. They integrate well with the rest of the language and share none
|
||||||
of C's preprocessor macros flaws.
|
of C's preprocessor macros flaws.
|
||||||
|
|
||||||
To *invoke* a template, call it like a procedure.
|
To *invoke* a template, call it like a procedure.
|
||||||
|
|
@ -509,31 +509,31 @@ Example:
|
||||||
|
|
||||||
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
||||||
|
|
||||||
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
|
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
|
||||||
templates: This has the benefit that if you overload the ``==`` operator,
|
templates: this has the benefit that if you overload the ``==`` operator,
|
||||||
the ``!=`` operator is available automatically and does the right thing. (Except
|
the ``!=`` operator is available automatically and does the right thing. (Except
|
||||||
for IEEE floating point numbers - NaN breaks basic boolean logic.)
|
for IEEE floating point numbers - NaN breaks basic boolean logic.)
|
||||||
|
|
||||||
``a > b`` is transformed into ``b < a``.
|
``a > b`` is transformed into ``b < a``.
|
||||||
``a in b`` is transformed into ``contains(b, a)``.
|
``a in b`` is transformed into ``contains(b, a)``.
|
||||||
``notin`` and ``isnot`` have the obvious meanings.
|
``notin`` and ``isnot`` have the obvious meanings.
|
||||||
|
|
||||||
Templates are especially useful for lazy evaluation purposes. Consider a
|
Templates are especially useful for lazy evaluation purposes. Consider a
|
||||||
simple proc for logging:
|
simple proc for logging:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
const
|
const
|
||||||
debug = True
|
debug = True
|
||||||
|
|
||||||
proc log(msg: string) {.inline.} =
|
proc log(msg: string) {.inline.} =
|
||||||
if debug: stdout.writeln(msg)
|
if debug: stdout.writeln(msg)
|
||||||
|
|
||||||
var
|
var
|
||||||
x = 4
|
x = 4
|
||||||
log("x has the value: " & $x)
|
log("x has the value: " & $x)
|
||||||
|
|
||||||
This code has a shortcoming: If ``debug`` is set to false someday, the quite
|
This code has a shortcoming: if ``debug`` is set to false someday, the quite
|
||||||
expensive ``$`` and ``&`` operations are still performed! (The argument
|
expensive ``$`` and ``&`` operations are still performed! (The argument
|
||||||
evaluation for procedures is *eager*).
|
evaluation for procedures is *eager*).
|
||||||
|
|
||||||
Turning the ``log`` proc into a template solves this problem:
|
Turning the ``log`` proc into a template solves this problem:
|
||||||
|
|
@ -541,8 +541,8 @@ Turning the ``log`` proc into a template solves this problem:
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
const
|
const
|
||||||
debug = True
|
debug = True
|
||||||
|
|
||||||
template log(msg: string) =
|
template log(msg: string) =
|
||||||
if debug: stdout.writeln(msg)
|
if debug: stdout.writeln(msg)
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -558,12 +558,12 @@ The template body does not open a new scope. To open a new scope use a ``block``
|
||||||
statement:
|
statement:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
template declareInScope(x: expr, t: typeDesc): stmt =
|
||||||
var x: t
|
var x: t
|
||||||
|
|
||||||
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
||||||
# open a new scope:
|
# open a new scope:
|
||||||
block:
|
block:
|
||||||
var x: t
|
var x: t
|
||||||
|
|
||||||
declareInScope(a, int)
|
declareInScope(a, int)
|
||||||
|
|
@ -598,7 +598,7 @@ via a special ``:`` syntax:
|
||||||
|
|
||||||
In the example the two ``writeln`` statements are bound to the ``actions``
|
In the example the two ``writeln`` statements are bound to the ``actions``
|
||||||
parameter. The ``withFile`` template contains boilerplate code and helps to
|
parameter. The ``withFile`` template contains boilerplate code and helps to
|
||||||
avoid a common bug: To forget to close the file. Note how the
|
avoid a common bug: to forget to close the file. Note how the
|
||||||
``var fn = filename`` statement ensures that ``filename`` is evaluated only
|
``var fn = filename`` statement ensures that ``filename`` is evaluated only
|
||||||
once.
|
once.
|
||||||
|
|
||||||
|
|
@ -606,12 +606,12 @@ once.
|
||||||
Macros
|
Macros
|
||||||
======
|
======
|
||||||
|
|
||||||
Macros enable advanced compile-time code tranformations, but they
|
Macros enable advanced compile-time code transformations, but they
|
||||||
cannot change Nimrod's syntax. However, this is no real restriction because
|
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||||
Nimrod's syntax is flexible enough anyway.
|
Nimrod's syntax is flexible enough anyway.
|
||||||
|
|
||||||
To write a macro, one needs to know how the Nimrod concrete syntax is converted
|
To write a macro, one needs to know how the Nimrod concrete syntax is converted
|
||||||
to an abstract syntax tree (AST). The AST is documented in the
|
to an abstract syntax tree (AST). The AST is documented in the
|
||||||
`macros <macros.html>`_ module.
|
`macros <macros.html>`_ module.
|
||||||
|
|
||||||
There are two ways to invoke a macro:
|
There are two ways to invoke a macro:
|
||||||
|
|
@ -676,13 +676,13 @@ Statement Macros
|
||||||
Statement macros are defined just as expression macros. However, they are
|
Statement macros are defined just as expression macros. However, they are
|
||||||
invoked by an expression following a colon.
|
invoked by an expression following a colon.
|
||||||
|
|
||||||
The following example outlines a macro that generates a lexical analyser from
|
The following example outlines a macro that generates a lexical analyzer from
|
||||||
regular expressions:
|
regular expressions:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
macro case_token(n: stmt): stmt =
|
macro case_token(n: stmt): stmt =
|
||||||
# creates a lexical analyser from regular expressions
|
# creates a lexical analyzer from regular expressions
|
||||||
# ... (implementation is an exercise for the reader :-)
|
# ... (implementation is an exercise for the reader :-)
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
|
|
||||||
64
tests/tromans.nim
Executable file
64
tests/tromans.nim
Executable file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import
|
||||||
|
math, strutils
|
||||||
|
|
||||||
|
## Convert an integer to a Roman numeral
|
||||||
|
# See http://en.wikipedia.org/wiki/Roman_numerals for reference
|
||||||
|
|
||||||
|
proc raiseInvalidValue(msg: string) {.noreturn.} =
|
||||||
|
# Yes, we really need a shorthand for this code...
|
||||||
|
var e: ref EInvalidValue
|
||||||
|
new(e)
|
||||||
|
e.msg = msg
|
||||||
|
raise e
|
||||||
|
|
||||||
|
# I should use a class, perhaps.
|
||||||
|
# --> No. Why introduce additional state into such a simple and nice
|
||||||
|
# interface? State is evil. :D
|
||||||
|
|
||||||
|
proc ConvertRomanToDecimal(romanVal: string): int =
|
||||||
|
result = 0
|
||||||
|
var prevVal = 0
|
||||||
|
for i in countdown(romanVal.len - 1, 0):
|
||||||
|
var val = 0
|
||||||
|
case romanVal[i]
|
||||||
|
of 'I', 'i': val = 1
|
||||||
|
of 'V', 'v': val = 5
|
||||||
|
of 'X', 'x': val = 10
|
||||||
|
of 'L', 'l': val = 50
|
||||||
|
of 'C', 'c': val = 100
|
||||||
|
of 'D', 'd': val = 500
|
||||||
|
of 'M', 'm': val = 1000
|
||||||
|
else: raiseInvalidValue("Incorrect character in roman numeral! (" &
|
||||||
|
$romanVal[i] & ")")
|
||||||
|
if val >= prevVal:
|
||||||
|
inc(result, val)
|
||||||
|
else:
|
||||||
|
dec(result, val)
|
||||||
|
prevVal = val
|
||||||
|
|
||||||
|
proc ConvertDecimalToRoman(decValParam: int): string =
|
||||||
|
# Apparently numbers cannot be above 4000
|
||||||
|
# Well, they can be (using overbar or parenthesis notation)
|
||||||
|
# but I see little interest (beside coding challenge) in coding them as
|
||||||
|
# we rarely use huge Roman numeral.
|
||||||
|
const romanComposites = [
|
||||||
|
("M", 1000), ("CM", 900),
|
||||||
|
("D", 500), ("CD", 400), ("C", 100),
|
||||||
|
("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
|
||||||
|
("V", 5), ("IV", 4), ("I", 1)]
|
||||||
|
if decValParam < 1 or decValParam > 3999:
|
||||||
|
raiseInvalidValue("number not representable")
|
||||||
|
result = ""
|
||||||
|
var decVal = decValParam
|
||||||
|
for key, val in items(romanComposites):
|
||||||
|
while decVal >= val:
|
||||||
|
dec(decVal, val)
|
||||||
|
result.add(key)
|
||||||
|
|
||||||
|
randomize()
|
||||||
|
for i in 1 .. 10:
|
||||||
|
var rnd = 1 + random(3990)
|
||||||
|
var roman = ConvertDecimalToRoman(rnd)
|
||||||
|
var decimal = ConvertRomanToDecimal(roman)
|
||||||
|
echo("$# => $# => $#" % [ $rnd, roman, $decimal ])
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue