better subscript overloading

This commit is contained in:
rumpf_a@web.de 2010-01-03 12:31:21 +01:00
commit a58a2f3823
85 changed files with 55936 additions and 2319 deletions

View file

@ -32,6 +32,7 @@ get get, ``[]`` consider overloading ``[]`` for get;
prefix: ``len`` instead of ``getLen``
length len also used for *number of elements*
size size, len size should refer to a byte size
memory mem implies a low-level operation
items items default iterator over a collection
pairs pairs iterator over (key, value) pairs
delete delete, del del is supposed to be faster than

View file

@ -24,7 +24,8 @@ indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
castExpr ::= 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
addrExpr ::= 'addr' '(' optInd expr optPar ')'
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
| '[' ']' | '=' | literal)+ '`'
| '[' (',' | ['$'] '..' ['$'])* ']'
| '=' | literal)+ '`'
| IDENT
primaryPrefix ::= (prefixOperator | 'bind') optInd

View file

@ -693,15 +693,16 @@ Example:
var
x: TIntArray
y: TIntSeq
x = [1, 2, 3, 4, 5, 6] # [] this is the array constructor
x = [1, 2, 3, 4, 5, 6] # [] is the array constructor
y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence
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.
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``.
@ -935,8 +936,8 @@ 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 compatibility: procedural types are only compatible
if they have the same calling convention.
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
each other:
@ -1304,7 +1305,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 then 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.
@ -1776,8 +1777,8 @@ Calling a procedure can be done in many different ways:
callme 0, 1, "abc", '\t'
A procedure cannot modify its parameters (unless the parameters have the
type `var`).
A procedure cannot modify its parameters (unless the parameters have the type
`var`).
`Operators`:idx: are procedures with a special operator symbol as identifier:
@ -1809,7 +1810,8 @@ Var parameters
The type of a parameter may be prefixed with the ``var`` keyword:
.. code-block:: nimrod
proc divmod(a, b: int, res, remainder: var int) =
proc divmod(a, b: int,
res, remainder: var int) =
res = a div b
remainder = a mod b
@ -1827,7 +1829,8 @@ an l-value. Var parameters are implemented as hidden pointers. The
above example is equivalent to:
.. code-block:: nimrod
proc divmod(a, b: int, res, remainder: ptr int) =
proc divmod(a, b: int,
res, remainder: ptr int) =
res^ = a div b
remainder^ = a mod b
@ -1856,6 +1859,15 @@ One can use `tuple unpacking`:idx: to access the tuple's fields:
assert y == 3
Overloading of the subscript operator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded.
Overloading support is only possible if the first parameter has no type that
already supports the built-in ``[]`` notation. Currently the compiler currently
does not check this. XXX Multiple indexes
Multi-methods
~~~~~~~~~~~~~
@ -2313,11 +2325,12 @@ regular expressions:
Modules
-------
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 dependencies`:idx: are allowed, but slightly subtle. Only
top-level symbols that are marked with an asterisk (``*``) are exported.
Each module needs to be in its own file and has its own `namespace`:idx:.
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 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:
@ -2413,6 +2426,7 @@ The Nimrod compiler emits different kinds of messages: `hint`:idx:,
`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if
the compiler encounters any static error.
Pragmas
=======
@ -2426,7 +2440,9 @@ Syntax::
Pragmas are Nimrod's method to give the compiler additional information/
commands without introducing a massive number of new keywords. Pragmas are
processed on the fly during semantic checking. Pragmas are enclosed in the
special ``{.`` and ``.}`` curly brackets.
special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a
first implementation to play with a language feature before a nicer syntax
to access the feature becomes available.
noSideEffect pragma
@ -2439,6 +2455,12 @@ 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.
**Possible future**: ``func`` may become a keyword and syntactic sugar for a
proc with no side effects:
.. code-block:: nimrod
func `+` (x, y: int): int
procvar pragma
--------------
@ -2458,6 +2480,53 @@ noReturn pragma
The `noreturn`:idx: pragma is used to mark a proc that it never returns.
Acyclic pragma
--------------
The `acyclic`:idx: pragma can be used for object types to mark them as acyclic
even though they seem to be cyclic. This is an **optimization** for the garbage
collector to not consider objects of this type as part of a cycle:
.. code-block:: nimrod
type
PNode = ref TNode
TNode {.acyclic, final.} = object
left, right: PNode
data: string
In the example a tree structure is declared with the ``TNode`` type. Note that
the type definition is recursive and the GC has to assume that objects of
this type may form a cyclic graph. The ``acyclic`` pragma passes the
information that this cannot happen to the GC. If the programmer uses the
``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
memory, but nothing worse happens.
**Possible future**: The ``acyclic`` pragma may become a property of a
``ref`` type:
.. code-block:: nimrod
type
PNode = acyclic ref TNode
TNode = object
left, right: PNode
data: string
Final pragma
------------
The `final`:idx: pragma can be used for an object type to specify that it
cannot be inherited from.
Pure pragma
-----------
The `pure`:idx: pragma serves two completely different purposes:
1) To mark a procedure that Nimrod should not generate any exit statements like
``return result;`` in the generated code. This is useful for procs that only
consist of an assembler statement.
2) To mark an object type that Nimrod should omit its type field. This is
necessary for compatibility with other compiled languages.
error pragma
------------
The `error`:idx: pragma is used to make the compiler output an error message
@ -2487,8 +2556,8 @@ compilation option pragmas
The listed pragmas here can be used to override the code generation options
for a section of code.
The implementation currently provides the following possible options (later
various others may be added).
The implementation currently provides the following possible options (various
others may be added later).
=============== =============== ============================================
pragma allowed values description
@ -2532,3 +2601,142 @@ but are used to override the settings temporarily. Example:
# speed critical
# ... some code ...
{.pop.} # restore old settings
Register pragma
---------------
The `register`:idx: pragma is for variables only. It declares the variable as
``register``, giving the compiler a hint that the variable should be placed
in a hardware register for faster access. C compilers usually ignore this
though and for good reasons: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though.
DeadCodeElim pragma
-------------------
The `deadCodeElim`:idx: pragma only applies to whole modules: It tells the
compiler to activate (or deactivate) dead code elimination for the module the
pragma appers in.
The ``--deadCodeElim:on`` command line switch has the same effect as marking
every module with ``{.deadCodeElim:on}``. However, for some modules such as
the GTK wrapper it makes sense to *always* turn on dead code elimination -
no matter if it is globally active or not.
Example:
.. code-block:: nimrod
{.deadCodeElim: on.}
Disabling certain messages
--------------------------
Nimrod generates some warnings and hints ("line too long") that may annoy the
user. A mechanism for disabling certain messages is provided: Each hint
and warning message contains a symbol in brackets. This is the message's
identifier that can be used to enable or disable it:
.. code-block:: Nimrod
{.warning[LineTooLong]: off.} # turn off warning about too long lines
This is often better than disabling all warnings at once.
Foreign function interface
==========================
Nimrod's `FFI`:idx: (foreign function interface) is extensive and only the
parts that scale to other future backends (like the LLVM/EcmaScript backends)
are documented here.
Importc pragma
--------------
The `importc`:idx: pragma provides a means to import a proc or a variable
from C. The optional argument is a string containing the C identifier. If
the argument is missing, the C name is the Nimrod identifier *exactly as
spelled*:
.. code-block::
proc printf(formatstr: cstring) {.importc: "printf", varargs.}
Note that this pragma is somewhat of a misnomer: Other backends will provide
the same feature under the same name.
Exportc pragma
--------------
The `exportc`:idx: pragma provides a means to export a type, a variable, or a
procedure to C. The optional argument is a string containing the C identifier.
If the argument is missing, the C name is the Nimrod
identifier *exactly as spelled*:
.. code-block:: Nimrod
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
Note that this pragma is somewhat of a misnomer: Other backends will provide
the same feature under the same name.
Varargs pragma
--------------
The `varargs`:idx: pragma can be applied to procedures only (and procedure
types). It tells Nimrod that the proc can take a variable number of parameters
after the last specified parameter. Nimrod string values will be converted to C
strings automatically:
.. code-block:: Nimrod
proc printf(formatstr: cstring) {.nodecl, varargs.}
printf("hallo %s", "world") # "world" will be passed as C string
Dynlib pragma
-------------
With the `dynlib`:idx: pragma a procedure can be imported from
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
non-optional argument has to be the name of the dynamic library:
.. code-block:: Nimrod
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.
The ``dynlib`` import mechanism supports a versioning scheme:
.. code-block:: nimrod
proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl,
importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".}
At runtime the dynamic library is searched for (in this order)::
libtcl.so.1
libtcl.so.0
libtcl8.5.so.1
libtcl8.5.so.0
libtcl8.4.so.1
libtcl8.4.so.0
libtcl8.3.so.1
libtcl8.3.so.0
The ``dynlib`` pragma supports not only constant strings as argument but also
string expressions in general:
.. code-block:: nimrod
import os
proc getDllName: string =
result = "mylib.dll"
if ExistsFile(result): return
result = "mylib2.dll"
if ExistsFile(result): return
quit("could not load dynamic library")
proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
strings, because they are precompiled.

