added tools and web dirs
This commit is contained in:
parent
300430fbba
commit
66a7e3d37c
489 changed files with 4593 additions and 9878 deletions
8
doc/abstypes.txt
Normal file → Executable file
8
doc/abstypes.txt
Normal file → Executable file
|
|
@ -91,7 +91,7 @@ we define our own ``+`` for dollars:
|
|||
result = TDollar(int(x) + int(y))
|
||||
|
||||
It does not make sense to multiply a dollar with a dollar, but with a
|
||||
unit-less number; and the same holds for division:
|
||||
number without unit; and the same holds for division:
|
||||
|
||||
.. code-block::
|
||||
proc `*` (x: TDollar, y: int): TDollar =
|
||||
|
|
@ -121,7 +121,7 @@ But it seems we still have to repeat all this boilerplate code for
|
|||
the ``TEuro`` currency. Fortunately, Nimrod has a template mechanism:
|
||||
|
||||
.. code-block:: nimrod
|
||||
template Additive(typ: typeExpr): stmt =
|
||||
template Additive(typ: typeDesc): stmt =
|
||||
proc `+` *(x, y: typ): typ {.borrow.}
|
||||
proc `-` *(x, y: typ): typ {.borrow.}
|
||||
|
||||
|
|
@ -129,13 +129,13 @@ the ``TEuro`` currency. Fortunately, Nimrod has a template mechanism:
|
|||
proc `+` *(x: typ): typ {.borrow.}
|
||||
proc `-` *(x: typ): typ {.borrow.}
|
||||
|
||||
template Multiplicative(typ, base: typeExpr): 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: typeExpr): stmt =
|
||||
template Comparable(typ: typeDesc): stmt =
|
||||
proc `<` * (x, y: typ): bool {.borrow.}
|
||||
proc `<=` * (x, y: typ): bool {.borrow.}
|
||||
proc `==` * (x, y: typ): bool {.borrow.}
|
||||
|
|
|
|||
0
doc/astspec.txt
Normal file → Executable file
0
doc/astspec.txt
Normal file → Executable file
0
doc/docs.txt
Normal file → Executable file
0
doc/docs.txt
Normal file → Executable file
0
doc/endb.txt
Normal file → Executable file
0
doc/endb.txt
Normal file → Executable file
0
doc/filelist.txt
Normal file → Executable file
0
doc/filelist.txt
Normal file → Executable file
4
doc/grammar.txt
Normal file → Executable file
4
doc/grammar.txt
Normal file → Executable file
|
|
@ -135,10 +135,10 @@ fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
|
|||
|
||||
pragma ::= '{.' optInd (colonExpr [comma])* [SAD] ('.}' | '}')
|
||||
|
||||
param ::= symbol (comma symbol)* ':' typeDesc
|
||||
param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
|
||||
paramList ::= ['(' [param (comma param)*] [SAD] ')'] [':' typeDesc]
|
||||
|
||||
genericParam ::= symbol [':' typeDesc]
|
||||
genericParam ::= symbol [':' typeDesc] ['=' expr]
|
||||
genericParams ::= '[' genericParam (comma genericParam)* [SAD] ']'
|
||||
|
||||
procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
|
||||
|
|
|
|||
129
doc/intern.txt
Normal file → Executable file
129
doc/intern.txt
Normal file → Executable file
|
|
@ -17,7 +17,7 @@ The Nimrod project's directory structure is:
|
|||
============ ==============================================
|
||||
Path Purpose
|
||||
============ ==============================================
|
||||
``bin`` binary files go into here
|
||||
``bin`` generated binary files
|
||||
``build`` generated C code for the installation
|
||||
``nim`` Pascal sources of the Nimrod compiler; this
|
||||
should be modified, not the Nimrod version in
|
||||
|
|
@ -26,16 +26,16 @@ Path Purpose
|
|||
automatically generated from the Pascal
|
||||
version
|
||||
``data`` data files that are used for generating source
|
||||
code go into here
|
||||
code
|
||||
``doc`` the documentation lives here; it is a bunch of
|
||||
reStructuredText files
|
||||
``dist`` additional packages for the distribution
|
||||
``config`` configuration files for Nimrod go into here
|
||||
``config`` configuration files for Nimrod
|
||||
``lib`` the Nimrod library lives here; ``rod`` depends
|
||||
on it!
|
||||
``web`` website of Nimrod; generated by ``koch.py``
|
||||
from the ``*.txt`` and ``*.tmpl`` files
|
||||
``obj`` generated ``*.obj`` files go into here
|
||||
``obj`` generated ``*.obj`` files
|
||||
============ ==============================================
|
||||
|
||||
|
||||
|
|
@ -72,6 +72,18 @@ the same::
|
|||
./boot [-d:release]
|
||||
|
||||
|
||||
Coding Guidelines
|
||||
=================
|
||||
|
||||
* Use CamelCase, not underscored_identifiers.
|
||||
* Indent with two spaces.
|
||||
* Max line length is 80 characters.
|
||||
* Provide spaces around binary operators if that enhances readability.
|
||||
* Use a space after a colon, but not before it.
|
||||
* Start types with a capital ``T``, unless they are pointers which start with
|
||||
``P``.
|
||||
|
||||
|
||||
Pascal annotations
|
||||
==================
|
||||
There are some annotations that the Pascal sources use so that they can
|
||||
|
|
@ -153,9 +165,9 @@ Complex assignments
|
|||
for any type that needs one. However, this would make the code bigger and
|
||||
the RTTI is likely already there for the GC.
|
||||
|
||||
We already knew the type information as a graph in the compiler.
|
||||
We already know the type information as a graph in the compiler.
|
||||
Thus we need to serialize this graph as RTTI for C code generation.
|
||||
Look at the file ``lib/hti.nim`` for more information.
|
||||
Look at the file ``lib/system/hti.nim`` for more information.
|
||||
|
||||
|
||||
The Garbage Collector
|
||||
|
|
@ -243,11 +255,8 @@ Consider this example:
|
|||
# r is on the stack
|
||||
setRef(r.left) # here we should update the refcounts!
|
||||
|
||||
Though it would be possible to produce code updating the refcounts (if
|
||||
necessary) before and after the call to ``setRef``, it is a complex task to
|
||||
do so in the code generator. So we don't and instead decide at runtime
|
||||
whether the reference is on the stack or not. The generated code looks
|
||||
roughly like this:
|
||||
We have to decide at runtime whether the reference is on the stack or not.
|
||||
The generated code looks roughly like this:
|
||||
|
||||
.. code-block:: C
|
||||
void setref(TNode** ref) {
|
||||
|
|
@ -260,13 +269,7 @@ roughly like this:
|
|||
|
||||
Note that for systems with a continous stack (which most systems have)
|
||||
the check whether the ref is on the stack is very cheap (only two
|
||||
comparisons). Another advantage of this scheme is that the code produced is
|
||||
smaller.
|
||||
|
||||
|
||||
The algorithm in pseudo-code
|
||||
----------------------------
|
||||
To be written.
|
||||
comparisons).
|
||||
|
||||
|
||||
The compiler's architecture
|
||||
|
|
@ -332,3 +335,93 @@ underlying C compiler already does all the hard work for us. The problem is the
|
|||
common runtime library, especially the memory manager. Note that Borland's
|
||||
Delphi had exactly the same problem. The workaround is to not link the GC with
|
||||
the Dll and provide an extra runtime dll that needs to be initialized.
|
||||
|
||||
|
||||
Code generation for closures
|
||||
============================
|
||||
|
||||
Example code:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc add(x: int): proc (y: int): int {.closure.} =
|
||||
return lambda (y: int): int =
|
||||
return x + y
|
||||
|
||||
var add2 = add(2)
|
||||
echo add2(5) #OUT 7
|
||||
|
||||
This should produce roughly this code:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
PClosure = ref object
|
||||
fn: proc (x: int, c: PClosure): int
|
||||
x: int # data
|
||||
|
||||
proc wasLambda(y: int, c: PClosure): int =
|
||||
return y + c.x
|
||||
|
||||
proc add(x: int): PClosure =
|
||||
var c: PClosure
|
||||
new(c)
|
||||
c.x = x
|
||||
c.fn = wasLambda
|
||||
|
||||
var add2 = add(2)
|
||||
echo add2.fn(5, add2)
|
||||
|
||||
|
||||
Beware of nesting:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} =
|
||||
return lamba (y: int): proc (z: int): int {.closure.} =
|
||||
return lambda (z: int): int =
|
||||
return x + y + z
|
||||
|
||||
var add24 = add(2)(4)
|
||||
echo add24(5) #OUT 11
|
||||
|
||||
This should produce roughly this code:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
PClosure1 = ref object
|
||||
fn: proc (x: int, c: PClosure1): int
|
||||
x: int # data
|
||||
|
||||
PClosure2 = ref object
|
||||
fn: proc (x: int, c: PClosure2): int
|
||||
y: int
|
||||
c1: PClosure1
|
||||
|
||||
|
||||
proc innerLambda(z: int, c2: PClosure2): int =
|
||||
return c2.c1.x + c2.y + z
|
||||
|
||||
proc outerLambda1(y: int, c1: PClosure1): PClosure2 =
|
||||
new(result)
|
||||
result.c1 = c1
|
||||
result.y = y
|
||||
result.fn = innerLambda
|
||||
|
||||
proc add(x: int): PClosure1 =
|
||||
new(result)
|
||||
result.x = x
|
||||
result.fn = outerLambda
|
||||
|
||||
var tmp = add(2)
|
||||
var tmp2 = tmp.fn(4, tmp)
|
||||
var add24 = tmp2.fn(4, tmp2)
|
||||
echo add24(5)
|
||||
|
||||
|
||||
Accumulator
|
||||
-----------
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc GetAccumulator(start: int): proc (): int {.closure} =
|
||||
var i = start
|
||||
return lambda: int =
|
||||
inc i
|
||||
return i
|
||||
|
|
|
|||
2
doc/lib.txt
Normal file → Executable file
2
doc/lib.txt
Normal file → Executable file
|
|
@ -134,7 +134,7 @@ Impure libraries
|
|||
Wrappers
|
||||
========
|
||||
|
||||
Note that the generated HTML for some of these wrappers is so huge, that it is
|
||||
The generated HTML for some of these wrappers is so huge, that it is
|
||||
not contained in the distribution. You can then find them on the website.
|
||||
|
||||
* `posix <posix.html>`_
|
||||
|
|
|
|||
363
doc/manual.txt
Normal file → Executable file
363
doc/manual.txt
Normal file → Executable file
|
|
@ -8,6 +8,10 @@ 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
|
||||
pretty much constant for a given task. -- Ran
|
||||
|
||||
About this document
|
||||
===================
|
||||
|
||||
|
|
@ -171,10 +175,10 @@ preferred. Another advantage is that it frees the programmer from remembering
|
|||
the exact spelling of an identifier.
|
||||
|
||||
|
||||
Literal strings
|
||||
String literals
|
||||
---------------
|
||||
|
||||
`Literal strings`:idx: can be delimited by matching double quotes, and can
|
||||
`String literals`:idx: can be delimited by matching double quotes, and can
|
||||
contain the following `escape sequences`:idx:\ :
|
||||
|
||||
================== ===================================================
|
||||
|
|
@ -202,12 +206,21 @@ contain the following `escape sequences`:idx:\ :
|
|||
|
||||
Strings in Nimrod may contain any 8-bit value, except embedded zeros.
|
||||
|
||||
Literal strings can also be delimited by three double squotes
|
||||
|
||||
Triple quoted string literals
|
||||
-----------------------------
|
||||
|
||||
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,
|
||||
the newline is not included in the string.
|
||||
|
||||
|
||||
Raw string literals
|
||||
-------------------
|
||||
|
||||
There are also `raw string literals` that are preceded with the letter ``r``
|
||||
(or ``R``) and are delimited by matching double quotes (just like ordinary
|
||||
string literals) and do not interpret the escape sequences. This is especially
|
||||
|
|
@ -218,7 +231,22 @@ convenient for regular expressions or Windows paths:
|
|||
var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab
|
||||
|
||||
|
||||
Literal characters
|
||||
Generalized raw string literals
|
||||
-------------------------------
|
||||
|
||||
The construct ``identifier"string literal"`` (without whitespace between the
|
||||
identifier and the opening quotation mark) is a
|
||||
`generalized raw string literal`:idx:. It is a shortcut for the construct
|
||||
``identifier(r"string literal")``, so it denotes a procedure call with a
|
||||
raw string literal as its only argument. Generalized raw string literals
|
||||
are especially convenient for embedding mini languages directly into Nimrod
|
||||
(for example regular expressions).
|
||||
|
||||
The construct ``identifier"""string literal"""`` exists too. It is a shortcut
|
||||
for ``identifier("""string literal""")``.
|
||||
|
||||
|
||||
Character literals
|
||||
------------------
|
||||
|
||||
Character literals are enclosed in single quotes ``''`` and can contain the
|
||||
|
|
@ -501,7 +529,7 @@ designed for this.
|
|||
Another reason is that Nimrod can support ``array[char, int]`` or
|
||||
``set[char]`` efficiently as many algorithms rely on this feature. The
|
||||
`TRune` type is used for Unicode characters, it can represent any Unicode
|
||||
character. ``TRune`` is declared the ``unicode`` module.
|
||||
character. ``TRune`` is declared in the ``unicode`` module.
|
||||
|
||||
|
||||
|
||||
|
|
@ -548,7 +576,7 @@ Subrange types
|
|||
~~~~~~~~~~~~~~
|
||||
A `subrange`:idx: type is a range of values from an ordinal type (the base
|
||||
type). To define a subrange type, one must specify it's limiting values: the
|
||||
highest and lowest value of the type:
|
||||
lowest and highest value of the type:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
|
|
@ -764,7 +792,7 @@ basetype can only be an ordinal type. The reason is that sets are implemented
|
|||
as high performance bit vectors.
|
||||
|
||||
Sets can be constructed via the set constructor: ``{}`` is the empty set. The
|
||||
empty set is type combatible with any special set type. The constructor
|
||||
empty set is type compatible with any special set type. The constructor
|
||||
can also be used to include elements (and ranges of elements) in the set:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
|
@ -903,9 +931,8 @@ each other:
|
|||
|
||||
`closure`:idx:
|
||||
indicates that the procedure expects a context, a closure that needs
|
||||
to be passed to the procedure. The implementation is the
|
||||
same as ``cdecl``, but with a hidden pointer parameter (the
|
||||
*closure*). The hidden parameter is always the last one.
|
||||
to be passed to the procedure. The calling convention ``nimcall`` is
|
||||
compatible to ``closure``.
|
||||
|
||||
`syscall`:idx:
|
||||
The syscall convention is the same as ``__syscall`` in C. It is used for
|
||||
|
|
@ -915,11 +942,108 @@ each other:
|
|||
The generated C code will not have any explicit calling convention and thus
|
||||
use the C compiler's default calling convention. This is needed because
|
||||
Nimrod's default calling convention for procedures is ``fastcall`` to
|
||||
improve speed. This is unlikely to be needed by the user.
|
||||
improve speed.
|
||||
|
||||
Most calling conventions exist only for the Windows 32-bit platform.
|
||||
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
TDollar = distinct int
|
||||
TEuro = distinct int
|
||||
|
||||
var
|
||||
d: TDollar
|
||||
e: TEuro
|
||||
|
||||
echo d + 12
|
||||
# Error: cannot add a number with no unit and a ``TDollar``
|
||||
|
||||
Unfortunetaly, ``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:
|
||||
|
||||
.. code-block::
|
||||
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 =
|
||||
result = TDollar(int(x) * y)
|
||||
|
||||
proc `*` (x: int, y: TDollar): TDollar =
|
||||
result = TDollar(x * int(y))
|
||||
|
||||
proc `div` ...
|
||||
|
||||
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.
|
||||
The pragma ``borrow`` has been designed to solve this problem; in principle
|
||||
it generates the above trivial implementations:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc `*` (x: TDollar, y: int): TDollar {.borrow.}
|
||||
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 proc that deals with the distinct type's base type, so no code is
|
||||
generated.
|
||||
|
||||
But it seems all this boilerplate code needs to be repeated for the ``TEuro``
|
||||
currency. This can be solved with templates_.
|
||||
|
||||
.. code-block:: nimrod
|
||||
template Additive(typ: typeDesc): stmt =
|
||||
proc `+` *(x, y: typ): typ {.borrow.}
|
||||
proc `-` *(x, y: typ): typ {.borrow.}
|
||||
|
||||
# unary operators:
|
||||
proc `+` *(x: typ): typ {.borrow.}
|
||||
proc `-` *(x: typ): typ {.borrow.}
|
||||
|
||||
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 =
|
||||
proc `<` * (x, y: typ): bool {.borrow.}
|
||||
proc `<=` * (x, y: typ): bool {.borrow.}
|
||||
proc `==` * (x, y: typ): bool {.borrow.}
|
||||
|
||||
template DefineCurrency(typ, base: expr): stmt =
|
||||
type
|
||||
typ* = distinct base
|
||||
Additive(typ)
|
||||
Multiplicative(typ, base)
|
||||
Comparable(typ)
|
||||
|
||||
DefineCurrency(TDollar, int)
|
||||
DefineCurrency(TEuro, int)
|
||||
|
||||
|
||||
|
||||
Type relations
|
||||
--------------
|
||||
|
||||
|
|
@ -956,7 +1080,7 @@ algorithm determines type equality:
|
|||
for i in 0..a.tupleLen-1:
|
||||
if not typeEqualsAux(a[i], b[i], s): return false
|
||||
result = true
|
||||
of object, enum, abstract:
|
||||
of object, enum, distinct:
|
||||
result = a == b
|
||||
of proc:
|
||||
result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and
|
||||
|
|
@ -973,7 +1097,7 @@ auxiliary set ``s`` to detect this case.
|
|||
|
||||
Subtype relation
|
||||
~~~~~~~~~~~~~~~~
|
||||
If object ``b`` inherits from ``a``, ``b`` is a subtype of ``a``. This subtype
|
||||
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
|
||||
|
|
@ -987,27 +1111,70 @@ relation is extended to the types ``var``, ``ref``, ``ptr``:
|
|||
of var, ref, ptr:
|
||||
result = isSubtype(a.baseType, b.baseType)
|
||||
|
||||
XXX nil is a special value!
|
||||
.. XXX nil is a special value!
|
||||
|
||||
|
||||
Convertible relation
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
A type ``a`` is convertible to type ``b`` iff the following algorithm returns
|
||||
true:
|
||||
A type ``a`` is **implicitely** convertible to type ``b`` iff the following
|
||||
algorithm returns true:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc isConvertible(a, b: PType): bool =
|
||||
if a.kind == b.kind:
|
||||
case a.kind
|
||||
of proc:
|
||||
# XXX range types?
|
||||
proc isImplicitelyConvertible(a, b: PType): bool =
|
||||
case a.kind
|
||||
of proc:
|
||||
if b.kind == proc:
|
||||
var x = a.parameterTuple
|
||||
var y = b.parameterTuple
|
||||
if x.tupleLen == y.tupleLen:
|
||||
for i in 0.. x.tupleLen-1:
|
||||
if not isSubtype(x[i], y[i]): return false
|
||||
result = isSubType(b.resultType, a.resultType)
|
||||
of int8: result = b.kind in {int16, int32, int64, int}
|
||||
of int16: result = b.kind in {int32, int64, int}
|
||||
of int32: result = b.kind in {int64, int}
|
||||
of float: result = b.kind in {float32, float64}
|
||||
of float32: result = b.kind in {float64, float}
|
||||
of float64: result = b.kind in {float32, float}
|
||||
of seq:
|
||||
result = b.kind == openArray and typeEquals(a.baseType, b.baseType)
|
||||
of array:
|
||||
result = b.kind == openArray and typeEquals(a.baseType, b.baseType)
|
||||
if a.baseType == char and a.indexType.rangeA == 0:
|
||||
result = b.kind = cstring
|
||||
of cstring, ptr:
|
||||
result = b.kind == pointer
|
||||
of string:
|
||||
result = b.kind == cstring
|
||||
|
||||
A type ``a`` is **explicitely** 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
|
||||
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
|
||||
if b.kind == distinct and typeEquals(b.baseType, a): return true
|
||||
return false
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Overloading resolution
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To be written.
|
||||
|
||||
|
||||
Statements and expressions
|
||||
|
|
@ -1095,7 +1262,7 @@ Type default value
|
|||
============================ ==============================================
|
||||
any integer type 0
|
||||
any float 0.0
|
||||
char '\0'
|
||||
char '\\0'
|
||||
bool false
|
||||
ref or pointer type nil
|
||||
procedural type nil
|
||||
|
|
@ -1192,8 +1359,8 @@ a static error is given. This holds only for expressions of ordinal types.
|
|||
If the expression is not of an ordinal type, and no ``else`` part is
|
||||
given, control just passes after the ``case`` statement.
|
||||
|
||||
To suppress the static error in the ordinal case the programmer needs
|
||||
to write an ``else`` part with a ``nil`` statement.
|
||||
To suppress the static error in the ordinal case an ``else`` part with a ``nil``
|
||||
statement can be used.
|
||||
|
||||
|
||||
When statement
|
||||
|
|
@ -1271,7 +1438,7 @@ Example:
|
|||
# and tries to add them
|
||||
var
|
||||
f: TFile
|
||||
if openFile(f, "numbers.txt"):
|
||||
if open(f, "numbers.txt"):
|
||||
try:
|
||||
var a = readLine(f)
|
||||
var b = readLine(f)
|
||||
|
|
@ -1285,7 +1452,7 @@ Example:
|
|||
except:
|
||||
echo("Unknown exception!")
|
||||
finally:
|
||||
closeFile(f)
|
||||
close(f)
|
||||
|
||||
The statements after the `try`:idx: are executed in sequential order unless
|
||||
an exception ``e`` is raised. If the exception type of ``e`` matches any
|
||||
|
|
@ -1417,7 +1584,7 @@ Example:
|
|||
|
||||
The `while`:idx: statement is executed until the ``expr`` evaluates to false.
|
||||
Endless loops are no error. ``while`` statements open an `implicit block`,
|
||||
so that they can be leaved with a ``break`` statement.
|
||||
so that they can be left with a ``break`` statement.
|
||||
|
||||
|
||||
Continue statement
|
||||
|
|
@ -1562,8 +1729,9 @@ type `var`).
|
|||
return intToStr(x)
|
||||
|
||||
Operators with one parameter are prefix operators, operators with two
|
||||
parameters are infix operators. There is no way to declare postfix
|
||||
operators: All postfix operators are built-in and handled by the
|
||||
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.
|
||||
|
||||
Any operator can be called like an ordinary proc with the '`opr`'
|
||||
|
|
@ -1622,18 +1790,13 @@ return values. This can be done in a cleaner way by returning a tuple:
|
|||
assert t.res == 1
|
||||
assert t.remainder = 3
|
||||
|
||||
Even more elegant is to use `tuple unpacking` to access the tuple's fields:
|
||||
Even more elegant is to use `tuple unpacking`:idx: to access the tuple's fields:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var (x, y) = divmod(8, 5) # tuple unpacking
|
||||
assert x == 1
|
||||
assert y == 3
|
||||
|
||||
Unfortunately, this form of tuple unpacking is not yet implemented.
|
||||
|
||||
..
|
||||
XXX remove this as soon as tuple unpacking is implemented
|
||||
|
||||
|
||||
|
||||
Iterators and the for statement
|
||||
|
|
@ -1655,7 +1818,7 @@ Syntax::
|
|||
The `for`:idx: statement is an abstract mechanism to iterate over the elements
|
||||
of a container. It relies on an `iterator`:idx: to do so. Like ``while``
|
||||
statements, ``for`` statements open an `implicit block`:idx:, so that they
|
||||
can be leaved with a ``break`` statement. The ``for`` loop declares
|
||||
can be left with a ``break`` statement. The ``for`` loop declares
|
||||
iteration variables (``x`` in the example) - their scope reaches until the
|
||||
end of the loop body. The iteration variables' types are inferred by the
|
||||
return type of the iterator.
|
||||
|
|
@ -1737,8 +1900,6 @@ possible within a single ``type`` section.
|
|||
Generics
|
||||
~~~~~~~~
|
||||
|
||||
`Version 0.7.10: Generic types like in the example do not work.`:red:
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
|
@ -1778,11 +1939,9 @@ Example:
|
|||
# inorder traversal of a binary tree
|
||||
# recursive iterators are not yet implemented, so this does not work in
|
||||
# the current compiler!
|
||||
if root.le != nil:
|
||||
yield inorder(root.le)
|
||||
if root.le != nil: yield inorder(root.le)
|
||||
yield root.data
|
||||
if root.ri != nil:
|
||||
yield inorder(root.ri)
|
||||
if root.ri != nil: yield inorder(root.ri)
|
||||
|
||||
var
|
||||
root: PBinaryTree[string] # instantiate a PBinaryTree with the type string
|
||||
|
|
@ -1799,12 +1958,11 @@ introduce type parameters or to instantiate a generic proc, iterator or type.
|
|||
Templates
|
||||
~~~~~~~~~
|
||||
|
||||
A `template`:idx: is a simple form of a macro. It operates on parse trees and is
|
||||
processed in the semantic pass of the compiler. So they integrate well with the
|
||||
rest of the language and share none of C's preprocessor macros flaws. However,
|
||||
they may lead to code that is harder to understand and maintain. So one ought
|
||||
to use them sparingly. The usage of ordinary procs, iterators or generics is
|
||||
preferred to the usage of templates.
|
||||
A `template`:idx: is a simple form of a macro: It is a simple substitution
|
||||
mechanism that operates on Nimrod's abstract syntax trees. It is processed in
|
||||
the semantic pass of the compiler.
|
||||
|
||||
The syntax to *invoke* a template is the same as calling a procedure.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -1815,20 +1973,86 @@ Example:
|
|||
|
||||
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
||||
|
||||
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
|
||||
templates:
|
||||
|
||||
| ``a > b`` is transformed into ``b < a``.
|
||||
| ``a in b`` is transformed into ``contains(b, a)``.
|
||||
| ``notin`` and ``isnot`` have the obvious meanings.
|
||||
|
||||
The "types" of templates can be the symbols ``expr`` (stands for *expression*),
|
||||
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
|
||||
description*). These are no real types, they just help the compiler parsing.
|
||||
Real types can be used too; this implies that expressions are expected.
|
||||
However, for parameter type checking the arguments are semantically checked
|
||||
before being passed to the template. Other arguments are not semantically
|
||||
checked before being passed to the template.
|
||||
|
||||
The template body does not open a new scope. To open a new scope a ``block``
|
||||
statement can be used:
|
||||
|
||||
.. code-block:: nimrod
|
||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
||||
var x: t
|
||||
|
||||
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
||||
# open a new scope:
|
||||
block:
|
||||
var x: t
|
||||
|
||||
declareInScope(a, int)
|
||||
a = 42 # works, `a` is known here
|
||||
|
||||
declareInNewScope(b, int)
|
||||
b = 42 # does not work, `b` is unknown
|
||||
|
||||
|
||||
If there is a ``stmt`` parameter it should be the last in the template
|
||||
declaration, because statements are passed to a template via a
|
||||
special ``:`` syntax:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
template withFile(f, fn, mode: expr, actions: stmt): stmt =
|
||||
block:
|
||||
var f: TFile
|
||||
if open(f, fn, mode):
|
||||
try:
|
||||
actions
|
||||
finally:
|
||||
close(f)
|
||||
else:
|
||||
quit("cannot open: " & fn)
|
||||
|
||||
withFile(txt, "ttempl3.txt", fmWrite):
|
||||
txt.writeln("line 1")
|
||||
txt.writeln("line 2")
|
||||
|
||||
In the example the two ``writeln`` statements are bound to the ``actions``
|
||||
parameter.
|
||||
|
||||
|
||||
**Style note**: For code readability, it is the best idea to use the least
|
||||
powerful programming construct that still suffices. So the "check list" is:
|
||||
|
||||
(1) Use an ordinary proc/iterator, if possible.
|
||||
(2) Else: Use a generic proc/iterator, if possible.
|
||||
(3) Else: Use a template, if possible.
|
||||
(4) Else: Use a macro.
|
||||
|
||||
|
||||
Macros
|
||||
------
|
||||
|
||||
`Macros`:idx: are the most powerful feature of Nimrod. They can be used
|
||||
to implement `domain specific languages`:idx:. But they may lead to code
|
||||
that is harder to understand and maintain. So one ought to use them sparingly.
|
||||
to implement `domain specific languages`:idx:.
|
||||
|
||||
While macros enable advanced compile-time code tranformations, they
|
||||
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||
Nimrod's syntax is flexible enough anyway.
|
||||
|
||||
To write macros, one needs to know how the Nimrod concrete syntax is converted
|
||||
to an abstract syntax tree. (Unfortunately the AST is not yet documented.)
|
||||
to an abstract syntax tree.
|
||||
|
||||
There are two ways to invoke a macro:
|
||||
(1) invoking a macro like a procedure call (`expression macros`)
|
||||
|
|
@ -1847,7 +2071,7 @@ variable number of arguments:
|
|||
import macros
|
||||
|
||||
macro debug(n: expr): stmt =
|
||||
# `n` is a Nimrod AST that contains the whole macro expression
|
||||
# `n` is a Nimrod AST that contains the whole macro invokation
|
||||
# this macro returns a list of statements:
|
||||
result = newNimNode(nnkStmtList, n)
|
||||
# iterate over any argument that is passed to this macro:
|
||||
|
|
@ -1948,6 +2172,7 @@ This is best illustrated by an example:
|
|||
main()
|
||||
|
||||
|
||||
.. code-block:: nimrod
|
||||
# Module B
|
||||
import A # A is not parsed here! Only the already known symbols
|
||||
# of A are imported.
|
||||
|
|
@ -1981,7 +2206,7 @@ Tuple or object scope
|
|||
The field identifiers inside a tuple or object definition are valid in the
|
||||
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.
|
||||
* In all descendent types of the object type.
|
||||
|
||||
|
|
@ -2000,9 +2225,11 @@ iterator in which case the overloading resolution takes place:
|
|||
# Module A
|
||||
var x*: string
|
||||
|
||||
.. code-block:: nimrod
|
||||
# Module B
|
||||
var x*: int
|
||||
|
||||
.. code-block:: nimrod
|
||||
# Module C
|
||||
import A, B
|
||||
write(stdout, x) # error: x is ambiguous
|
||||
|
|
@ -2035,26 +2262,22 @@ processed on the fly during semantic checking. Pragmas are enclosed in the
|
|||
special ``{.`` and ``.}`` curly brackets.
|
||||
|
||||
|
||||
define pragma
|
||||
-------------
|
||||
The `define`:idx: pragma defines a conditional symbol. This symbol may only be
|
||||
used in other pragmas and in the ``defined`` expression and not in ordinary
|
||||
Nimrod source code. The conditional symbols go into a special symbol table.
|
||||
The compiler defines the target processor and the target operating
|
||||
system as conditional symbols.
|
||||
|
||||
Warning: The ``define`` pragma is deprecated as it conflicts with separate
|
||||
compilation! One should use boolean constants as a replacement - this is
|
||||
cleaner anyway.
|
||||
noSideEffect pragma
|
||||
-------------------
|
||||
The `noSideEffect`:idx: pragma is used to mark a proc/iterator to have no side
|
||||
effects. This means that the proc/iterator only changes locations that are
|
||||
reachable from its parameters and the return value only depends on the
|
||||
arguments. If none of its parameters have the type ``var T``
|
||||
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
|
||||
|
||||
undef pragma
|
||||
------------
|
||||
The `undef`:idx: pragma the counterpart to the define pragma. It undefines a
|
||||
conditional symbol.
|
||||
|
||||
Warning: The ``undef`` pragma is deprecated as it conflicts with separate
|
||||
compilation!
|
||||
compileTime pragma
|
||||
------------------
|
||||
The `compileTime`:idx: pragma is used to mark a proc to be used at compile
|
||||
time only. No code will be generated for it. Compile time procs are useful
|
||||
as helpers for macros.
|
||||
|
||||
|
||||
error pragma
|
||||
|
|
|
|||
0
doc/mytest.cfg
Normal file → Executable file
0
doc/mytest.cfg
Normal file → Executable file
0
doc/nimdoc.css
Normal file → Executable file
0
doc/nimdoc.css
Normal file → Executable file
65
doc/nimrodc.txt
Normal file → Executable file
65
doc/nimrodc.txt
Normal file → Executable file
|
|
@ -107,8 +107,8 @@ non-optional argument has to be the name of the dynamic library:
|
|||
proc gtk_image_new(): PGtkWidget {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}
|
||||
|
||||
In general, importing a dynamic library does not require any special linker
|
||||
options or linking with import libraries. This also
|
||||
implies that no *devel* packages need to be installed.
|
||||
options or linking with import libraries. This also implies that no *devel*
|
||||
packages need to be installed.
|
||||
|
||||
|
||||
No_decl Pragma
|
||||
|
|
@ -279,9 +279,7 @@ However, sometimes one has to optimize. Do it in the following order:
|
|||
4. try to find a better algorithm
|
||||
5. do low-level optimizations
|
||||
|
||||
This section can only help you with the last item. Note that rewriting parts
|
||||
of your program in C is *never* necessary to speed up your program, because
|
||||
everything that can be done in C can be done in Nimrod.
|
||||
This section can only help you with the last item.
|
||||
|
||||
|
||||
Optimizing string handling
|
||||
|
|
@ -308,31 +306,32 @@ if several different string constants are used. This is likely to be more
|
|||
efficient than any hand-coded scheme.
|
||||
|
||||
|
||||
The ECMAScript code generator
|
||||
=============================
|
||||
|
||||
Note: As of version 0.7.0 the ECMAScript code generator is not maintained any
|
||||
longer. Help if you are interested.
|
||||
|
||||
Note: I use the term `ECMAScript`:idx: here instead of `JavaScript`:idx:, since
|
||||
it is the proper term.
|
||||
|
||||
The ECMAScript code generator is experimental!
|
||||
|
||||
Nimrod targets ECMAScript 1.5 which is supported by any widely used browser.
|
||||
Since ECMAScript does not have a portable means to include another module,
|
||||
Nimrod just generates a long ``.js`` file.
|
||||
|
||||
Features or modules that the ECMAScript platform does not support are not
|
||||
available. This includes:
|
||||
|
||||
* manual memory management (``alloc``, etc.)
|
||||
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||
* file management (``openfile``, etc.)
|
||||
* most modules of the Standard library
|
||||
* proper 64 bit integer arithmetic
|
||||
* proper unsigned integer arithmetic
|
||||
|
||||
However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
|
||||
available! To access the DOM, use the `dom`:idx: module that is only available
|
||||
for the ECMAScript platform.
|
||||
..
|
||||
The ECMAScript code generator
|
||||
=============================
|
||||
|
||||
Note: As of version 0.7.0 the ECMAScript code generator is not maintained any
|
||||
longer. Help if you are interested.
|
||||
|
||||
Note: I use the term `ECMAScript`:idx: here instead of `JavaScript`:idx:,
|
||||
since it is the proper term.
|
||||
|
||||
The ECMAScript code generator is experimental!
|
||||
|
||||
Nimrod targets ECMAScript 1.5 which is supported by any widely used browser.
|
||||
Since ECMAScript does not have a portable means to include another module,
|
||||
Nimrod just generates a long ``.js`` file.
|
||||
|
||||
Features or modules that the ECMAScript platform does not support are not
|
||||
available. This includes:
|
||||
|
||||
* manual memory management (``alloc``, etc.)
|
||||
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||
* file management
|
||||
* most modules of the Standard library
|
||||
* proper 64 bit integer arithmetic
|
||||
* proper unsigned integer arithmetic
|
||||
|
||||
However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
|
||||
available! To access the DOM, use the `dom`:idx: module that is only
|
||||
available for the ECMAScript platform.
|
||||
|
|
|
|||
0
doc/overview.txt
Normal file → Executable file
0
doc/overview.txt
Normal file → Executable file
0
doc/readme.txt
Normal file → Executable file
0
doc/readme.txt
Normal file → Executable file
0
doc/regexprs.txt
Normal file → Executable file
0
doc/regexprs.txt
Normal file → Executable file
0
doc/rst.txt
Normal file → Executable file
0
doc/rst.txt
Normal file → Executable file
|
|
@ -1,24 +0,0 @@
|
|||
==============================
|
||||
First steps after installation
|
||||
==============================
|
||||
|
||||
This document explains how to *use* the Nimrod compiler.
|
||||
Open your favourite text editor and type (or download it
|
||||
`here <download/code/hallo.nim>`_):
|
||||
|
||||
.. code-block:: nimrod
|
||||
:file: ../tests/hallo.nim
|
||||
|
||||
Save this file as ``hallo.nim`` somewhere (I refer to the location as
|
||||
``$yourloc``). Now open a console and call the Nimrod compiler::
|
||||
|
||||
nimrod compile --run $yourloc/hallo
|
||||
|
||||
The ``--run`` switch tells Nimrod that it should run the generated
|
||||
executable after successful compilation. If things don't work,
|
||||
check if Nimrod's ``bin`` directory is in your path environment
|
||||
variable. On Windows the directory ``dist\llvm-gcc4.2\bin`` may
|
||||
also be required in your path.
|
||||
|
||||
Note that Nimrod produced a standalone native executable in
|
||||
``$yourloc`` that you can run without the Nimrod compiler.
|
||||
1200
doc/theindex.txt
Normal file → Executable file
1200
doc/theindex.txt
Normal file → Executable file
File diff suppressed because it is too large
Load diff
0
doc/tut1.txt
Normal file → Executable file
0
doc/tut1.txt
Normal file → Executable file
46
doc/tut2.txt
Normal file → Executable file
46
doc/tut2.txt
Normal file → Executable file
|
|
@ -311,11 +311,10 @@ class provides a constructor, etc.
|
|||
c.draw()
|
||||
|
||||
The code uses a ``draw`` procedure that is bound statically, but inside it
|
||||
the dynamic dispatch happens with the help of the ``fdraw`` field. This is
|
||||
slightly more inconvienent than in traditional OOP-languages, but has the
|
||||
advantage of being much more flexible (and somewhat faster). The above approach
|
||||
also allows some form *monkey patching* by modifying the ``fdraw`` field.
|
||||
|
||||
the dynamic dispatch happens with the help of the ``fdraw`` field. Even though
|
||||
this solution has its advantages compared to traditional OOP-languages, it is
|
||||
a **preliminary** solution. Multimethods are a planned language feature that
|
||||
provide a more flexible and efficient mechanism.
|
||||
|
||||
|
||||
Exceptions
|
||||
|
|
@ -323,15 +322,13 @@ Exceptions
|
|||
|
||||
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 should stick to. Reusing an existing exception type is
|
||||
often better than defining a new exception type: It avoids a proliferation of
|
||||
types.
|
||||
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:
|
||||
For example, if a file cannot be opened, this should not raise an exception
|
||||
since this is quite common (the file may have been deleted).
|
||||
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
|
||||
|
|
@ -359,7 +356,7 @@ The `try`:idx: statement handles exceptions:
|
|||
# and tries to add them
|
||||
var
|
||||
f: TFile
|
||||
if openFile(f, "numbers.txt"):
|
||||
if open(f, "numbers.txt"):
|
||||
try:
|
||||
var a = readLine(f)
|
||||
var b = readLine(f)
|
||||
|
|
@ -375,7 +372,7 @@ The `try`:idx: statement handles exceptions:
|
|||
# reraise the unknown exception:
|
||||
raise
|
||||
finally:
|
||||
closeFile(f)
|
||||
close(f)
|
||||
|
||||
The statements after the ``try`` are executed unless an exception is
|
||||
raised. Then the appropriate ``except`` part is executed.
|
||||
|
|
@ -396,8 +393,6 @@ is not executed (if an exception occurs).
|
|||
Generics
|
||||
========
|
||||
|
||||
`Version 0.7.10: Complex generic types like in the example do not work.`:red:
|
||||
|
||||
`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:
|
||||
|
|
@ -448,7 +443,7 @@ containers:
|
|||
while stack.len > 0:
|
||||
var n = stack.pop()
|
||||
while n != nil:
|
||||
yield n
|
||||
yield n.data
|
||||
add(stack, n.ri) # push right subtree onto the stack
|
||||
n = n.le # and follow the left pointer
|
||||
|
||||
|
|
@ -472,8 +467,7 @@ 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
|
||||
of C's preprocessor macros flaws. However, they may lead to code that is harder
|
||||
to understand and maintain. So one should use them sparingly.
|
||||
of C's preprocessor macros flaws.
|
||||
|
||||
To *invoke* a template, call it like a procedure.
|
||||
|
||||
|
|
@ -488,7 +482,8 @@ Example:
|
|||
|
||||
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.
|
||||
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)``.
|
||||
|
|
@ -513,7 +508,7 @@ 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 said to be *eager*).
|
||||
|
||||
Turning the ``log`` proc into a template solves this problem in an elegant way:
|
||||
Turning the ``log`` proc into a template solves this problem:
|
||||
|
||||
.. code-block:: nimrod
|
||||
const
|
||||
|
|
@ -530,7 +525,7 @@ Turning the ``log`` proc into a template solves this problem in an elegant way:
|
|||
The "types" of templates can be the symbols ``expr`` (stands for *expression*),
|
||||
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
|
||||
description*). These are no real types, they just help the compiler parsing.
|
||||
In later versions, real types will be supported too.
|
||||
However, real types are supported too.
|
||||
|
||||
The template body does not open a new scope. To open a new scope
|
||||
use a ``block`` statement:
|
||||
|
|
@ -557,7 +552,8 @@ via a special ``:`` syntax:
|
|||
|
||||
.. code-block:: nimrod
|
||||
|
||||
template withFile(f, filename, mode: expr, actions: stmt): stmt =
|
||||
template withFile(f: expr, filename: string, mode: TFileMode,
|
||||
actions: stmt): stmt =
|
||||
block:
|
||||
var fn = filename
|
||||
var f: TFile
|
||||
|
|
@ -583,11 +579,6 @@ once.
|
|||
Macros
|
||||
======
|
||||
|
||||
If the template mechanism scares you, you will be pleased to hear that
|
||||
templates are not really necessary: Macros can do anything that templates can
|
||||
do and much more. Macros are harder to write than templates and even harder
|
||||
to get right :-). Now that you have been warned, lets see what a macro *is*.
|
||||
|
||||
Macros enable advanced compile-time code tranformations, but they
|
||||
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||
Nimrod's syntax is flexible enough anyway.
|
||||
|
|
@ -598,7 +589,8 @@ to an abstract syntax tree (AST). The AST is documented in the
|
|||
|
||||
There are two ways to invoke a macro:
|
||||
(1) invoking a macro like a procedure call (`expression macros`:idx:)
|
||||
(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`:idx:)
|
||||
(2) invoking a macro with the special ``macrostmt``
|
||||
syntax (`statement macros`:idx:)
|
||||
|
||||
|
||||
Expression Macros
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue