mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
fixed typos in documentation
This commit is contained in:
@@ -24,8 +24,8 @@ ast type definitions of the abstract syntax tree (AST) and
|
||||
node constructors
|
||||
astalgo algorithms for containers of AST nodes; converting the
|
||||
AST to YAML; the symbol table
|
||||
passes implement the passes managemer for passes over the AST
|
||||
trees few algorithms for nodes; this module is less important
|
||||
passes implement the passes manager for passes over the AST
|
||||
trees some algorithms for nodes; this module is less important
|
||||
types module for traversing type graphs; also contain several
|
||||
helpers for dealing with types
|
||||
|
||||
|
||||
167
doc/manual.txt
167
doc/manual.txt
@@ -8,8 +8,8 @@ Nimrod Manual
|
||||
.. contents::
|
||||
|
||||
|
||||
"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
|
||||
"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
|
||||
pretty much constant for a given task. -- Ran
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
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
|
||||
@@ -168,10 +168,10 @@ language.
|
||||
Nimrod is a `style-insensitive`:idx: language. This means that it is not
|
||||
case-sensitive and even underscores are ignored:
|
||||
**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
|
||||
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.
|
||||
|
||||
|
||||
@@ -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
|
||||
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.
|
||||
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
this.
|
||||
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'
|
||||
|
||||
|
||||
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
|
||||
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
|
||||
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
|
||||
(prefix ``0x``) notation.
|
||||
|
||||
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``,
|
||||
unless the literal contains a dot or an ``E`` in which case it is of
|
||||
type ``float``.
|
||||
@@ -385,7 +385,7 @@ have no side-effect can be used in constant expressions too:
|
||||
|
||||
.. code-block:: nimrod
|
||||
import strutils
|
||||
const
|
||||
const
|
||||
constEval = contains("abc", 'b') # computed at compile time!
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ Pre-defined numerical types
|
||||
These integer types are pre-defined:
|
||||
|
||||
``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)
|
||||
this type should be used in general. An integer literal that has no type
|
||||
suffix is of this type.
|
||||
@@ -450,7 +450,7 @@ they cannot lead to over- or underflow errors. Unsigned operations use the
|
||||
operation meaning
|
||||
====================== ======================================================
|
||||
``a +% b`` unsigned integer addition
|
||||
``a -% b`` unsigned integer substraction
|
||||
``a -% b`` unsigned integer subtraction
|
||||
``a *% b`` unsigned integer multiplication
|
||||
``a /% b`` unsigned integer division
|
||||
``a %% b`` unsigned integer modulo operation
|
||||
@@ -472,7 +472,7 @@ operation meaning
|
||||
The following floating point types are pre-defined:
|
||||
|
||||
``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)
|
||||
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).
|
||||
|
||||
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
|
||||
follows the IEEE standard. Integer types are not converted to floating point
|
||||
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.
|
||||
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
|
||||
designed for this.
|
||||
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
|
||||
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
|
||||
type
|
||||
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
|
||||
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
|
||||
builtin ``len`` procedure; the length never counts the terminating zero.
|
||||
The assignment operator for strings always copies the string.
|
||||
The ``&`` operator concatenates strings.
|
||||
|
||||
Strings are compared by their lexicographical order. All comparison operators
|
||||
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
|
||||
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
||||
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
|
||||
~~~~~~~~~~~~~~~~
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
received by ``len()``. ``low()`` for a sequence or an open array always returns
|
||||
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``.
|
||||
|
||||
@@ -686,10 +689,10 @@ support nested open arrays.
|
||||
|
||||
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.
|
||||
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 ``()``
|
||||
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
|
||||
@@ -736,7 +739,7 @@ the ``is`` operator can be used to determine the object's type.
|
||||
assert(student is TStudent) # is true
|
||||
|
||||
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*.
|
||||
|
||||
|
||||
@@ -760,9 +763,9 @@ An example:
|
||||
nkIf # an if statement
|
||||
PNode = ref TNode
|
||||
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 nkFloat: floavVal: float
|
||||
of nkFloat: floatVal: float
|
||||
of nkString: strVal: string
|
||||
of nkAdd, nkSub:
|
||||
leftOp, rightOp: PNode
|
||||
@@ -796,7 +799,7 @@ can also be used to include elements (and ranges of elements) in the set:
|
||||
|
||||
.. 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
|
||||
# from '0' to '9'
|
||||
|
||||
@@ -821,7 +824,7 @@ operation meaning
|
||||
|
||||
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
|
||||
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``.
|
||||
|
||||
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 memory manually!
|
||||
|
||||
@@ -891,7 +894,7 @@ Example:
|
||||
forEach(printItem) # this will NOT work because calling conventions differ
|
||||
|
||||
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.
|
||||
|
||||
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,
|
||||
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
|
||||
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``.
|
||||
|
||||
`fastcall`:idx:
|
||||
@@ -930,7 +933,7 @@ each other:
|
||||
`closure`:idx:
|
||||
indicates that the procedure expects a context, a closure that needs
|
||||
to be passed to the procedure. The calling convention ``nimcall`` is
|
||||
compatible to ``closure``.
|
||||
compatible to ``closure``.
|
||||
|
||||
`syscall`:idx:
|
||||
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.
|
||||
|
||||
Assigning/passing a procedure to a procedural variable is only allowed if one
|
||||
of the following conditions hold:
|
||||
Assigning/passing a procedure to a procedural variable is only allowed if one
|
||||
of the following conditions hold:
|
||||
1) The procedure that is accessed resists in the current module.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
A distinct type can be used to model different physical `units`:idx: with a
|
||||
numerical base type, for example. The following example models currencies.
|
||||
|
||||
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
|
||||
type
|
||||
@@ -978,33 +981,33 @@ types are a perfect tool to model different currencies:
|
||||
var
|
||||
d: TDollar
|
||||
e: TEuro
|
||||
|
||||
echo d + 12
|
||||
|
||||
echo d + 12
|
||||
# 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
|
||||
a ``+`` for dollars needs to be defined:
|
||||
a ``+`` for dollars needs to be defined:
|
||||
|
||||
.. code-block::
|
||||
proc `+` (x, y: TDollar): TDollar =
|
||||
proc `+` (x, y: TDollar): TDollar =
|
||||
result = TDollar(int(x) + int(y))
|
||||
|
||||
It does not make sense to multiply a dollar with a dollar, but with a
|
||||
number without unit; and the same holds for division:
|
||||
|
||||
.. code-block::
|
||||
proc `*` (x: TDollar, y: int): TDollar =
|
||||
.. code-block::
|
||||
proc `*` (x: TDollar, y: int): TDollar =
|
||||
result = TDollar(int(x) * y)
|
||||
|
||||
proc `*` (x: int, y: TDollar): TDollar =
|
||||
proc `*` (x: int, y: TDollar): TDollar =
|
||||
result = TDollar(x * int(y))
|
||||
|
||||
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
|
||||
``+`` 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
|
||||
it generates the above trivial implementations:
|
||||
|
||||
@@ -1013,7 +1016,7 @@ it generates the above trivial implementations:
|
||||
proc `*` (x: int, y: TDollar): 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
|
||||
generated.
|
||||
|
||||
@@ -1028,19 +1031,19 @@ currency. This can be solved with templates_.
|
||||
# unary operators:
|
||||
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: base, y: typ): typ {.borrow.}
|
||||
proc `div` *(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.}
|
||||
|
||||
template DefineCurrency(typ, base: expr): stmt =
|
||||
|
||||
template DefineCurrency(typ, base: expr): stmt =
|
||||
type
|
||||
typ* = distinct base
|
||||
Additive(typ)
|
||||
@@ -1070,7 +1073,7 @@ algorithm determines type equality:
|
||||
s: var set[tuple[PType, PType]]): bool =
|
||||
if (a,b) in s: return true
|
||||
incl(s, (a,b))
|
||||
if a.kind == b.kind:
|
||||
if a.kind == b.kind:
|
||||
case a.kind
|
||||
of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil:
|
||||
# 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``:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc isSubtype(a, b: PType): bool =
|
||||
proc isSubtype(a, b: PType): bool =
|
||||
if a.kind == b.kind:
|
||||
case a.kind
|
||||
of object:
|
||||
@@ -1124,12 +1127,12 @@ relation is extended to the types ``var``, ``ref``, ``ptr``:
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
# XXX range types?
|
||||
proc isImplicitelyConvertible(a, b: PType): bool =
|
||||
proc isImplicitlyConvertible(a, b: PType): bool =
|
||||
case a.kind
|
||||
of proc:
|
||||
if b.kind == proc:
|
||||
@@ -1155,16 +1158,16 @@ algorithm returns true:
|
||||
result = b.kind == pointer
|
||||
of string:
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc isIntegralType(t: PType): bool =
|
||||
result = isOrdinal(t) or t.kind in {float, float32, float64}
|
||||
|
||||
proc isExplicitelyConvertible(a, b: PType): bool =
|
||||
if isImplicitelyConvertible(a, b): return true
|
||||
proc isExplicitlyConvertible(a, b: PType): bool =
|
||||
if isImplicitlyConvertible(a, b): return true
|
||||
if isIntegralType(a) and isIntegralType(b): return true
|
||||
if isSubtype(a, b) or isSubtype(b, a): 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
|
||||
`l-value` and ``isImplicitelyConvertible(b.typ, a.typ)`` holds.
|
||||
`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds.
|
||||
|
||||
|
||||
Overloading resolution
|
||||
@@ -1251,7 +1254,7 @@ Syntax::
|
||||
|
||||
|
||||
`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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -1260,7 +1263,7 @@ variables of the same type:
|
||||
a: int = 0
|
||||
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
|
||||
with a default value if there is no initializing expression. The default
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1469,7 +1472,7 @@ The statements following the ``except`` clauses are called
|
||||
`exception handlers`:idx:.
|
||||
|
||||
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
|
||||
exception handlers.
|
||||
@@ -1508,7 +1511,7 @@ variables, ``result`` is initialized to (binary) zero:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc returnZero(): int =
|
||||
# implicitely returns 0
|
||||
# implicitly returns 0
|
||||
|
||||
|
||||
Yield statement
|
||||
@@ -1741,8 +1744,8 @@ type `var`).
|
||||
Operators with one parameter are prefix operators, operators with two
|
||||
parameters are infix operators. (However, the parser distinguishes these from
|
||||
the operators position within an expression.) There is no way to declare
|
||||
postfix operators: All postfix operators are built-in and handled by the
|
||||
grammar explicitely.
|
||||
postfix operators: all postfix operators are built-in and handled by the
|
||||
grammar explicitly.
|
||||
|
||||
Any operator can be called like an ordinary proc with the '`opr`'
|
||||
notation. (Thus an operator can have more than two parameters):
|
||||
@@ -1870,11 +1873,11 @@ dispatching:
|
||||
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.
|
||||
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
|
||||
calls and enables inlining. However, other optimizations like compile time
|
||||
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
|
||||
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
|
||||
Nimrod's syntax is flexible enough anyway.
|
||||
|
||||
@@ -2190,7 +2193,7 @@ variable number of arguments:
|
||||
import macros
|
||||
|
||||
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:
|
||||
result = newNimNode(nnkStmtList, n)
|
||||
# iterate over any argument that is passed to this macro:
|
||||
@@ -2239,14 +2242,14 @@ invoked by an expression following a colon::
|
||||
| 'except' exceptList ':' 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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
import macros
|
||||
|
||||
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 :-)
|
||||
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
|
||||
`information hiding`:idx: and `separate compilation`:idx:. A module may gain
|
||||
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.
|
||||
|
||||
The algorithm for compiling modules is:
|
||||
@@ -2327,7 +2330,7 @@ following places:
|
||||
|
||||
* To the end of the tuple/object definition.
|
||||
* 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
|
||||
~~~~~~~~~~~~
|
||||
@@ -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
|
||||
module.
|
||||
|
||||
If a module imports an identifier by two different modules, each occurance of
|
||||
the identifier has to be qualified, unless it is an overloaded procedure or
|
||||
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
|
||||
iterator in which case the overloading resolution takes place:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -2394,8 +2397,8 @@ verify this.
|
||||
|
||||
procvar pragma
|
||||
--------------
|
||||
The `procvar`:idx: pragma is used to mark a proc so that it can be passed to a
|
||||
procedural variable.
|
||||
The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
||||
procedural variable.
|
||||
|
||||
|
||||
compileTime pragma
|
||||
|
||||
@@ -178,6 +178,6 @@ There are two ways to construct a PEG in Nimrod code:
|
||||
`peg` proc.
|
||||
(2) Constructing the AST directly with proc calls. This method does not
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
tutorial you will have a decent knowledge about Nimrod. This tutorial assumes
|
||||
that you are familiar with basic programming concepts like variables, types
|
||||
or statements.
|
||||
or statements.
|
||||
|
||||
|
||||
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
|
||||
# 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
|
||||
|
||||
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
|
||||
done with spaces only, tabulators are not allowed.
|
||||
|
||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||
a new variable named ``name`` of type ``string`` with the value that is
|
||||
returned by the ``readline`` procedure. Since the compiler knows that
|
||||
``readline`` returns a string, you can leave out the type in the declaration
|
||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||
a new variable named ``name`` of type ``string`` with the value that is
|
||||
returned by the ``readline`` procedure. Since the compiler knows that
|
||||
``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:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
var name = readline(stdin)
|
||||
|
||||
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
|
||||
declared in the system_ module which is implicitly imported by any other
|
||||
module.
|
||||
@@ -70,12 +70,12 @@ module.
|
||||
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,
|
||||
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:
|
||||
``This_is_an_identifier`` and this is the same identifier
|
||||
``ThisIsAnIdentifier``. This feature enables you to use other
|
||||
``This_is_an_identifier`` and ``ThisIsAnIdentifier`` are the same identifier.
|
||||
This feature enables you to use other
|
||||
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
|
||||
(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
|
||||
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
|
||||
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
|
||||
transformations (such as pretty-printing) and superior documentation generators.
|
||||
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:
|
||||
|
||||
.. code-block::
|
||||
Echo("Hallo!")
|
||||
Echo("Hello!")
|
||||
# comment has the same indentation as above statement -> fine
|
||||
Echo("Hi!")
|
||||
# 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``
|
||||
|
||||
Indentation can be used after the ``var`` keyword to list a whole section of
|
||||
variables:
|
||||
variables:
|
||||
|
||||
.. code-block::
|
||||
var
|
||||
@@ -190,7 +190,7 @@ constant declaration at compile time:
|
||||
const x = "abc" # the constant x contains the string "abc"
|
||||
|
||||
Indentation can be used after the ``const`` keyword to list a whole section of
|
||||
constants:
|
||||
constants:
|
||||
|
||||
.. code-block::
|
||||
const
|
||||
@@ -204,7 +204,7 @@ Control flow statements
|
||||
=======================
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ a multi-branch:
|
||||
else:
|
||||
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.
|
||||
|
||||
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 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
|
||||
``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
|
||||
@@ -276,8 +276,8 @@ the compiler that for every other value nothing should be done:
|
||||
else: nil
|
||||
|
||||
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
|
||||
that it is impossible to cover any possible string value: That is why there is
|
||||
case statement with an else part cannot fail and thus the error disappears. Note
|
||||
that it is impossible to cover all possible string values: that is why there is
|
||||
no such check for string cases.
|
||||
|
||||
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
|
||||
-------------
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -315,7 +315,7 @@ provides. The example uses the built-in ``countup`` iterator:
|
||||
Echo($i)
|
||||
|
||||
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
|
||||
through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
||||
the same:
|
||||
@@ -335,7 +335,7 @@ Counting down can be achieved as easily (but is less often needed):
|
||||
Echo($i)
|
||||
|
||||
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
|
||||
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
|
||||
------------------------------
|
||||
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
|
||||
outside the loop:
|
||||
|
||||
@@ -358,7 +358,7 @@ outside the loop:
|
||||
|
||||
A while (for) statement introduces an implicit block. Identifiers
|
||||
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
|
||||
block myblock:
|
||||
@@ -430,7 +430,7 @@ differences:
|
||||
The ``when`` statement is useful for writing platform specific code, similar to
|
||||
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.
|
||||
|
||||
**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
|
||||
indentation rules.
|
||||
indentation rules.
|
||||
|
||||
In Nimrod there is a distinction between *simple statements* and *complex
|
||||
statements*. *Simple statements* cannot contain other statements:
|
||||
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
|
||||
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
|
||||
|
||||
# indentation needed for nested if statement:
|
||||
if x:
|
||||
if x:
|
||||
if y:
|
||||
y = false
|
||||
else:
|
||||
y = true
|
||||
|
||||
# indentation needed, because two statements follow the condition:
|
||||
if x:
|
||||
if x:
|
||||
x = false
|
||||
y = false
|
||||
|
||||
|
||||
*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
|
||||
contain indentation at certain places for better readability:
|
||||
contain indentation at certain places for better readability:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
if thisIsaLongCondition() and
|
||||
thisIsAnotherLongCondition(1,
|
||||
thisIsAnotherLongCondition(1,
|
||||
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.
|
||||
|
||||
|
||||
@@ -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``
|
||||
and returns true if he answered "yes" (or something similar) and returns
|
||||
false if he answered "no" (or something similar). A ``return`` statement leaves
|
||||
the procedure (and therefore the while loop) immediately. The
|
||||
``(question: string): bool`` syntax describes that the procedure expects a
|
||||
the procedure (and therefore the while loop) immediately. The
|
||||
``(question: string): bool`` syntax describes that the procedure expects a
|
||||
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``.
|
||||
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.
|
||||
|
||||
|
||||
@@ -540,8 +540,8 @@ Parameters
|
||||
----------
|
||||
Parameters are constant in the procedure body. Their value cannot be changed
|
||||
because this allows the compiler to implement parameter passing in the most
|
||||
efficient way. If the procedure needs to modify the argument for the
|
||||
caller, a ``var`` parameter can be used:
|
||||
efficient way. If the procedure needs to modify the argument for the
|
||||
caller, a ``var`` parameter can be used:
|
||||
|
||||
.. code-block:: nimrod
|
||||
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
|
||||
proc toString(x: int): string = ...
|
||||
proc toString(x: bool): string =
|
||||
if x: return "true"
|
||||
if x: return "true"
|
||||
else: return "false"
|
||||
|
||||
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
|
||||
this overloading resolution algorithm works exactly is not discussed here
|
||||
(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.
|
||||
|
||||
|
||||
@@ -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
|
||||
use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
|
||||
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)``, 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
|
||||
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.
|
||||
|
||||
|
||||
@@ -771,7 +771,7 @@ Characters
|
||||
----------
|
||||
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.
|
||||
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
|
||||
designed for this.
|
||||
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)``!
|
||||
...
|
||||
|
||||
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
|
||||
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``
|
||||
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.
|
||||
|
||||
The common operators ``+ - * div mod < <= == != > >=`` are defined for
|
||||
@@ -843,7 +844,7 @@ errors. Unsigned operations use the ``%`` suffix as convention:
|
||||
operation meaning
|
||||
====================== ======================================================
|
||||
``a +% b`` unsigned integer addition
|
||||
``a -% b`` unsigned integer substraction
|
||||
``a -% b`` unsigned integer subtraction
|
||||
``a *% b`` unsigned integer multiplication
|
||||
``a /% b`` unsigned integer division
|
||||
``a %% b`` unsigned integer modulo operation
|
||||
@@ -877,7 +878,7 @@ The common operators ``+ - * / < <= == != > >=`` are defined for
|
||||
floats and follow the IEEE standard.
|
||||
|
||||
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
|
||||
types automatically and vice versa. The ``toInt`` and ``toFloat`` procs can be
|
||||
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
|
||||
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
|
||||
type
|
||||
@@ -937,7 +938,7 @@ An explicit ordered enum can have *wholes*:
|
||||
|
||||
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
|
||||
a few special operations:
|
||||
|
||||
@@ -979,7 +980,7 @@ subrange types (and vice versa) are allowed.
|
||||
The ``system`` module defines the important ``natural`` type as
|
||||
``range[0..high(int)]`` (``high`` returns the maximal value). Other programming
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
@@ -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
|
||||
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.
|
||||
|
||||
An openarray is also a means to implement passing a variable number of
|
||||
@@ -1156,7 +1157,7 @@ integer.
|
||||
|
||||
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
|
||||
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
|
||||
are declared with the **ptr** keyword.
|
||||
|
||||
The ``^`` operator can be used to *derefer* a reference, meaning to retrieve
|
||||
the item the reference points to. The ``addr`` procedure returns the address
|
||||
of an item. An address is always an untraced reference:
|
||||
The ``^`` operator can be used to *derefer* a reference, meaning to retrieve
|
||||
the item the reference points to. The ``addr`` procedure returns the address
|
||||
of an item. An address is always an untraced reference:
|
||||
``addr`` is an *unsafe* feature.
|
||||
|
||||
The ``.`` (access a tuple/object field operator)
|
||||
@@ -1199,7 +1200,7 @@ further information.
|
||||
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
|
||||
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
|
||||
memory manually:
|
||||
|
||||
@@ -1221,11 +1222,11 @@ memory manually:
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
**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
|
||||
---------------
|
||||
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
|
||||
``nil`` is an allowed value for a variable of a procedural type.
|
||||
Nimrod uses procedural types to achieve `functional`:idx: programming
|
||||
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
|
||||
``nil`` is an allowed value for a variable of a procedural type.
|
||||
Nimrod uses procedural types to achieve `functional`:idx: programming
|
||||
techniques.
|
||||
|
||||
Example:
|
||||
@@ -1248,8 +1249,8 @@ Example:
|
||||
type
|
||||
TCallback = proc (x: int)
|
||||
|
||||
proc echoItem(x: Int) = echo(x)
|
||||
|
||||
proc echoItem(x: Int) = echo(x)
|
||||
|
||||
proc forEach(callback: TCallback) =
|
||||
const
|
||||
data = [2, 3, 5, 7, 11]
|
||||
@@ -1259,7 +1260,7 @@ Example:
|
||||
forEach(echoItem)
|
||||
|
||||
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
|
||||
listed in the `user guide <nimrodc.html>`_.
|
||||
|
||||
@@ -1268,35 +1269,35 @@ Modules
|
||||
=======
|
||||
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
|
||||
`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
|
||||
`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
|
||||
with an asterisk (``*``) are exported:
|
||||
|
||||
.. code-block:: nimrod
|
||||
# Module A
|
||||
var
|
||||
x*, y: int
|
||||
|
||||
proc `*` *(a, b: seq[int]): seq[int] =
|
||||
|
||||
proc `*` *(a, b: seq[int]): seq[int] =
|
||||
# allocate a new sequence:
|
||||
newSeq(result, len(a))
|
||||
# multiply two int sequences:
|
||||
for i in 0..len(a)-1: result[i] = a[i] * b[i]
|
||||
|
||||
when isMainModule:
|
||||
when isMainModule:
|
||||
# test the new ``*`` operator for sequences:
|
||||
assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
|
||||
|
||||
The above module exports ``x`` and ``*``, but not ``y``.
|
||||
|
||||
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
|
||||
module is compiled as the main file. This is very useful to embed tests within
|
||||
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.
|
||||
|
||||
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
|
||||
rules apply:
|
||||
rules apply:
|
||||
|
||||
.. code-block:: nimrod
|
||||
# Module A
|
||||
@@ -1378,7 +1379,7 @@ From statement
|
||||
|
||||
We have already seen the simple ``import`` statement that just imports all
|
||||
exported symbols. An alternative that only imports listed symbols is the
|
||||
``from import`` statement:
|
||||
``from import`` statement:
|
||||
|
||||
.. code-block:: nimrod
|
||||
from mymodule import x, y, z
|
||||
@@ -1386,16 +1387,16 @@ exported symbols. An alternative that only imports listed symbols is the
|
||||
|
||||
Include statement
|
||||
-----------------
|
||||
The `include`:idx: statement does something fundametally different than
|
||||
importing a module: It merely includes the contents of a file. The ``include``
|
||||
The `include`:idx: statement does something fundametally different than
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
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
|
||||
generated documentation.
|
||||
generated documentation.
|
||||
|
||||
|
||||
Part 2
|
||||
|
||||
158
doc/tut2.txt
158
doc/tut2.txt
@@ -11,9 +11,9 @@ Nimrod Tutorial (Part II)
|
||||
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.
|
||||
|
||||
|
||||
@@ -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
|
||||
processed during semantic checking. Pragmas are enclosed in the
|
||||
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.
|
||||
|
||||
|
||||
Object Oriented Programming
|
||||
===========================
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ Mutually recursive types
|
||||
------------------------
|
||||
|
||||
Objects, tuples and references can model quite complex data structures which
|
||||
depend on each other; they are *mutually recursive*. In Nimrod
|
||||
these types can only be declared within a single type section. (Anything else
|
||||
depend on each other; they are *mutually recursive*. In Nimrod
|
||||
these types can only be declared within a single type section. (Anything else
|
||||
would require arbitrary symbol lookahead which slows down compilation.)
|
||||
|
||||
Example:
|
||||
@@ -106,22 +106,22 @@ Example:
|
||||
Type conversions
|
||||
----------------
|
||||
Nimrod distinguishes between `type casts`:idx: and `type conversions`:idx:.
|
||||
Casts are done with the ``cast`` operator and force the compiler to
|
||||
interpret a bit pattern to be of another type.
|
||||
Casts are done with the ``cast`` operator and force the compiler to
|
||||
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
|
||||
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)``
|
||||
(like an ordinary call):
|
||||
(like an ordinary call):
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc getID(x: TPerson): int =
|
||||
proc getID(x: TPerson): int =
|
||||
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``.
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ An example:
|
||||
|
||||
.. 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
|
||||
TNodeKind = enum # the different node types
|
||||
nkInt, # a leaf with an integer value
|
||||
@@ -171,12 +171,12 @@ object fields raises an exception.
|
||||
|
||||
Methods
|
||||
-------
|
||||
In ordinary object oriented languages, procedures (also called *methods*) are
|
||||
bound to a class. This has disadvantages:
|
||||
In ordinary object oriented languages, procedures (also called *methods*) are
|
||||
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.
|
||||
* 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?
|
||||
|
||||
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:
|
||||
``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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -217,9 +217,9 @@ So "pure object oriented" code is easy to write:
|
||||
|
||||
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
|
||||
the same. But setting a value is different; for this a special setter syntax
|
||||
As the above example shows, Nimrod has no need for *get-properties*:
|
||||
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
|
||||
is needed:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -229,23 +229,23 @@ is needed:
|
||||
FHost: int # cannot be accessed from the outside of the module
|
||||
# the `F` prefix is a convention to avoid clashes since
|
||||
# the accessors are named `host`
|
||||
|
||||
proc `host=`*(s: var TSocket, value: int) {.inline.} =
|
||||
|
||||
proc `host=`*(s: var TSocket, value: int) {.inline.} =
|
||||
## setter of hostAddr
|
||||
s.FHost = value
|
||||
|
||||
proc host*(s: TSocket): int {.inline.} =
|
||||
## getter of hostAddr
|
||||
return s.FHost
|
||||
|
||||
var
|
||||
|
||||
var
|
||||
s: TSocket
|
||||
s.host = 34 # same as `host=`(s, 34)
|
||||
|
||||
(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:\ :
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -261,15 +261,15 @@ The ``[]`` array access operator can be overloaded to provide
|
||||
of 2: v.z = value
|
||||
else: assert(false)
|
||||
|
||||
proc `[]`* (v: TVector, i: int): float =
|
||||
proc `[]`* (v: TVector, i: int): float =
|
||||
# getter
|
||||
case i
|
||||
of 0: result = v.x
|
||||
of 1: result = v.y
|
||||
of 2: result = v.z
|
||||
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.
|
||||
|
||||
|
||||
@@ -336,9 +336,9 @@ dispatching:
|
||||
collide(a, b) # output: 2
|
||||
|
||||
|
||||
As the example demonstrates, invokation of a multi-method cannot be ambiguous:
|
||||
Collide 2 is prefered over collide 1 because the resolution works from left to
|
||||
right. Thus ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
|
||||
As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
||||
Collide 2 is preferred over collide 1 because the resolution works from left to
|
||||
right. Thus ``TUnit, TThing`` is preferred over ``TThing, TUnit``.
|
||||
|
||||
**Perfomance note**: Nimrod does not produce a virtual method table, but
|
||||
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
|
||||
==========
|
||||
|
||||
In Nimrod `exceptions`:idx: are objects. By convention, exception types are
|
||||
prefixed with an 'E', not 'T'. The ``system`` module defines an exception
|
||||
In Nimrod `exceptions`:idx: are objects. By convention, exception types are
|
||||
prefixed with an 'E', not 'T'. The ``system`` module defines an exception
|
||||
hierarchy that you might want to stick to.
|
||||
|
||||
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
|
||||
exception since this is quite common (the file may not exist).
|
||||
|
||||
|
||||
Raise statement
|
||||
---------------
|
||||
Raising an exception is done with the ``raise`` statement:
|
||||
Raising an exception is done with the ``raise`` statement:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var
|
||||
@@ -371,14 +371,14 @@ Raising an exception is done with the ``raise`` statement:
|
||||
e.msg = "the request to the OS failed"
|
||||
raise e
|
||||
|
||||
If the ``raise`` keyword is not followed by an expression, the last exception
|
||||
is *re-raised*.
|
||||
If the ``raise`` keyword is not followed by an expression, the last exception
|
||||
is *re-raised*.
|
||||
|
||||
|
||||
Try statement
|
||||
-------------
|
||||
|
||||
The `try`:idx: statement handles exceptions:
|
||||
The `try`:idx: statement handles exceptions:
|
||||
|
||||
.. code-block:: nimrod
|
||||
# read the first two lines of a text file that should contain numbers
|
||||
@@ -403,11 +403,11 @@ The `try`:idx: statement handles exceptions:
|
||||
finally:
|
||||
close(f)
|
||||
|
||||
The statements after the ``try`` are executed unless an exception is
|
||||
raised. Then the appropriate ``except`` part is executed.
|
||||
The statements after the ``try`` are executed unless an exception is
|
||||
raised. Then the appropriate ``except`` part is executed.
|
||||
|
||||
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.
|
||||
|
||||
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`: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
|
||||
containers:
|
||||
containers:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
@@ -434,7 +434,7 @@ containers:
|
||||
data: T # the data stored in a node
|
||||
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
|
||||
new(result)
|
||||
result.dat = data
|
||||
@@ -448,7 +448,7 @@ containers:
|
||||
while it != nil:
|
||||
# compare the data items; uses the generic ``cmp`` proc
|
||||
# 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 it.le == nil:
|
||||
it.le = n
|
||||
@@ -460,13 +460,13 @@ containers:
|
||||
return
|
||||
it = it.ri
|
||||
|
||||
proc add*[T](root: var PBinaryTree[T], data: T) =
|
||||
proc add*[T](root: var PBinaryTree[T], data: T) =
|
||||
# convenience proc:
|
||||
add(root, newNode(data))
|
||||
|
||||
iterator preorder*[T](root: PBinaryTree[T]): T =
|
||||
# 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):
|
||||
var stack: seq[PBinaryTree[T]] = @[root]
|
||||
while stack.len > 0:
|
||||
@@ -483,19 +483,19 @@ containers:
|
||||
for str in preorder(root):
|
||||
stdout.writeln(str)
|
||||
|
||||
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,
|
||||
iterator or type. As the example shows, generics work with overloading: The
|
||||
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,
|
||||
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
|
||||
is not hidden and used in the ``preorder`` iterator.
|
||||
is not hidden and used in the ``preorder`` iterator.
|
||||
|
||||
|
||||
Templates
|
||||
=========
|
||||
|
||||
Templates are a simple substitution mechanism that operates on Nimrod's
|
||||
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
|
||||
Templates are a simple substitution mechanism that operates on Nimrod's
|
||||
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
|
||||
of C's preprocessor macros flaws.
|
||||
|
||||
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))
|
||||
|
||||
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
|
||||
templates: This has the benefit that if you overload the ``==`` operator,
|
||||
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
|
||||
templates: this has the benefit that if you overload the ``==`` operator,
|
||||
the ``!=`` operator is available automatically and does the right thing. (Except
|
||||
for IEEE floating point numbers - NaN breaks basic boolean logic.)
|
||||
|
||||
``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.
|
||||
|
||||
Templates are especially useful for lazy evaluation purposes. Consider a
|
||||
simple proc for logging:
|
||||
simple proc for logging:
|
||||
|
||||
.. code-block:: nimrod
|
||||
const
|
||||
debug = True
|
||||
|
||||
proc log(msg: string) {.inline.} =
|
||||
|
||||
proc log(msg: string) {.inline.} =
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
var
|
||||
x = 4
|
||||
log("x has the value: " & $x)
|
||||
|
||||
This code has a shortcoming: If ``debug`` is set to false someday, the quite
|
||||
expensive ``$`` and ``&`` operations are still performed! (The argument
|
||||
This code has a shortcoming: if ``debug`` is set to false someday, the quite
|
||||
expensive ``$`` and ``&`` operations are still performed! (The argument
|
||||
evaluation for procedures is *eager*).
|
||||
|
||||
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
|
||||
const
|
||||
debug = True
|
||||
|
||||
template log(msg: string) =
|
||||
|
||||
template log(msg: string) =
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
var
|
||||
@@ -558,12 +558,12 @@ The template body does not open a new scope. To open a new scope use a ``block``
|
||||
statement:
|
||||
|
||||
.. code-block:: nimrod
|
||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
||||
var x: t
|
||||
|
||||
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
||||
|
||||
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
||||
# open a new scope:
|
||||
block:
|
||||
block:
|
||||
var x: t
|
||||
|
||||
declareInScope(a, int)
|
||||
@@ -598,7 +598,7 @@ via a special ``:`` syntax:
|
||||
|
||||
In the example the two ``writeln`` statements are bound to the ``actions``
|
||||
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
|
||||
once.
|
||||
|
||||
@@ -606,12 +606,12 @@ once.
|
||||
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
|
||||
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 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.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
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 :-)
|
||||
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 ])
|
||||
|
||||
Reference in New Issue
Block a user