View file

@ -71,87 +71,12 @@ Additional Features
===================
This section describes Nimrod's additional features that are not listed in the
Nimrod manual.
New Pragmas and Options
-----------------------
Because Nimrod generates C code it needs some "red tape" to work properly.
Lots of options and pragmas for tweaking the generated C code are available.
Importc Pragma
~~~~~~~~~~~~~~
The `importc`:idx: pragma provides a means to import a type, a variable, or a
procedure from C. The optional argument is a string containing the C
identifier. If the argument is missing, the C name is the Nimrod
identifier *exactly as spelled*:
.. code-block::
proc printf(formatstr: cstring) {.importc: "printf", varargs.}
Nimrod manual. Some of the features here only make sense for the C code
generator and are subject to change.
Exportc Pragma
~~~~~~~~~~~~~~
The `exportc`:idx: pragma provides a means to export a type, a variable, or a
procedure to C. The optional argument is a string containing the C
identifier. If the argument is missing, the C name is the Nimrod
identifier *exactly as spelled*:
.. code-block:: Nimrod
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
Dynlib Pragma
~~~~~~~~~~~~~
With the `dynlib`:idx: pragma a procedure or a variable can be imported from
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
non-optional argument has to be the name of the dynamic library:
.. code-block:: Nimrod
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.
The ``dynlib`` import mechanism supports a versioning scheme:
.. code-block:: nimrod
proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl,
importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".}
At runtime the dynamic library is searched for (in this order)::
libtcl.so.1
libtcl.so.0
libtcl8.5.so.1
libtcl8.5.so.0
libtcl8.4.so.1
libtcl8.4.so.0
libtcl8.3.so.1
libtcl8.3.so.0
The ``dynlib`` pragma supports not only constant strings as argument but also
string expressions in general:
.. code-block:: nimrod
import os
proc getDllName: string =
result = "mylib.dll"
if ExistsFile(result): return
result = "mylib2.dll"
if ExistsFile(result): return
quit("could not load dynamic library")
proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
strings, because they are precompiled.
NoDecl Pragma
~~~~~~~~~~~~~
NoDecl pragma
-------------
The `noDecl`:idx: pragma can be applied to almost any symbol (variable, proc,
type, etc.) and is sometimes useful for interoperability with C:
It tells Nimrod that it should not generate a declaration for the symbol in
@ -164,9 +89,11 @@ the C code. For example:
However, the ``header`` pragma is often the better alternative.
**Note**: This will not work for the LLVM backend.
Header Pragma
~~~~~~~~~~~~~
Header pragma
-------------
The `header`:idx: pragma is very similar to the ``noDecl`` pragma: It can be
applied to almost any symbol and specifies that it should not be declared
and instead the generated code should contain an ``#include``:
@ -181,118 +108,48 @@ contains the header file: As usual for C, a system header file is enclosed
in angle brackets: ``<>``. If no angle brackets are given, Nimrod
encloses the header file in ``""`` in the generated C code.
Varargs Pragma
~~~~~~~~~~~~~~
The `varargs`:idx: pragma can be applied to procedures only (and procedure
types). It tells Nimrod that the proc can take a variable number of parameters
after the last specified parameter. Nimrod string values will be converted to C
strings automatically:
.. code-block:: Nimrod
proc printf(formatstr: cstring) {.nodecl, varargs.}
printf("hallo %s", "world") # "world" will be passed as C string
**Note**: This will not work for the LLVM backend.
LineDir Option
~~~~~~~~~~~~~~
LineDir option
--------------
The `lineDir`:idx: option can be turned on or off. If turned on the
generated C code contains ``#line`` directives. This may be helpful for
debugging with GDB.
StackTrace Option
~~~~~~~~~~~~~~~~~
StackTrace option
-----------------
If the `stackTrace`:idx: option is turned on, the generated C contains code to
ensure that proper stack traces are given if the program crashes or an
uncaught exception is raised.
LineTrace Option
~~~~~~~~~~~~~~~~
LineTrace option
----------------
The `lineTrace`:idx: option implies the ``stackTrace`` option. If turned on,
the generated C contains code to ensure that proper stack traces with line
number information are given if the program crashes or an uncaught exception
is raised.
Debugger Option
~~~~~~~~~~~~~~~
Debugger option
---------------
The `debugger`:idx: option enables or disables the *Embedded Nimrod Debugger*.
See the documentation of endb_ for further information.
Breakpoint Pragma
~~~~~~~~~~~~~~~~~
Breakpoint pragma
-----------------
The *breakpoint* pragma was specially added for the sake of debugging with
ENDB. See the documentation of `endb <endb.html>`_ for further information.
Volatile Pragma
~~~~~~~~~~~~~~~
Volatile pragma
---------------
The `volatile`:idx: pragma is for variables only. It declares the variable as
``volatile``, whatever that means in C/C++.
Register Pragma
~~~~~~~~~~~~~~~
The `register`:idx: pragma is for variables only. It declares the variable as
``register``, giving the compiler a hint that the variable should be placed
in a hardware register for faster access. C compilers usually ignore this
though and for good reasons: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though.
Acyclic Pragma
~~~~~~~~~~~~~~
The `acyclic`:idx: pragma can be used for object types to mark them as acyclic
even though they seem to be cyclic. This is an **optimization** for the garbage
collector to not consider objects of this type as part of a cycle:
.. code-block:: nimrod
type
PNode = ref TNode
TNode {.acyclic, final.} = object
left, right: PNode
data: string
In the example a tree structure is declared with the ``TNode`` type. Note that
the type definition is recursive and the GC has to assume that objects of
this type may form a cyclic graph. The ``acyclic`` pragma passes the
information that this cannot happen to the GC. If the programmer uses the
``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
memory, but nothing worse happens.
DeadCodeElim Pragma
~~~~~~~~~~~~~~~~~~~
The `deadCodeElim`:idx: pragma only applies to whole modules: It tells the
compiler to activate (or deactivate) dead code elimination for the module the
pragma appers in.
The ``--deadCodeElim:on`` command line switch has the same effect as marking
every module with ``{.deadCodeElim:on}``. However, for some modules such as
the GTK wrapper it makes sense to *always* turn on dead code elimination -
no matter if it is globally active or not.
Example:
.. code-block:: nimrod
{.deadCodeElim: on.}
Disabling certain messages
--------------------------
Nimrod generates some warnings and hints ("line too long") that may annoy the
user. A mechanism for disabling certain messages is provided: Each hint
and warning message contains a symbol in brackets. This is the message's
identifier that can be used to enable or disable it:
.. code-block:: Nimrod
{.warning[LineTooLong]: off.} # turn off warning about too long lines
This is often better than disabling all warnings at once.
**Note**: This pragma will not exist for the LLVM backend.
Debugging with Nimrod