diff options
Diffstat (limited to 'doc/manual')
-rw-r--r-- | doc/manual/about.txt | 26 | ||||
-rw-r--r-- | doc/manual/definitions.txt | 6 | ||||
-rw-r--r-- | doc/manual/effects.txt | 36 | ||||
-rw-r--r-- | doc/manual/ffi.txt | 40 | ||||
-rw-r--r-- | doc/manual/generics.txt | 13 | ||||
-rw-r--r-- | doc/manual/lexing.txt | 86 | ||||
-rw-r--r-- | doc/manual/locking.txt | 18 | ||||
-rw-r--r-- | doc/manual/modules.txt | 29 | ||||
-rw-r--r-- | doc/manual/pragmas.txt | 523 | ||||
-rw-r--r-- | doc/manual/procs.txt | 166 | ||||
-rw-r--r-- | doc/manual/special_ops.txt | 2 | ||||
-rw-r--r-- | doc/manual/stmts.txt | 139 | ||||
-rw-r--r-- | doc/manual/syntax.txt | 42 | ||||
-rw-r--r-- | doc/manual/taint.txt | 8 | ||||
-rw-r--r-- | doc/manual/templates.txt | 82 | ||||
-rw-r--r-- | doc/manual/threads.txt | 4 | ||||
-rw-r--r-- | doc/manual/trmacros.txt | 72 | ||||
-rw-r--r-- | doc/manual/type_bound_ops.txt | 62 | ||||
-rw-r--r-- | doc/manual/type_rel.txt | 21 | ||||
-rw-r--r-- | doc/manual/type_sections.txt | 2 | ||||
-rw-r--r-- | doc/manual/types.txt | 74 |
21 files changed, 1086 insertions, 365 deletions
diff --git a/doc/manual/about.txt b/doc/manual/about.txt index 78167efe3..58e3baa85 100644 --- a/doc/manual/about.txt +++ b/doc/manual/about.txt @@ -1,37 +1,37 @@ About this document =================== -**Note**: This document is a draft! Several of Nim's features need more -precise wording. This manual will evolve into a proper specification some -day. +**Note**: This document is a draft! Several of Nim's features may need more +precise wording. This manual is constantly evolving until the 1.0 release and is +not to be considered as the final proper specification. This document describes the lexis, the syntax, and the semantics of Nim. -The language constructs are explained using an extended BNF, in -which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and -``(a)?`` means an optional *a*. Parentheses may be used to group elements. +The language constructs are explained using an extended BNF, in which ``(a)*`` +means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and ``(a)?`` means an +optional *a*. Parentheses may be used to group elements. ``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but not consumed. It will be consumed in the following rule. -The ``|``, ``/`` symbols are used to mark alternatives and have the lowest -precedence. ``/`` is the ordered choice that requires the parser to try the +The ``|``, ``/`` symbols are used to mark alternatives and have the lowest +precedence. ``/`` is the ordered choice that requires the parser to try the alternatives in the given order. ``/`` is often used to ensure the grammar -is not ambiguous. +is not ambiguous. Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted with ``'``. An example:: ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? - + The binary ``^*`` operator is used as a shorthand for 0 or more occurrences -separated by its second argument; likewise ``^+`` means 1 or more -occurrences: ``a ^+ b`` is short for ``a (b a)*`` +separated by its second argument; likewise ``^+`` means 1 or more +occurrences: ``a ^+ b`` is short for ``a (b a)*`` and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: arrayConstructor = '[' expr ^* ',' ']' Other parts of Nim - like scoping rules or runtime semantics are only -described in an informal manner for now. +described in the, more easily comprehensible, informal manner for now. diff --git a/doc/manual/definitions.txt b/doc/manual/definitions.txt index 9eb20f70f..21954fb78 100644 --- a/doc/manual/definitions.txt +++ b/doc/manual/definitions.txt @@ -26,11 +26,11 @@ program execution. Unless explicitly classified, an error is a static error. A `checked runtime error`:idx: is an error that the implementation detects and reports at runtime. The method for reporting such errors is via *raising -exceptions* or *dying with a fatal error*. However, the implementation +exceptions* or *dying with a fatal error*. However, the implementation provides a means to disable these runtime checks. See the section pragmas_ -for details. +for details. -Wether a checked runtime error results in an exception or in a fatal error at +Whether a checked runtime error results in an exception or in a fatal error at runtime is implementation specific. Thus the following program is always invalid: diff --git a/doc/manual/effects.txt b/doc/manual/effects.txt index a79f6ea85..254a43fbb 100644 --- a/doc/manual/effects.txt +++ b/doc/manual/effects.txt @@ -5,7 +5,7 @@ Exception tracking ------------------ Nim supports exception tracking. The `raises`:idx: pragma can be used -to explicitly define which exceptions a proc/iterator/method/converter is +to explicitly define which exceptions a proc/iterator/method/converter is allowed to raise. The compiler verifies this: .. code-block:: nim @@ -24,7 +24,7 @@ An empty ``raises`` list (``raises: []``) means that no exception may be raised: result = false -A ``raises`` list can also be attached to a proc type. This affects type +A ``raises`` list can also be attached to a proc type. This affects type compatibility: .. code-block:: nim @@ -35,7 +35,7 @@ compatibility: proc p(x: string) = raise newException(OSError, "OS") - + c = p # type error @@ -46,30 +46,30 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph: raise ``system.Exception`` (the base type of the exception hierarchy) and thus any exception unless ``T`` has an explicit ``raises`` list. However if the call is of the form ``f(...)`` where ``f`` is a parameter - of the currently analysed routine it is ignored. The call is optimistically + of the currently analysed routine it is ignored. The call is optimistically assumed to have no effect. Rule 2 compensates for this case. -2. Every expression of some proc type wihtin a call that is not a call - itself (and not nil) is assumed to be called indirectly somehow and thus +2. Every expression of some proc type within a call that is not a call + itself (and not nil) is assumed to be called indirectly somehow and thus its raises list is added to ``p``'s raises list. -3. Every call to a proc ``q`` which has an unknown body (due to a forward - declaration or an ``importc`` pragma) is assumed to +3. Every call to a proc ``q`` which has an unknown body (due to a forward + declaration or an ``importc`` pragma) is assumed to raise ``system.Exception`` unless ``q`` has an explicit ``raises`` list. -4. Every call to a method ``m`` is assumed to +4. Every call to a method ``m`` is assumed to raise ``system.Exception`` unless ``m`` has an explicit ``raises`` list. 5. For every other call the analysis can determine an exact ``raises`` list. -6. For determining a ``raises`` list, the ``raise`` and ``try`` statements +6. For determining a ``raises`` list, the ``raise`` and ``try`` statements of ``p`` are taken into consideration. -Rules 1-2 ensure the following works: +Rules 1-2 ensure the following works: .. code-block:: nim proc noRaise(x: proc()) {.raises: [].} = # unknown call that might raise anything, but valid: x() - + proc doRaise() {.raises: [IOError].} = raise newException(IOError, "IO") - + proc use() {.raises: [].} = # doesn't compile! Can raise IOError! noRaise(doRaise) @@ -82,21 +82,21 @@ Tag tracking ------------ The exception tracking is part of Nim's `effect system`:idx:. Raising an -exception is an *effect*. Other effects can also be defined. A user defined +exception is an *effect*. Other effects can also be defined. A user defined effect is a means to *tag* a routine and to perform checks against this tag: .. code-block:: nim type IO = object ## input/output effect proc readLine(): string {.tags: [IO].} - + proc no_IO_please() {.tags: [].} = # the compiler prevents this: let x = readLine() -A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can +A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can also be attached to a proc type. This affects type compatibility. -The inference for tag tracking is analogous to the inference for +The inference for tag tracking is analogous to the inference for exception tracking. @@ -105,7 +105,7 @@ Read/Write tracking **Note**: Read/write tracking is not yet implemented! -The inference for read/write tracking is analogous to the inference for +The inference for read/write tracking is analogous to the inference for exception tracking. diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt index 4a4e0316f..f9056b159 100644 --- a/doc/manual/ffi.txt +++ b/doc/manual/ffi.txt @@ -70,8 +70,8 @@ the compiler to pass the type by reference (hidden pointer) to procs. Varargs pragma -------------- -The ``varargs`` pragma can be applied to procedures only (and procedure -types). It tells Nim that the proc can take a variable number of parameters +The ``varargs`` pragma can be applied to procedures only (and procedure +types). It tells Nim that the proc can take a variable number of parameters after the last specified parameter. Nim string values will be converted to C strings automatically: @@ -94,20 +94,20 @@ should scan unions conservatively. Packed pragma ------------- -The ``packed`` pragma can be applied to any ``object`` type. It ensures -that the fields of an object are packed back-to-back in memory. It is useful -to store packets or messages from/to network or hardware drivers, and for -interoperability with C. Combining packed pragma with inheritance is not -defined, and it should not be used with GC'ed memory (ref's). +The ``packed`` pragma can be applied to any ``object`` type. It ensures +that the fields of an object are packed back-to-back in memory. It is useful +to store packets or messages from/to network or hardware drivers, and for +interoperability with C. Combining packed pragma with inheritance is not +defined, and it should not be used with GC'ed memory (ref's). -**Future directions**: Using GC'ed memory in packed pragma will result in +**Future directions**: Using GC'ed memory in packed pragma will result in compile-time error. Usage with inheritance should be defined and documented. Unchecked pragma ---------------- The ``unchecked`` pragma can be used to mark a named array as ``unchecked`` -meaning its bounds are not checked. This is often useful when one wishes to -implement his own flexibly sized arrays. Additionally an unchecked array is +meaning its bounds are not checked. This is often useful to +implement customized flexibly sized arrays. Additionally an unchecked array is translated into a C array of undetermined size: .. code-block:: nim @@ -141,7 +141,7 @@ runtime size of the array. Dynlib pragma for import ------------------------ With the ``dynlib`` pragma a procedure or a variable can be imported from -a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). +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:: Nim @@ -152,17 +152,17 @@ 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: +The ``dynlib`` import mechanism supports a versioning scheme: -.. code-block:: nim - proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, +.. code-block:: nim + 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.1 libtcl8.5.so.0 libtcl8.4.so.1 libtcl8.4.so.0 @@ -175,22 +175,22 @@ string expressions in general: .. code-block:: nim import os - proc getDllName: string = + 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. -**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime +**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime because of order of initialization problems. -**Note**: A ``dynlib`` import can be overriden with +**Note**: A ``dynlib`` import can be overriden with the ``--dynlibOverride:name`` command line option. The Compiler User Guide contains further information. diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index cce3a8830..c6206d030 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -53,7 +53,7 @@ The following example shows a generic binary tree can be modelled: add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and add(root, newNode("world")) # ``add`` for str in inorder(root): - writeln(stdout, str) + writeLine(stdout, str) Is operator @@ -116,7 +116,7 @@ type class matches ``array`` any array type ``set`` any set type ``seq`` any seq type -``auto`` any type +``any`` any type ================== =================================================== Furthermore, every generic type automatically creates a type class of the same @@ -163,13 +163,6 @@ module to illustrate this: Alternatively, the ``distinct`` type modifier can be applied to the type class to allow each param matching the type class to bind to a different type. -If a proc param doesn't have a type specified, Nim will use the -``distinct auto`` type class (also known as ``any``): - -.. code-block:: nim - # allow any combination of param types - proc concat(a, b): string = $a & $b - Procs written with the implicitly generic style will often need to refer to the type parameters of the matched generic type. They can be easily accessed using the dot syntax: @@ -219,7 +212,7 @@ Concepts are written in the following form: (x < y) is bool Container[T] = concept c - c.len is ordinal + c.len is Ordinal items(c) is iterator for value in c: type(value) is T diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt index e2f006f04..7f81ab422 100644 --- a/doc/manual/lexing.txt +++ b/doc/manual/lexing.txt @@ -25,7 +25,7 @@ a separate token. This trick allows parsing of Nim with only 1 token of lookahead. The parser uses a stack of indentation levels: the stack consists of integers -counting the spaces. The indentation information is queried at strategic +counting the spaces. The indentation information is queried at strategic places in the parser but ignored otherwise: The pseudo terminal ``IND{>}`` denotes an indentation that consists of more spaces than the entry at the top of the stack; IND{=} an indentation that has the same number of spaces. ``DED`` @@ -36,7 +36,7 @@ With this notation we can now easily define the core of the grammar: A block of statements (simplified example):: ifStmt = 'if' expr ':' stmt - (IND{=} 'elif' expr ':' stmt)* + (IND{=} 'elif' expr ':' stmt)* (IND{=} 'else' ':' stmt)? simpleStmt = ifStmt / ... @@ -80,7 +80,7 @@ underscores ``__`` are not allowed:: digit ::= '0'..'9' IDENTIFIER ::= letter ( ['_'] (letter | digit) )* -Currently any unicode character with an ordinal value > 127 (non ASCII) is +Currently any Unicode character with an ordinal value > 127 (non ASCII) is classified as a ``letter`` and may thus be part of an identifier but later versions of the language may assign some Unicode characters to belong to the operator characters instead. @@ -101,25 +101,28 @@ Two identifiers are considered equal if the following algorithm returns true: .. code-block:: nim proc sameIdentifier(a, b: string): bool = - a[0] == b[0] and a.replace("_", "").toLower == b.replace("_", "").toLower + a[0] == b[0] and + a.replace(re"_|–", "").toLower == b.replace(re"_|–", "").toLower That means only the first letters are compared in a case sensitive manner. Other -letters are compared case insensitively and underscores are ignored. +letters are compared case insensitively and underscores and en-dash (Unicode +point U+2013) are ignored. -This rather strange way to do identifier comparisons is called +This rather unorthodox way to do identifier comparisons is called `partial case insensitivity`:idx: and has some advantages over the conventional case sensitivity: It allows programmers to mostly use their own preferred -spelling style and libraries written by different programmers cannot use -incompatible conventions. A Nim-aware editor or IDE can show the identifiers as -preferred. Another advantage is that it frees the programmer from remembering +spelling style, be it humpStyle, snake_style or dash–style and libraries written +by different programmers cannot use incompatible conventions. +A Nim-aware editor or IDE can show the identifiers as preferred. +Another advantage is that it frees the programmer from remembering the exact spelling of an identifier. The exception with respect to the first letter allows common code like ``var foo: Foo`` to be parsed unambiguously. -Historically, Nim was a `style-insensitive`:idx: language. This means that it -was not case-sensitive and underscores were ignored and there was no distinction -between ``foo`` and ``Foo``. +Historically, Nim was a fully `style-insensitive`:idx: language. This meant that +it was not case-sensitive and underscores were ignored and there was no even a +distinction between ``foo`` and ``Foo``. String literals @@ -153,7 +156,7 @@ contain the following `escape sequences`:idx:\ : ================== =================================================== -Strings in Nim may contain any 8-bit value, even embedded zeros. However +Strings in Nim may contain any 8-bit value, even embedded zeros. However some operations may interpret the first binary zero as a terminator. @@ -171,7 +174,7 @@ be whitespace between the opening ``"""`` and the newline), the newline (and the preceding whitespace) is not included in the string. The ending of the string literal is defined by the pattern ``"""[^"]``, so this: -.. code-block:: nim +.. code-block:: nim """"long string within quotes"""" Produces:: @@ -184,9 +187,9 @@ Raw string literals Terminal symbol in the grammar: ``RSTR_LIT``. -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. +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 convenient for regular expressions or Windows paths: .. code-block:: nim @@ -198,21 +201,21 @@ To produce a single ``"`` within a raw string literal, it has to be doubled: .. code-block:: nim r"a""b" - + Produces:: - + a"b -``r""""`` is not possible with this notation, because the three leading -quotes introduce a triple quoted string literal. ``r"""`` is the same -as ``"""`` since triple quoted string literals do not interpret escape +``r""""`` is not possible with this notation, because the three leading +quotes introduce a triple quoted string literal. ``r"""`` is the same +as ``"""`` since triple quoted string literals do not interpret escape sequences either. Generalized raw string literals ------------------------------- -Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, +Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, ``GENERALIZED_TRIPLESTR_LIT``. The construct ``identifier"string literal"`` (without whitespace between the @@ -276,9 +279,9 @@ Numerical constants are of a single type and have the form:: bindigit = '0'..'1' HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* DEC_LIT = digit ( ['_'] digit )* - OCT_LIT = '0o' octdigit ( ['_'] octdigit )* + OCT_LIT = '0' ('o' | 'c' | 'C') octdigit ( ['_'] octdigit )* BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* - + INT_LIT = HEX_LIT | DEC_LIT | OCT_LIT @@ -289,7 +292,7 @@ Numerical constants are of a single type and have the form:: INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32' INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64' - UINT8_LIT = INT_LIT ['\''] ('u' | 'U') + UINT_LIT = INT_LIT ['\''] ('u' | 'U') UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8' UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16' UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32' @@ -297,15 +300,17 @@ Numerical constants are of a single type and have the form:: exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent) - FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32' - FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64' + FLOAT32_SUFFIX = ('f' | 'F') ['32'] + FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX + FLOAT64_SUFFIX = ( ('f' | 'F') '64' ) | 'd' | 'D' + FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX 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`` or ``0c``) and hexadecimal (prefix ``0x``) notation. There exists a literal for each numerical type that is @@ -331,8 +336,11 @@ The type suffixes are: ``'u16`` uint16 ``'u32`` uint32 ``'u64`` uint64 + ``'f`` float32 + ``'d`` float64 ``'f32`` float32 ``'f64`` float64 + ``'f128`` float128 ================= ========================= Floating point literals may also be in binary, octal or hexadecimal @@ -340,12 +348,18 @@ notation: ``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` is approximately 1.72826e35 according to the IEEE floating point standard. +Literals are bounds checked so that they fit the datatype. Non base-10 +literals are used mainly for flags and bit pattern representations, therefore +bounds checking is done on bit width, not value range. If the literal fits in +the bit width of the datatype, it is accepted. +Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 +instead of causing an overflow error. Operators --------- -In Nim one can define his own operators. An operator is any -combination of the following characters:: +Nim allows user defined operators. An operator is any combination of the +following characters:: = + - * / < > @ $ ~ & % | @@ -355,7 +369,7 @@ These keywords are also operators: ``and or not xor shl shr div mod in notin is isnot of``. `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they -are used for other notational purposes. +are used for other notational purposes. ``*:`` is as a special case the two tokens `*`:tok: and `:`:tok: (to support ``var v*: T``). @@ -369,7 +383,7 @@ The following strings denote other tokens:: ` ( ) { } [ ] , ; [. .] {. .} (. .) -The `slice`:idx: operator `..`:tok: takes precedence over other tokens that -contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: +The `slice`:idx: operator `..`:tok: takes precedence over other tokens that +contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens `{.`:tok:, `.}`:tok:. diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt index 864eeccb5..b14c98636 100644 --- a/doc/manual/locking.txt +++ b/doc/manual/locking.txt @@ -63,7 +63,7 @@ model low level lockfree mechanisms: .. code-block:: nim var dummyLock {.compileTime.}: int var atomicCounter {.guard: dummyLock.}: int - + template atomicRead(x): expr = {.locks: [dummyLock].}: memoryReadBarrier() @@ -135,30 +135,30 @@ Lock levels are used to enforce a global locking order in order to prevent deadlocks at compile-time. A lock level is an constant integer in the range 0..1_000. Lock level 0 means that no lock is acquired at all. -If a section of code holds a lock of level ``M`` than it can also acquire any +If a section of code holds a lock of level ``M`` than it can also acquire any lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks -of the same level can only be acquired *at the same time* within a +of the same level can only be acquired *at the same time* within a single ``locks`` section: .. code-block:: nim var a, b: TLock[2] var x: TLock[1] # invalid locking order: TLock[1] cannot be acquired before TLock[2]: - {.locks: [x].}: + {.locks: [x].}: {.locks: [a].}: ... # valid locking order: TLock[2] acquired before TLock[1]: - {.locks: [a].}: + {.locks: [a].}: {.locks: [x].}: ... # invalid locking order: TLock[2] acquired before TLock[2]: - {.locks: [a].}: + {.locks: [a].}: {.locks: [b].}: ... # valid locking order, locks of the same level acquired at the same time: - {.locks: [a, b].}: + {.locks: [a, b].}: ... @@ -187,7 +187,7 @@ level. This then means that the routine may acquire locks of up to this level. This is essential so that procs can be called within a ``locks`` section: .. code-block:: nim - proc p() {.locks: 3.} = discard + proc p() {.locks: 3.} = discard var a: TLock[4] {.locks: [a].}: @@ -195,6 +195,6 @@ This is essential so that procs can be called within a ``locks`` section: p() -As usual ``locks`` is an inferred effect and there is a subtype +As usual ``locks`` is an inferred effect and there is a subtype relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` iff (M <= N). diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt index 70f6026b2..e6a08b5ce 100644 --- a/doc/manual/modules.txt +++ b/doc/manual/modules.txt @@ -81,8 +81,8 @@ A module alias can be introduced via the ``as`` keyword: echo su.format("$1", "lalelu") -The original module name is then not accessible. The -notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` +The original module name is then not accessible. The +notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` can be used to refer to a module in subdirectories: .. code-block:: nim @@ -104,7 +104,7 @@ Likewise the following does not make sense as the name is ``strutils`` already: From import statement ~~~~~~~~~~~~~~~~~~~~~ -After the ``from`` statement a module name follows followed by +After the ``from`` statement a module name follows followed by an ``import`` to list the symbols one likes to use without explict full qualification: @@ -115,8 +115,8 @@ full qualification: # always possible: full qualification: echo strutils.replace("abc", "a", "z") -It's also possible to use ``from module import nil`` if one wants to import -the module but wants to enforce fully qualified access to every symbol +It's also possible to use ``from module import nil`` if one wants to import +the module but wants to enforce fully qualified access to every symbol in ``module``. @@ -134,18 +134,26 @@ modules don't need to import a module's dependencies: # module A import B export B.MyObject - + proc `$`*(x: MyObject): string = "my object" .. code-block:: nim # module C import A - - # B.MyObject has been imported implicitly here: + + # B.MyObject has been imported implicitly here: var x: MyObject echo($x) +Note on paths +----------- +In module related statements, if any part of the module name / +path begins with a number, you may have to quote it in double quotes. +In the following example, it would be seen as a literal number '3.0' of type +'float64' if not quoted, if uncertain - quote it: +.. code-block:: nim + import "gfx/3d/somemodule" Scope rules ----------- @@ -177,9 +185,8 @@ following places: Module scope ~~~~~~~~~~~~ All identifiers of a module are valid from the point of declaration until -the end of the module. Identifiers from indirectly dependent modules are *not* -available. The `system`:idx: module is automatically imported in every other -module. +the end of the module. Identifiers from indirectly dependent modules are *not* +available. The `system`:idx: module is automatically imported in every module. 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 diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 46fd89b13..f89194c9a 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -18,9 +18,7 @@ The deprecated pragma is used to mark a symbol as deprecated: proc p() {.deprecated.} var x {.deprecated.}: char -It can also be used as a statement. Then it takes a list of *renamings*. The -upcoming ``nimfix`` tool can automatically update the code and perform these -renamings: +It can also be used as a statement, in that case it takes a list of *renamings*. .. code-block:: nim type @@ -28,6 +26,9 @@ renamings: Stream = ref object {.deprecated: [TFile: File, PStream: Stream].} +The ``nimfix`` tool can be used to, without effort, automatically update your +code and refactor it by performing these renamings. + noSideEffect pragma ------------------- @@ -54,9 +55,7 @@ destructor pragma ----------------- The ``destructor`` pragma is used to mark a proc to act as a type destructor. -Its usage is deprecated, use the ``override`` pragma instead. -See `type bound operations`_. - +Its usage is deprecated, See `type bound operations`_ instead. override pragma --------------- @@ -71,9 +70,21 @@ procedural variable. compileTime pragma ------------------ -The ``compileTime`` 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. +The ``compileTime`` pragma is used to mark a proc or variable to be used at +compile time only. No code will be generated for it. Compile time procs are +useful as helpers for macros. Since version 0.12.0 of the language, a proc +that uses ``system.NimNode`` within its parameter types is implictly declared +``compileTime``: + +.. code-block:: nim + proc astHelper(n: NimNode): NimNode = + result = n + +Is the same as: + +.. code-block:: nim + proc astHelper(n: NimNode): NimNode {.compileTime.} = + result = n noReturn pragma @@ -372,7 +383,7 @@ The ``register`` pragma is for variables only. It declares the variable as 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 +In highly specific cases (a dispatch loop of a bytecode interpreter for example) it may provide benefits, though. @@ -430,13 +441,13 @@ Example: 2. When a top level call is encountered (usually at the very end of the module), the compiler will try to determine the actual types of all of the symbols in the matching overload set. This is a potentially recursive process as the signatures - of the symbols may include other call expressions, whoose types will be resolved + of the symbols may include other call expressions, whose types will be resolved at this point too. - 3. Finally, after the best overload is picked, the compiler will start compiling - the body of the respective symbol. This in turn will lead the compiler to discover - more call expresions that need to be resolved and steps 2 and 3 will be repeated - as necessary. + 3. Finally, after the best overload is picked, the compiler will start + compiling the body of the respective symbol. This in turn will lead the + compiler to discover more call expressions that need to be resolved and steps + 2 and 3 will be repeated as necessary. Please note that if a callable symbol is never used in this scenario, its body will never be compiled. This is the default behavior leading to best compilation @@ -513,3 +524,485 @@ Example: add "foo" add "bar" + +Implementation Specific Pragmas +=============================== + +This section describes additional pragmas that the current Nim implementation +supports but which should not be seen as part of the language specification. + +Bitsize pragma +-------------- + +The ``bitsize`` pragma is for object field members. It declares the field as +a bitfield in C/C++. + +.. code-block:: Nim + type + mybitfield = object + flag {.bitsize:1.}: cuint + +generates: + +.. code-block:: C + struct mybitfield { + unsigned int flag:1; + }; + + +Volatile pragma +--------------- +The ``volatile`` pragma is for variables only. It declares the variable as +``volatile``, whatever that means in C/C++ (its semantics are not well defined +in C/C++). + +**Note**: This pragma will not exist for the LLVM backend. + + +NoDecl pragma +------------- +The ``noDecl`` pragma can be applied to almost any symbol (variable, proc, +type, etc.) and is sometimes useful for interoperability with C: +It tells Nim that it should not generate a declaration for the symbol in +the C code. For example: + +.. code-block:: Nim + var + EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as + # Nim does not know its value + +However, the ``header`` pragma is often the better alternative. + +**Note**: This will not work for the LLVM backend. + + +Header pragma +------------- +The ``header`` 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``: + +.. code-block:: Nim + type + PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer + # import C's FILE* type; Nim will treat it as a new pointer type + +The ``header`` pragma always expects a string constant. The string contant +contains the header file: As usual for C, a system header file is enclosed +in angle brackets: ``<>``. If no angle brackets are given, Nim +encloses the header file in ``""`` in the generated C code. + +**Note**: This will not work for the LLVM backend. + + +IncompleteStruct pragma +----------------------- +The ``incompleteStruct`` pragma tells the compiler to not use the +underlying C ``struct`` in a ``sizeof`` expression: + +.. code-block:: Nim + type + DIR* {.importc: "DIR", header: "<dirent.h>", + final, pure, incompleteStruct.} = object + + +Compile pragma +-------------- +The ``compile`` pragma can be used to compile and link a C/C++ source file +with the project: + +.. code-block:: Nim + {.compile: "myfile.cpp".} + +**Note**: Nim computes a SHA1 checksum and only recompiles the file if it +has changed. You can use the ``-f`` command line option to force recompilation +of the file. + + +Link pragma +----------- +The ``link`` pragma can be used to link an additional file with the project: + +.. code-block:: Nim + {.link: "myfile.o".} + + +PassC pragma +------------ +The ``passC`` pragma can be used to pass additional parameters to the C +compiler like you would using the commandline switch ``--passC``: + +.. code-block:: Nim + {.passC: "-Wall -Werror".} + +Note that you can use ``gorge`` from the `system module <system.html>`_ to +embed parameters from an external command at compile time: + +.. code-block:: Nim + {.passC: gorge("pkg-config --cflags sdl").} + +PassL pragma +------------ +The ``passL`` pragma can be used to pass additional parameters to the linker +like you would using the commandline switch ``--passL``: + +.. code-block:: Nim + {.passL: "-lSDLmain -lSDL".} + +Note that you can use ``gorge`` from the `system module <system.html>`_ to +embed parameters from an external command at compile time: + +.. code-block:: Nim + {.passL: gorge("pkg-config --libs sdl").} + + +Emit pragma +----------- +The ``emit`` pragma can be used to directly affect the output of the +compiler's code generator. So it makes your code unportable to other code +generators/backends. Its usage is highly discouraged! However, it can be +extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. + +Example: + +.. code-block:: Nim + {.emit: """ + static int cvariable = 420; + """.} + + {.push stackTrace:off.} + proc embedsC() = + var nimVar = 89 + # use backticks to access Nim symbols within an emit section: + {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} + {.pop.} + + embedsC() + +As can be seen from the example, to Nim symbols can be referred via backticks. +Use two backticks to produce a single verbatim backtick. + +For a toplevel emit statement the section where in the generated C/C++ file +the code should be emitted can be influenced via the +prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/`` or ``/*INCLUDESECTION*/``: + +.. code-block:: Nim + {.emit: """/*TYPESECTION*/ + struct Vector3 { + public: + Vector3(): x(5) {} + Vector3(float x_): x(x_) {} + float x; + }; + """.} + + type Vector3 {.importcpp: "Vector3", nodecl} = object + x: cfloat + + proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl} + + +ImportCpp pragma +---------------- + +**Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows +about the ``importcpp`` pragma pattern language. It is not necessary +to know all the details described here. + + +Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the +``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols +in general. The generated code then uses the C++ method calling +syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit`` +pragmas this allows *sloppy* interfacing with libraries written in C++: + +.. code-block:: Nim + # Horrible example of how to interface with a C++ engine ... ;-) + + {.link: "/usr/lib/libIrrlicht.so".} + + {.emit: """ + using namespace irr; + using namespace core; + using namespace scene; + using namespace video; + using namespace io; + using namespace gui; + """.} + + const + irr = "<irrlicht/irrlicht.h>" + + type + IrrlichtDeviceObj {.final, header: irr, + importcpp: "IrrlichtDevice".} = object + IrrlichtDevice = ptr IrrlichtDeviceObj + + proc createDevice(): IrrlichtDevice {. + header: irr, importcpp: "createDevice(@)".} + proc run(device: IrrlichtDevice): bool {. + header: irr, importcpp: "#.run(@)".} + +The compiler needs to be told to generate C++ (command ``cpp``) for +this to work. The conditional symbol ``cpp`` is defined when the compiler +emits C++ code. + + +Namespaces +~~~~~~~~~~ + +The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace`` +declarations. It is usually much better to instead refer to the imported name +via the ``namespace::identifier`` notation: + +.. code-block:: nim + type + IrrlichtDeviceObj {.final, header: irr, + importcpp: "irr::IrrlichtDevice".} = object + + +Importcpp for enums +~~~~~~~~~~~~~~~~~~~ + +When ``importcpp`` is applied to an enum type the numerical enum values are +annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``. +(This turned out to be the simplest way to implement it.) + + +Importcpp for procs +~~~~~~~~~~~~~~~~~~~ + +Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern +language for maximum flexibility: + +- A hash ``#`` symbol is replaced by the first or next argument. +- A dot following the hash ``#.`` indicates that the call should use C++'s dot + or arrow notation. +- An at symbol ``@`` is replaced by the remaining arguments, separated by + commas. + +For example: + +.. code-block:: nim + proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".} + var x: ptr CppObj + cppMethod(x[], 1, 2, 3) + +Produces: + +.. code-block:: C + x->CppMethod(1, 2, 3) + +As a special rule to keep backwards compatibility with older versions of the +``importcpp`` pragma, if there is no special pattern +character (any of ``# ' @``) at all, C++'s +dot or arrow notation is assumed, so the above example can also be written as: + +.. code-block:: nim + proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".} + +Note that the pattern language naturally also covers C++'s operator overloading +capabilities: + +.. code-block:: nim + proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".} + proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".} + + +- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9 + is replaced by the i'th parameter *type*. The 0th position is the result + type. This can be used to pass types to C++ function templates. Between + the ``'`` and the digit an asterisk can be used to get to the base type + of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.) + Two stars can be used to get to the element type of the element type etc. + +For example: + +.. code-block:: nim + + type Input {.importcpp: "System::Input".} = object + proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.} + + let x: ptr Input = getSubsystem[Input]() + +Produces: + +.. code-block:: C + x = SystemManager::getSubsystem<System::Input>() + + +- ``#@`` is a special case to support a ``cnew`` operation. It is required so + that the call expression is inlined directly, without going through a + temporary location. This is only required to circumvent a limitation of the + current code generator. + +For example C++'s ``new`` operator can be "imported" like this: + +.. code-block:: nim + proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.} + + # constructor of 'Foo': + proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".} + + let x = cnew constructFoo(3, 4) + +Produces: + +.. code-block:: C + x = new Foo(3, 4) + +However, depending on the use case ``new Foo`` can also be wrapped like this +instead: + +.. code-block:: nim + proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".} + + let x = newFoo(3, 4) + + +Wrapping constructors +~~~~~~~~~~~~~~~~~~~~~ + +Sometimes a C++ class has a private copy constructor and so code like +``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``. +For this purpose the Nim proc that wraps a C++ constructor needs to be +annotated with the `constructor`:idx: pragma. This pragma also helps to generate +faster C++ code since construction then doesn't invoke the copy constructor: + +.. code-block:: nim + # a better constructor of 'Foo': + proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.} + + +Wrapping destructors +~~~~~~~~~~~~~~~~~~~~ + +Since Nim generates C++ directly, any destructor is called implicitly by the +C++ compiler at the scope exits. This means that often one can get away with +not wrapping the destructor at all! However when it needs to be invoked +explicitly, it needs to be wrapped. But the pattern language already provides +everything that is required for that: + +.. code-block:: nim + proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".} + + +Importcpp for objects +~~~~~~~~~~~~~~~~~~~~~ + +Generic ``importcpp``'ed objects are mapped to C++ templates. This means that +you can import C++'s templates rather easily without the need for a pattern +language for object types: + +.. code-block:: nim + type + StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object + proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. + importcpp: "#[#] = #", header: "<map>".} + + var x: StdMap[cint, cdouble] + x[6] = 91.4 + + +Produces: + +.. code-block:: C + std::map<int, double> x; + x[6] = 91.4; + + +- If more precise control is needed, the apostrophe ``'`` can be used in the + supplied pattern to denote the concrete type parameters of the generic type. + See the usage of the apostrophe operator in proc patterns for more details. + +.. code-block:: nim + + type + VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object + + var x: VectorIterator[cint] + + +Produces: + +.. code-block:: C + + std::vector<int>::iterator x; + + +ImportObjC pragma +----------------- +Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the +``importobjc`` pragma can be used to import `Objective C`:idx: methods. The +generated code then uses the Objective C method calling syntax: ``[obj method +param1: arg]``. In addition with the ``header`` and ``emit`` pragmas this +allows *sloppy* interfacing with libraries written in Objective C: + +.. code-block:: Nim + # horrible example of how to interface with GNUStep ... + + {.passL: "-lobjc".} + {.emit: """ + #include <objc/Object.h> + @interface Greeter:Object + { + } + + - (void)greet:(long)x y:(long)dummy; + @end + + #include <stdio.h> + @implementation Greeter + + - (void)greet:(long)x y:(long)dummy + { + printf("Hello, World!\n"); + } + @end + + #include <stdlib.h> + """.} + + type + Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int + + proc newGreeter: Id {.importobjc: "Greeter new", nodecl.} + proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.} + proc free(self: Id) {.importobjc: "free", nodecl.} + + var g = newGreeter() + g.greet(12, 34) + g.free() + +The compiler needs to be told to generate Objective C (command ``objc``) for +this to work. The conditional symbol ``objc`` is defined when the compiler +emits Objective C code. + + +CodegenDecl pragma +------------------ + +The ``codegenDecl`` pragma can be used to directly influence Nim's code +generator. It receives a format string that determines how the variable or +proc is declared in the generated code: + +.. code-block:: nim + var + a {.codegenDecl: "$# progmem $#".}: int + + proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} = + echo "realistic interrupt handler" + + +InjectStmt pragma +----------------- + +The ``injectStmt`` pragma can be used to inject a statement before every +other statement in the current module. It is only supposed to be used for +debugging: + +.. code-block:: nim + {.injectStmt: gcInvariants().} + + # ... complex code here that produces crashes ... + diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index 9de984ecf..ee74b2ea6 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -2,17 +2,46 @@ Procedures ========== What most programming languages call `methods`:idx: or `functions`:idx: are -called `procedures`:idx: in Nim (which is the correct terminology). A -procedure declaration defines an identifier and associates it with a block -of code. -A procedure may call itself recursively. A parameter may be given a default -value that is used if the caller does not provide a value for this parameter. - -If the proc declaration has no body, it is a `forward`:idx: declaration. If -the proc returns a value, the procedure body can access an implicitly declared +called `procedures`:idx: in Nim (which is the correct terminology). A procedure +declaration consists of an identifier, zero or more formal parameters, a return +value type and a block of code. Formal parameters are declared as a list of +identifiers separated by either comma or semicolon. A parameter is given a type +by ``: typename``. The type applies to all parameters immediately before it, +until either the beginning of the parameter list, a semicolon separator or an +already typed parameter, is reached. The semicolon can be used to make +separation of types and subsequent identifiers more distinct. + +.. code-block:: nim + # Using only commas + proc foo(a, b: int, c, d: bool): int + + # Using semicolon for visual distinction + proc foo(a, b: int; c, d: bool): int + + # Will fail: a is untyped since ';' stops type propagation. + proc foo(a; b: int; c, d: bool): int + +A parameter may be declared with a default value which is used if the caller +does not provide a value for the argument. + +.. code-block:: nim + # b is optional with 47 as its default value + proc foo(a: int, b: int = 47): int + +Parameters can be declared mutable and so allow the proc to modify those +arguments, by using the type modifier `var`. + +.. code-block:: nim + # "returning" a value to the caller through the 2nd argument + # Notice that the function uses no actual return value at all (ie void) + proc foo(inp: int, outp: var int) = + outp = inp + 47 + +If the proc declaration has no body, it is a `forward`:idx: declaration. If the +proc returns a value, the procedure body can access an implicitly declared variable named `result`:idx: that represents the return value. Procs can be -overloaded. The overloading resolution algorithm tries to find the proc that is -the best match for the arguments. Example: +overloaded. The overloading resolution algorithm determines which proc is the +best match for the arguments. Example: .. code-block:: nim @@ -41,9 +70,8 @@ Calling a procedure can be done in many different ways: # call as a command statement: no () needed: callme 0, 1, "abc", '\t' +A procedure may call itself recursively. -A procedure cannot modify its parameters (unless the parameters have the type -`var`). `Operators`:idx: are procedures with a special operator symbol as identifier: @@ -92,7 +120,7 @@ current module: Method call syntax ------------------ -For object oriented programming, the syntax ``obj.method(args)`` can be used +For object oriented programming, the syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``. The parentheses can be omitted if there are no remaining arguments: ``obj.len`` (instead of ``len(obj)``). @@ -100,26 +128,34 @@ This method call syntax is not restricted to objects, it can be used to supply any type of first argument for procedures: .. code-block:: nim - + echo("abc".len) # is the same as echo(len("abc")) echo("abc".toUpper()) echo({'a', 'b', 'c'}.card) - stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo") + stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo") Another way to look at the method call syntax is that it provides the missing postfix notation. +The method call syntax conflicts with explicit generic instantiations: +``p[T](x)`` cannot be written as ``x.p[T]`` because ``x.p[T]`` is always +parsed as ``(x.p)[T]``. + +**Future directions**: ``p[.T.]`` might be introduced as an alternative syntax +to pass explict types to a generic and then ``x.p[.T.]`` can be parsed as +``x.(p[.T.])``. + See also: `Limitations of the method call syntax`_. Properties ---------- Nim 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 +with the *method call syntax* achieve the same. But setting a value is different; for this a special setter syntax is needed: .. code-block:: nim - + type Socket* = ref object of RootObj FHost: int # cannot be accessed from the outside of the module @@ -129,7 +165,7 @@ different; for this a special setter syntax is needed: proc `host=`*(s: var Socket, value: int) {.inline.} = ## setter of hostAddr s.FHost = value - + proc host*(s: Socket): int {.inline.} = ## getter of hostAddr s.FHost @@ -152,18 +188,18 @@ more argument in this case: .. code-block:: nim proc optarg(x: int, y: int = 0): int = x + y proc singlearg(x: int): int = 20*x - + echo optarg 1, " ", singlearg 2 # prints "1 40" - + let fail = optarg 1, optarg 8 # Wrong. Too many arguments for a command call let x = optarg(1, optarg 8) # traditional procedure call with 2 arguments let y = 1.optarg optarg 8 # same thing as above, w/o the parenthesis assert x == y -The command invocation syntax also can't have complex expressions as arguments. -For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do -notation`_) is limited, but usable for a single proc (see the example in the -corresponding section). Function calls with no arguments still needs () to +The command invocation syntax also can't have complex expressions as arguments. +For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do +notation`_) is limited, but usable for a single proc (see the example in the +corresponding section). Function calls with no arguments still needs () to distinguish between a call and the function itself as a first class value. @@ -193,7 +229,7 @@ the proc's name. cmp(x.len, y.len)) -Procs as expressions can appear both as nested procs and inside top level +Procs as expressions can appear both as nested procs and inside top level executable code. @@ -209,10 +245,10 @@ calls can use the ``do`` keyword: sort(cities) do (x,y: string) -> int: cmp(x.len, y.len) # Less parenthesis using the method plus command syntax: - cities = cities.map do (x:string) -> string: + cities = cities.map do (x:string) -> string: "City of " & x -``do`` is written after the parentheses enclosing the regular proc params. +``do`` is written after the parentheses enclosing the regular proc params. The proc expression represented by the do block is appended to them. More than one ``do`` block can appear in a single call: @@ -233,11 +269,11 @@ Nonoverloadable builtins The following builtin procs cannot be overloaded for reasons of implementation simplicity (they require specialized semantic checking):: - declared, defined, definedInScope, compiles, low, high, sizeOf, + declared, defined, definedInScope, compiles, low, high, sizeOf, is, of, shallowCopy, getAst, astToStr, spawn, procCall -Thus they act more like keywords than like ordinary identifiers; unlike a -keyword however, a redefinition may `shadow`:idx: the definition in +Thus they act more like keywords than like ordinary identifiers; unlike a +keyword however, a redefinition may `shadow`:idx: the definition in the ``system`` module. From this list the following should not be written in dot notation ``x.f`` since ``x`` cannot be type checked before it gets passed to ``f``:: @@ -314,11 +350,11 @@ returned value is an l-value and can be modified by the caller: proc WriteAccessToG(): var int = result = g - + WriteAccessToG() = 6 assert g == 6 -It is a compile time error if the implicitly introduced pointer could be +It is a compile time error if the implicitly introduced pointer could be used to access a location beyond its lifetime: .. code-block:: nim @@ -326,7 +362,7 @@ used to access a location beyond its lifetime: var g = 0 result = g # Error! -For iterators, a component of a tuple return type can have a ``var`` type too: +For iterators, a component of a tuple return type can have a ``var`` type too: .. code-block:: nim iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] = @@ -356,32 +392,37 @@ dispatch. x: int PlusExpr = ref object of Expression a, b: Expression - - method eval(e: Expression): int = + + method eval(e: Expression): int {.base.} = # override this base method quit "to override!" - + method eval(e: Literal): int = return e.x - + method eval(e: PlusExpr): int = # watch out: relies on dynamic binding result = eval(e.a) + eval(e.b) - + proc newLit(x: int): Literal = new(result) result.x = x - + proc newPlus(a, b: Expression): PlusExpr = new(result) result.a = a result.b = b -echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) - + echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) + In the example the constructors ``newLit`` and ``newPlus`` are procs because they should use static binding, but ``eval`` is a method because it requires dynamic binding. +As can be seen in the example, base methods have to be annotated with +the `base`:idx: pragma. The ``base`` pragma also acts as a reminder for the +programmer that a base method ``m`` is used as the foundation to determine all +the effects that a call to ``m`` might cause. + In a multi-method all parameters that have an object type are used for the dispatching: @@ -390,24 +431,24 @@ dispatching: Thing = ref object of RootObj Unit = ref object of Thing x: int - - method collide(a, b: Thing) {.inline.} = + + method collide(a, b: Thing) {.base, inline.} = quit "to override!" - + method collide(a: Thing, b: Unit) {.inline.} = echo "1" - + method collide(a: Unit, b: Thing) {.inline.} = echo "2" - + var a, b: Unit new a new b collide(a, b) # output: 2 -Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over -collide 1 because the resolution works from left to right. +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 ``Unit, Thing`` is preferred over ``Thing, Unit``. **Performance note**: Nim does not produce a virtual method table, but @@ -422,7 +463,7 @@ Iterators and the for statement 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 left with a ``break`` statement. +can be left with a ``break`` statement. The ``for`` loop declares iteration variables - their scope reaches until the end of the loop body. The iteration variables' types are inferred by the @@ -458,7 +499,7 @@ The compiler generates code as if the programmer would have written this: If the iterator yields a tuple, there can be as many iteration variables as there are components in the tuple. The i'th iteration variable's type is -the type of the i'th component. In other words, implicit tuple unpacking in a +the type of the i'th component. In other words, implicit tuple unpacking in a for loop context is supported. Implict items/pairs invocations @@ -470,12 +511,12 @@ ie. an ``items`` iterator is implicitly invoked: .. code-block:: nim for x in [1,2,3]: echo x - + If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly invoked. -Symbol lookup of the identifiers ``items``/``pairs`` is performed after -the rewriting step, so that all overloadings of ``items``/``pairs`` are taken +Symbol lookup of the identifiers ``items``/``pairs`` is performed after +the rewriting step, so that all overloads of ``items``/``pairs`` are taken into account. @@ -483,7 +524,7 @@ First class iterators --------------------- There are 2 kinds of iterators in Nim: *inline* and *closure* iterators. -An `inline iterator`:idx: is an iterator that's always inlined by the compiler +An `inline iterator`:idx: is an iterator that's always inlined by the compiler leading to zero overhead for the abstraction, but may result in a heavy increase in code size. Inline iterators are second class citizens; They can be passed as parameters only to other inlining code facilities like @@ -494,7 +535,7 @@ In contrast to that, a `closure iterator`:idx: can be passed around more freely: .. code-block:: nim iterator count0(): int {.closure.} = yield 0 - + iterator count2(): int {.closure.} = var x = 1 yield x @@ -511,14 +552,15 @@ Closure iterators have other restrictions than inline iterators: 1. ``yield`` in a closure iterator can not occur in a ``try`` statement. 2. For now, a closure iterator cannot be evaluated at compile time. -3. ``return`` is allowed in a closure iterator (but rarely useful). -4. Both inline and closure iterators cannot be recursive. +3. ``return`` is allowed in a closure iterator (but rarely useful) and ends + iteration. +4. Neither inline nor closure iterators can be recursive. Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly -default to being inline, but that this may change in future versions of the +default to being inline, but this may change in future versions of the implementation. -The ``iterator`` type is always of the calling convention ``closure`` +The ``iterator`` type is always of the calling convention ``closure`` implicitly; the following example shows how to use iterators to implement a `collaborative tasking`:idx: system: @@ -612,8 +654,8 @@ parameters of an outer factory proc: Implicit return type -------------------- - Since inline interators must always produce values that will be consumed in - a for loop, the compiler will implicity use the ``auto`` return type if no + Since inline iterators must always produce values that will be consumed in + a for loop, the compiler will implicitly use the ``auto`` return type if no type is given by the user. In contrast, since closure iterators can be used as a collaborative tasking system, ``void`` is a valid return type for them. @@ -621,7 +663,7 @@ parameters of an outer factory proc: Converters ========== -A converter is like an ordinary proc except that it enhances +A converter is like an ordinary proc except that it enhances the "implicitly convertible" type relation (see `Convertible relation`_): .. code-block:: nim diff --git a/doc/manual/special_ops.txt b/doc/manual/special_ops.txt index 46135f129..702693423 100644 --- a/doc/manual/special_ops.txt +++ b/doc/manual/special_ops.txt @@ -34,7 +34,7 @@ templates and macros), depending on the desired effect: The following dot operators are available: operator `.` ------------- +------------ This operator will be matched against both field accesses and method calls. operator `.()` diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 5b1284872..a833d7b7d 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -2,7 +2,7 @@ Statements and expressions ========================== Nim uses the common statement/expression paradigm: Statements do not -produce a value in contrast to expressions. However, some expressions are +produce a value in contrast to expressions. However, some expressions are statements. Statements are separated into `simple statements`:idx: and @@ -10,15 +10,15 @@ Statements are separated into `simple statements`:idx: and Simple statements are statements that cannot contain other statements like assignments, calls or the ``return`` statement; complex statements can contain other statements. To avoid the `dangling else problem`:idx:, complex -statements always have to be intended. The details can be found in the grammar. +statements always have to be indented. The details can be found in the grammar. Statement list expression ------------------------- -Statements can also occur in an expression context that looks +Statements can also occur in an expression context that looks like ``(stmt1; stmt2; ...; ex)``. This is called -an statement list expression or ``(;)``. The type +an statement list expression or ``(;)``. The type of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.) ``(;)`` does not introduce a new scope. @@ -30,24 +30,24 @@ Discard statement Example: .. code-block:: nim - proc p(x, y: int): int = + proc p(x, y: int): int = result = x + y discard p(3, 4) # discard the return value of `p` The ``discard`` statement evaluates its expression for side-effects and -throws the expression's resulting value away. +throws the expression's resulting value away. Ignoring the return value of a procedure without using a discard statement is a static error. The return value can be ignored implicitly if the called proc/iterator has -been declared with the `discardable`:idx: pragma: +been declared with the `discardable`:idx: pragma: .. code-block:: nim - proc p(x, y: int): int {.discardable.} = + proc p(x, y: int): int {.discardable.} = result = x + y - + p(3, 4) # now valid An empty ``discard`` statement is often used as a null statement: @@ -60,6 +60,24 @@ An empty ``discard`` statement is often used as a null statement: else: discard +Void context +------------ + +In a list of statements every expression except the last one needs to have the +type ``void``. In addition to this rule an assignment to the builtin ``result`` +symbol also triggers a ``void`` context: + +.. code-block:: nim + proc invalid*(): string = + result = "foo" + "invalid" # Error: value of type 'string' has to be discarded + +.. code-block:: nim + proc valid*(): string = + let x = 317 + "valid" + + Var statement ------------- @@ -98,11 +116,11 @@ T = enum cast[T](0); this may be an invalid value The implicit initialization can be avoided for optimization reasons with the -`noinit`:idx: pragma: +`noinit`:idx: pragma: .. code-block:: nim var - a {.noInit.}: array [0..1023, char] + a {.noInit.}: array [0..1023, char] If a proc is annotated with the ``noinit`` pragma this refers to its implicit ``result`` variable: @@ -113,13 +131,13 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit The implicit initialization can be also prevented by the `requiresInit`:idx: type pragma. The compiler requires an explicit initialization then. However -it does a `control flow analysis`:idx: to prove the variable has been +it does a `control flow analysis`:idx: to prove the variable has been initialized and does not rely on syntactic properties: .. code-block:: nim type MyObject = object {.requiresInit.} - + proc p() = # the following is valid: var x: MyObject @@ -129,11 +147,12 @@ initialized and does not rely on syntactic properties: x = a() use x + let statement ------------- A ``let`` statement declares new local and global `single assignment`:idx: -variables and binds a value to them. The syntax is the same as that of the ``var`` +variables and binds a value to them. The syntax is the same as that of the ``var`` statement, except that the keyword ``var`` is replaced by the keyword ``let``. Let variables are not l-values and can thus not be passed to ``var`` parameters nor can their address be taken. They cannot be assigned new values. @@ -141,6 +160,19 @@ nor can their address be taken. They cannot be assigned new values. For let variables the same pragmas are available as for ordinary variables. +Tuple unpacking +--------------- + +In a ``var`` or ``let`` statement tuple unpacking can be performed. The special +identifier ``_`` can be used to ignore some parts of the tuple: + +.. code-block:: nim + proc returnsTuple(): (int, int, int) = (4, 2, 3) + + let (x, _, z) = returnsTuple() + + + Const section ------------- @@ -157,33 +189,33 @@ have no side-effect can be used in constant expressions too: constEval = contains("abc", 'b') # computed at compile time! -The rules for compile-time computability are: +The rules for compile-time computability are: 1. Literals are compile-time computable. 2. Type conversions are compile-time computable. 3. Procedure calls of the form ``p(X)`` are compile-time computable if - ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ - for details) and if ``X`` is a (possibly empty) list of compile-time - computable arguments. + ``p`` is a proc without side-effects (see the `noSideEffect pragma + <#pragmas-nosideeffect-pragma>`_ for details) and if ``X`` is a + (possibly empty) list of compile-time computable arguments. -Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can +Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can they contain such a type. Static statement/expression --------------------------- -A static statement/expression can be used to enforce compile +A static statement/expression can be used to enforce compile time evaluation explicitly. Enforced compile time evaluation can even evaluate -code that has side effects: +code that has side effects: .. code-block:: static: echo "echo at compile time" -It's a static error if the compiler cannot perform the evaluation at compile +It's a static error if the compiler cannot perform the evaluation at compile time. The current implementation poses some restrictions for compile time @@ -215,22 +247,18 @@ the expression after the ``elif`` is evaluated (if there is an ``elif`` branch), if it is true the corresponding statements after the ``:`` are executed. This goes on until the last ``elif``. If all conditions fail, the ``else`` part is executed. If there is no ``else`` -part, execution continues with the statement after the ``if`` statement. +part, execution continues with the next statement. -The scoping for an ``if`` statement is slightly subtle to support an important -use case. A new scope starts for the ``if``/``elif`` condition and ends after -the corresponding *then* block: +In ``if`` statements new scopes begin immediately after the ``if``/``elif``/``else`` keywords and ends after the corresponding *then* block. +For visualization purposes the scopes have been enclosed in ``{| |}`` in the following example: .. code-block:: nim if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch): echo "key ", m[0], " value ", m[1] |} elif {| (let m = input =~ re""; m.isMatch): - echo "new m in this scope" |} - else: - # 'm' not declared here - -In the example the scopes have been enclosed in ``{| |}``. - + echo "new m in this scope" |} + else: {| + echo "m not declared here" |} Case statement -------------- @@ -244,7 +272,7 @@ Example: echo("permission denied") of "go-for-a-walk": echo("please yourself") else: echo("unknown command") - + # indentation of the branches is also allowed; and so is an optional colon # after the selecting expression: case readline(stdin): @@ -252,15 +280,15 @@ Example: echo("permission denied") of "go-for-a-walk": echo("please yourself") else: echo("unknown command") - + The ``case`` statement is similar to the if statement, but it represents a multi-branch selection. The expression after the keyword ``case`` is evaluated and if its value is in a *slicelist* the corresponding statements (after the ``of`` keyword) are executed. If the value is not in any given *slicelist* the ``else`` part is executed. If there is no ``else`` -part and not all possible values that ``expr`` can hold occur in a -``slicelist``, a static error occurs. This holds only for expressions of +part and not all possible values that ``expr`` can hold occur in a +``slicelist``, a static error occurs. This holds only for expressions of ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s type. To suppress the static error an ``else`` part with an empty ``discard`` statement should be used. @@ -281,7 +309,7 @@ expanded into a list of its elements: of SymChars, '_': echo "an identifier" of '0'..'9': echo "a number" else: echo "other" - + # is equivalent to: proc classify(s: string) = case s[0] @@ -320,6 +348,37 @@ a special syntactic extension, the ``when`` construct is also available within ``object`` definitions. +When nimvm statement +-------------------- + +``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` +statement to differentiate execution path between runtime and compile time. + +Example: + +.. code-block:: nim + proc someProcThatMayRunInCompileTime(): bool = + when nimvm: + # This code runs in compile time + result = true + else: + # This code runs in runtime + result = false + const ctValue = someProcThatMayRunInCompileTime() + let rtValue = someProcThatMayRunInCompileTime() + assert(ctValue == true) + assert(rtValue == false) + +``when nimvm`` statement must meet the following requirements: + +* Its expression must always be ``nimvm``. More complex expressions are not + allowed. +* It must not contain ``elif`` branches. +* It must contain ``else`` branch. +* Code in branches must not affect semantics of the code that follows the + ``when nimvm`` statement. E.g. it must not define symbols that are used in + the following code. + Return statement ---------------- @@ -580,14 +639,14 @@ A table constructor is syntactic sugar for an array constructor: .. code-block:: nim {"key1": "value1", "key2", "key3": "value2"} - + # is the same as: [("key1", "value1"), ("key2", "value2"), ("key3", "value2")] -The empty table can be written ``{:}`` (in contrast to the empty set +The empty table can be written ``{:}`` (in contrast to the empty set which is ``{}``) which is thus another way to write as the empty array -constructor ``[]``. This slightly unusal way of supporting tables +constructor ``[]``. This slightly unusual way of supporting tables has lots of advantages: * The order of the (key,value)-pairs is preserved, thus it is easy to diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index cf44eb588..c444a3995 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -15,17 +15,22 @@ Associativity Binary operators whose first character is ``^`` are right-associative, all other binary operators are left-associative. -Operators ending in ``>`` but longer than a single character are -called `arrow like`:idx:. - +.. code-block:: nim + proc `^/`(x, y: float): float = + # a right-associative division operator + result = x / y + echo 12 ^/ 4 ^/ 8 # 24.0 (4 / 8 = 0.5, then + 12 / 0.5 = 24.0) + echo 12 / 4 / 8 # 0.375 (12 / 4 = 3.0, then + 3 / 8 = 0.375) Precedence ---------- -Unary operators always bind stronger than any binary +Unary operators always bind stronger than any binary operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``. -If an unary operator's first character is ``@`` it is a `sigil-like`:idx: +If an unary operator's first character is ``@`` it is a `sigil-like`:idx: operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. @@ -33,9 +38,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. For binary operators that are not keywords the precedence is determined by the following rules: -If the operator ends with ``=`` and its first character is none of +Operators ending in either ``->``, ``~>`` or ``=>`` are called +`arrow like`:idx:, and have the lowest precedence of all operators. + +If the operator ends with ``=`` and its first character is none of ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which -has the lowest precedence. +has the second lowest precedence. Otherwise precedence is determined by the first character. @@ -43,14 +51,14 @@ Otherwise precedence is determined by the first character. Precedence level Operators First character Terminal symbol ================ =============================================== ================== =============== 10 (highest) ``$ ^`` OP10 - 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 - 8 ``+ -`` ``+ ~ |`` OP8 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ - ~ |`` OP8 7 ``&`` ``&`` OP7 6 ``..`` ``.`` OP6 - 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 + 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 4 ``and`` OP4 3 ``or xor`` OP3 - 2 ``@ : ?`` OP2 + 2 ``@ : ?`` OP2 1 *assignment operator* (like ``+=``, ``*=``) OP1 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 ================ =============================================== ================== =============== @@ -60,14 +68,14 @@ Strong spaces ------------- The number of spaces preceding a non-keyword operator affects precedence -if the experimental parser directive ``#!strongSpaces`` is used. Indentation +if the experimental parser directive ``#?strongSpaces`` is used. Indentation is not used to determine the number of spaces. If 2 or more operators have the same number of preceding spaces the precedence table applies, so ``1 + 3 * 4`` is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: .. code-block:: nim - #! strongSpaces - if foo+4 * 4 == 8 and b&c | 9 ++ + #? strongSpaces + if foo+4 * 4 == 8 and b&c | 9 ++ bar: echo "" # is parsed as @@ -75,10 +83,10 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: Furthermore whether an operator is used a prefix operator is affected by the -number of spaces: +number of spaces: .. code-block:: nim - #! strongSpaces + #? strongSpaces echo $foo # is parsed as echo($foo) @@ -87,7 +95,7 @@ This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors or as accessors: .. code-block:: nim - #! strongSpaces + #? strongSpaces echo (1,2) # is parsed as echo((1,2)) diff --git a/doc/manual/taint.txt b/doc/manual/taint.txt index 84f0c68b1..492686f31 100644 --- a/doc/manual/taint.txt +++ b/doc/manual/taint.txt @@ -1,11 +1,11 @@ Taint mode ========== -The Nim compiler and most parts of the standard library support -a taint mode. Input strings are declared with the `TaintedString`:idx: +The Nim compiler and most parts of the standard library support +a taint mode. Input strings are declared with the `TaintedString`:idx: string type declared in the ``system`` module. -If the taint mode is turned on (via the ``--taintMode:on`` command line +If the taint mode is turned on (via the ``--taintMode:on`` command line option) it is a distinct string type which helps to detect input validation errors: @@ -13,7 +13,7 @@ validation errors: echo "your name: " var name: TaintedString = stdin.readline # it is safe here to output the name without any input validation, so - # we simply convert `name` to string to make the compiler happy: + # we simply convert `name` to string to make the compiler happy: echo "hi, ", name.string If the taint mode is turned off, ``TaintedString`` is simply an alias for diff --git a/doc/manual/templates.txt b/doc/manual/templates.txt index eeb907ce0..092d65ea2 100644 --- a/doc/manual/templates.txt +++ b/doc/manual/templates.txt @@ -16,17 +16,17 @@ Example: assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact +The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact templates: | ``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. -The "types" of templates can be the symbols ``expr`` (stands for *expression*), -``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type -description*). These are "meta types", they can only be used in certain -contexts. Real types can be used too; this implies that expressions are +The "types" of templates can be the symbols ``expr`` (stands for *expression*), +``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type +description*). These are "meta types", they can only be used in certain +contexts. Real types can be used too; this implies that expressions are expected. @@ -40,7 +40,7 @@ So ordinary templates cannot receive undeclared identifiers: .. code-block:: nim - template declareInt(x: expr) = + template declareInt(x: expr) = var x: int declareInt(x) # error: unknown identifier: 'x' @@ -51,7 +51,7 @@ receive undeclared identifiers: .. code-block:: nim - template declareInt(x: expr) {.immediate.} = + template declareInt(x: expr) {.immediate.} = var x: int declareInt(x) # valid @@ -75,12 +75,12 @@ special ``:`` syntax: 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`` + txt.writeLine("line 1") + txt.writeLine("line 2") + +In the example the two ``writeLine`` statements are bound to the ``actions`` parameter. @@ -92,9 +92,9 @@ bound from the definition scope of the template: .. code-block:: nim # Module A - var + var lastId = 0 - + template genId*: expr = inc(lastId) lastId @@ -102,10 +102,10 @@ bound from the definition scope of the template: .. code-block:: nim # Module B import A - + echo genId() # Works as 'lastId' has been bound in 'genId's defining scope -As in generics symbol binding can be influenced via ``mixin`` or ``bind`` +As in generics symbol binding can be influenced via ``mixin`` or ``bind`` statements. @@ -117,11 +117,11 @@ In templates identifiers can be constructed with the backticks notation: .. code-block:: nim - template typedef(name: expr, typ: typedesc) {.immediate.} = + template typedef(name: expr, typ: typedesc) {.immediate.} = type `T name`* {.inject.} = typ `P name`* {.inject.} = ref `T name` - + typedef(myint, int) var x: PMyInt @@ -150,7 +150,7 @@ shadowed by the same argument name even when fully qualified: tstLev(levA) # produces: 'levA levA' - + But the global symbol can properly be captured by a ``bind`` statement: .. code-block:: nim @@ -177,14 +177,14 @@ Per default templates are `hygienic`:idx:\: Local identifiers declared in a template cannot be accessed in the instantiation context: .. code-block:: nim - + template newException*(exceptn: typedesc, message: string): expr = var e: ref exceptn # e is implicitly gensym'ed here new(e) e.msg = message e - + # so this works: let e = "message" raise newException(EIO, e) @@ -196,7 +196,7 @@ symbols are not exposed but inject'ed are. The default for symbols of entity ``type``, ``var``, ``let`` and ``const`` is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``, -``macro`` is ``inject``. However, if the name of the entity is passed as a +``macro`` is ``inject``. However, if the name of the entity is passed as a template parameter, it is an inject'ed symbol: .. code-block:: nim @@ -204,10 +204,10 @@ template parameter, it is an inject'ed symbol: block: var f: File # since 'f' is a template param, it's injected implicitly ... - + withFile(txt, "ttempl3.txt", fmWrite): - txt.writeln("line 1") - txt.writeln("line 2") + txt.writeLine("line 1") + txt.writeLine("line 2") The ``inject`` and ``gensym`` pragmas are second class annotations; they have @@ -215,7 +215,7 @@ no semantics outside of a template definition and cannot be abstracted over: .. code-block:: nim {.pragma myInject: inject.} - + template t() = var x {.myInject.}: int # does NOT work @@ -299,7 +299,7 @@ variable number of arguments: # add a call to the statement list that writes ": " add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) # add a call to the statement list that writes the expressions value: - add(result, newCall("writeln", newIdentNode("stdout"), n[i])) + add(result, newCall("writeLine", newIdentNode("stdout"), n[i])) var a: array [0..10, int] @@ -314,15 +314,15 @@ The macro call expands to: .. code-block:: nim write(stdout, "a[0]") write(stdout, ": ") - writeln(stdout, a[0]) + writeLine(stdout, a[0]) write(stdout, "a[1]") write(stdout, ": ") - writeln(stdout, a[1]) + writeLine(stdout, a[1]) write(stdout, "x") write(stdout, ": ") - writeln(stdout, x) + writeLine(stdout, x) Arguments that are passed to a ``varargs`` parameter are wrapped in an array @@ -333,10 +333,10 @@ children. BindSym ------- -The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and -``stdout`` are declared in the system module and thus visible in the +The above ``debug`` macro relies on the fact that ``write``, ``writeLine`` and +``stdout`` are declared in the system module and thus visible in the instantiating context. There is a way to use bound identifiers -(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` +(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` builtin can be used for that: .. code-block:: nim @@ -348,7 +348,7 @@ builtin can be used for that: # we can bind symbols in scope via 'bindSym': add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i]))) add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": "))) - add(result, newCall(bindSym"writeln", bindSym"stdout", n[i])) + add(result, newCall(bindSym"writeLine", bindSym"stdout", n[i])) var a: array [0..10, int] @@ -363,17 +363,17 @@ The macro call expands to: .. code-block:: nim write(stdout, "a[0]") write(stdout, ": ") - writeln(stdout, a[0]) + writeLine(stdout, a[0]) write(stdout, "a[1]") write(stdout, ": ") - writeln(stdout, a[1]) + writeLine(stdout, a[1]) write(stdout, "x") write(stdout, ": ") - writeln(stdout, x) + writeLine(stdout, x) -However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound +However, the symbols ``write``, ``writeLine`` and ``stdout`` are already bound and are not looked up again. As the example shows, ``bindSym`` does work with overloaded symbols implicitly. @@ -418,8 +418,8 @@ powerful programming construct that still suffices. So the "check list" is: Macros as pragmas ----------------- -Whole routines (procs, iterators etc.) can also be passed to a template or -a macro via the pragma notation: +Whole routines (procs, iterators etc.) can also be passed to a template or +a macro via the pragma notation: .. code-block:: nim template m(s: stmt) = discard diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt index fc3040c87..f2b79a34f 100644 --- a/doc/manual/threads.txt +++ b/doc/manual/threads.txt @@ -37,7 +37,7 @@ that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either directly or indirectly through a call to a GC unsafe proc. The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, -otherwise this property is inferred by the compiler. Note that ``noSideEfect`` +otherwise this property is inferred by the compiler. Note that ``noSideEffect`` implies ``gcsafe``. The only way to create a thread is via ``spawn`` or ``createThead``. ``spawn`` is usually the preferable method. Either way the invoked proc must not use ``var`` parameters nor must any of its parameters @@ -146,7 +146,7 @@ wait on multiple flow variables at the same time: # wait until 2 out of 3 servers received the update: proc main = - var responses = newSeq[RawFlowVar](3) + var responses = newSeq[FlowVarBase](3) for i in 0..2: responses[i] = spawn tellServer(Update, "key", "value") var index = awaitAny(responses) diff --git a/doc/manual/trmacros.txt b/doc/manual/trmacros.txt index 90d01e475..446896e28 100644 --- a/doc/manual/trmacros.txt +++ b/doc/manual/trmacros.txt @@ -3,32 +3,32 @@ Term rewriting macros Term rewriting macros are macros or templates that have not only a *name* but also a *pattern* that is searched for after the semantic checking -phase of the compiler: This means they provide an easy way to enhance the +phase of the compiler: This means they provide an easy way to enhance the compilation pipeline with user defined optimizations: .. code-block:: nim template optMul{`*`(a, 2)}(a: int): int = a+a - + let x = 3 echo x * 2 The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the curlies is the pattern to match against. The operators ``*``, ``**``, -``|``, ``~`` have a special meaning in patterns if they are written in infix +``|``, ``~`` have a special meaning in patterns if they are written in infix notation, so to match verbatim against ``*`` the ordinary function call syntax needs to be used. Unfortunately optimizations are hard to get right and even the tiny example -is **wrong**: +is **wrong**: .. code-block:: nim template optMul{`*`(a, 2)}(a: int): int = a+a - + proc f(): int = echo "side effect!" result = 55 - + echo f() * 2 We cannot duplicate 'a' if it denotes an expression that has a side effect! @@ -36,26 +36,30 @@ Fortunately Nim supports side effect analysis: .. code-block:: nim template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a - + proc f(): int = echo "side effect!" result = 55 - + echo f() * 2 # not optimized ;-) +You can make one overload matching with a constraint and one without, and the +one with a constraint will have precedence, and so you can handle both cases +differently. + So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We cannot really do that however as the following code only swaps arguments blindly: .. code-block:: nim template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a - + What optimizers really need to do is a *canonicalization*: .. code-block:: nim template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a -The ``int{lit}`` parameter pattern matches against an expression of +The ``int{lit}`` parameter pattern matches against an expression of type ``int``, but only if it's a literal. @@ -63,7 +67,7 @@ type ``int``, but only if it's a literal. Parameter constraints --------------------- -The `parameter constraint`:idx: expression can use the operators ``|`` (or), +The `parameter constraint`:idx: expression can use the operators ``|`` (or), ``&`` (and) and ``~`` (not) and the following predicates: =================== ===================================================== @@ -71,7 +75,7 @@ Predicate Meaning =================== ===================================================== ``atom`` The matching node has no children. ``lit`` The matching node is a literal like "abc", 12. -``sym`` The matching node must be a symbol (a bound +``sym`` The matching node must be a symbol (a bound identifier). ``ident`` The matching node must be an identifier (an unbound identifier). @@ -97,16 +101,18 @@ Predicate Meaning ``enumfield`` A symbol which is a field in an enumeration. ``forvar`` A for loop variable. ``label`` A label (used in ``block`` statements). -``nk*`` The matching AST must have the specified kind. +``nk*`` The matching AST must have the specified kind. (Example: ``nkIfStmt`` denotes an ``if`` statement.) -``alias`` States that the marked parameter needs to alias +``alias`` States that the marked parameter needs to alias with *some* other parameter. ``noalias`` States that *every* other parameter must not alias with the marked parameter. =================== ===================================================== +Predicates that share their name with a keyword have to be escaped with +backticks: `` `const` ``. The ``alias`` and ``noalias`` predicates refer not only to the matching AST, -but also to every other bound parameter; syntactially they need to occur after +but also to every other bound parameter; syntactically they need to occur after the ordinary AST predicates: .. code-block:: nim @@ -144,15 +150,15 @@ constant folding, so the following does not work: The reason is that the compiler already transformed the 1 into "1" for the ``echo`` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactived with the ``--patterns:off`` -command line option or temporarily with the ``patterns`` pragma. +semantics anyway. In fact they can be deactivated with the ``--patterns:off`` +command line option or temporarily with the ``patterns`` pragma. The ``{}`` operator ~~~~~~~~~~~~~~~~~~~ A pattern expression can be bound to a pattern parameter via the ``expr{param}`` -notation: +notation: .. code-block:: nim template t{(0|1|2){x}}(x: expr): expr = x+1 @@ -170,7 +176,7 @@ The ``~`` operator is the **not** operator in patterns: template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt = x = y if x: x = z - + var a = false b = true @@ -183,12 +189,12 @@ The ``*`` operator ~~~~~~~~~~~~~~~~~~ The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` -to ``&(a, b, c)``: +to ``&(a, b, c)``: .. code-block:: nim var calls = 0 - + proc `&&`(s: varargs[string]): string = result = s[0] for i in 1..len(s)-1: result.add s[i] @@ -205,8 +211,8 @@ to ``&(a, b, c)``: The second operator of `*` must be a parameter; it is used to gather all the arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"`` -is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) -which is flattened into a call expression; thus the invocation of ``optConc`` +is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) +which is flattened into a call expression; thus the invocation of ``optConc`` produces: .. code-block:: nim @@ -239,7 +245,7 @@ all the arguments, but also the matched operators in reverse polish notation: var x, y, z: Matrix - echo x + y * z - x + echo x + y * z - x This passes the expression ``x + y * z - x`` to the ``optM`` macro as an ``nnkArgList`` node containing:: @@ -259,17 +265,17 @@ an ``nnkArgList`` node containing:: Parameters ---------- -Parameters in a pattern are type checked in the matching process. If a +Parameters in a pattern are type checked in the matching process. If a parameter is of the type ``varargs`` it is treated specially and it can match 0 or more arguments in the AST to be matched against: .. code-block:: nim template optWrite{ write(f, x) - ((write|writeln){w})(f, y) + ((write|writeLine){w})(f, y) }(x, y: varargs[expr], f: File, w: expr) = w(f, x, y) - + Example: Partial evaluation @@ -304,7 +310,7 @@ The following example shows how some form of hoisting can be implemented: The ``optPeg`` template optimizes the case of a peg constructor with a string literal, so that the pattern will only be parsed once at program startup and -stored in a global ``gl`` which is then re-used. This optimization is called +stored in a global ``gl`` which is then re-used. This optimization is called hoisting because it is comparable to classical loop hoisting. @@ -337,7 +343,7 @@ ordinary routines. Move optimization ----------------- -The ``call`` constraint is particularly useful to implement a move +The ``call`` constraint is particularly useful to implement a move optimization for types that have copying semantics: .. code-block:: nim @@ -345,15 +351,15 @@ optimization for types that have copying semantics: ## puts a (key, value)-pair into `t`. The semantics of string require ## a copy here: let idx = findInsertionPosition(key) - t[idx] = key - t[idx] = val + t[idx].key = key + t[idx].val = val proc `[]=`*(t: var Table, key: string{call}, val: string{call}) = ## puts a (key, value)-pair into `t`. Optimized version that knows that ## the strings are unique and thus don't need to be copied: let idx = findInsertionPosition(key) - shallowCopy t[idx], key - shallowCopy t[idx], val + shallowCopy t[idx].key, key + shallowCopy t[idx].val, val var t: Table # overloading resolution ensures that the optimized []= is called here: diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt index 59d55a6cd..c707979fe 100644 --- a/doc/manual/type_bound_ops.txt +++ b/doc/manual/type_bound_ops.txt @@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type. operator `=` ------------ -This operator is the assignment operator. Note that in the contexts -like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for -parameter passing no assignment is performed. The ``override`` pragma is -optional for overriding ``=``. +This operator is the assignment operator. Note that in the contexts +``result = expr``, ``parameter = defaultValue`` or for +parameter passing no assignment is performed. For a type ``T`` that has an +overloaded assignment operator ``var v = T()`` is rewritten +to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count +as assignments. + +The assignment operator needs to be attached to an object or distinct +type ``T``. Its signature has to be ``(var T, T)``. Example: + +.. code-block:: nim + type + Concrete = object + a, b: string + + proc `=`(d: var Concrete; src: Concrete) = + shallowCopy(d.a, src.a) + shallowCopy(d.b, src.b) + echo "Concrete '=' called" + + var x, y: array[0..2, Concrete] + var cA, cB: Concrete + + var cATup, cBTup: tuple[x: int, ha: Concrete] + + x = y + cA = cB + cATup = cBTup -**Note**: Overriding of operator ``=`` is not yet implemented. destructors ----------- A destructor must have a single parameter with a concrete type (the name of a -generic type is allowed too). The name of the destructor has to be ``destroy`` -and it need to be annotated with the ``override`` pragma. +generic type is allowed too). The name of the destructor has to be ``=destroy``. -``destroy(v)`` will be automatically invoked for every local stack +``=destroy(v)`` will be automatically invoked for every local stack variable ``v`` that goes out of scope. -If a structured type features a field with destructable type and +If a structured type features a field with destructable type and the user has not provided an explicit implementation, a destructor for the -structured type will be automatically generated. Calls to any base class +structured type will be automatically generated. Calls to any base class destructors in both user-defined and generated destructors will be inserted. A destructor is attached to the type it destructs; expressions of this type @@ -52,13 +74,13 @@ can then only be used in *destructible contexts* and as parameters: MyObj = object x, y: int p: pointer - - proc destroy(o: var MyObj) {.override.} = + + proc `=destroy`(o: var MyObj) = if o.p != nil: dealloc o.p - + proc open: MyObj = result = MyObj(x: 1, y: 2, p: alloc(3)) - + proc work(o: MyObj) = echo o.x # No destructor invoked here for 'o' as 'o' is a parameter. @@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters: var x = open() # valid: pass 'x' to some other proc: work(x) - + # Error: usage of a type with a destructor in a non destructible context echo open() @@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve the support of destructors. Be aware that destructors are not called for objects allocated with ``new``. -This may change in future versions of language, but for now the ``finalizer`` +This may change in future versions of language, but for now the `finalizer`:idx: parameter to ``new`` has to be used. **Note**: Destructors are still experimental and the spec might change @@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis. deepCopy -------- -``deepCopy`` is a builtin that is invoked whenever data is passed to +``=deepCopy`` is a builtin that is invoked whenever data is passed to a ``spawn``'ed proc to ensure memory safety. The programmer can override its behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the language may weaken this restriction.) @@ -103,10 +125,10 @@ language may weaken this restriction.) The signature has to be: .. code-block:: nim - proc deepCopy(x: T): T {.override.} + proc `=deepCopy`(x: T): T -This mechanism is used by most data structures that support shared memory like -channels to implement thread safe automatic memory management. +This mechanism will be used by most data structures that support shared memory +like channels to implement thread safe automatic memory management. The builtin ``deepCopy`` can even clone closures and their environments. See the documentation of `spawn`_ for details. diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt index d1593a02e..434d6b030 100644 --- a/doc/manual/type_rel.txt +++ b/doc/manual/type_rel.txt @@ -9,11 +9,11 @@ Type equality ------------- Nim uses structural type equivalence for most types. Only for objects, enumerations and distinct types name equivalence is used. The following -algorithm (in pseudo-code) determines type equality: +algorithm, *in pseudo-code*, determines type equality: .. code-block:: nim proc typeEqualsAux(a, b: PType, - s: var set[PType * PType]): bool = + s: var HashSet[(PType, PType)]): bool = if (a,b) in s: return true incl(s, (a,b)) if a.kind == b.kind: @@ -43,7 +43,7 @@ algorithm (in pseudo-code) determines type equality: a.callingConvention == b.callingConvention proc typeEquals(a, b: PType): bool = - var s: set[PType * PType] = {} + var s: HashSet[(PType, PType)] = {} result = typeEqualsAux(a, b, s) Since types are graphs which can have cycles, the above algorithm needs an @@ -294,6 +294,21 @@ If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary type checking, the argument is checked to be an `l-value`:idx:. ``var T`` matches better than just ``T`` then. +.. code-block:: nim + proc sayHi(x: int): string = + # matches a non-var int + result = $x + proc sayHi(x: var int): string = + # matches a var int + result = $(x + 10) + + proc sayHello(x: int) = + var m = x # a mutable version of x + echo sayHi(x) # matches the non-var version of sayHi + echo sayHi(m) # matches the var version of sayHi + + sayHello(3) # 3 + # 13 Automatic dereferencing ----------------------- diff --git a/doc/manual/type_sections.txt b/doc/manual/type_sections.txt index 8420a0098..34bbe6bd5 100644 --- a/doc/manual/type_sections.txt +++ b/doc/manual/type_sections.txt @@ -18,6 +18,6 @@ Example: A type section begins with the ``type`` keyword. It contains multiple type definitions. A type definition binds a type to a name. Type definitions can be recursive or even mutually recursive. Mutually recursive types are only -possible within a single ``type`` section. Nominal types like ``objects`` +possible within a single ``type`` section. Nominal types like ``objects`` or ``enums`` can only be defined in a ``type`` section. diff --git a/doc/manual/types.txt b/doc/manual/types.txt index e9d33045b..babf3286f 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -342,6 +342,34 @@ builtin ``len`` procedure; the length never counts the terminating zero. The assignment operator for strings always copies the string. The ``&`` operator concatenates strings. +Most native Nim types support conversion to strings with the special ``$`` proc. +When calling the ``echo`` proc, for example, the built-in stringify operation +for the parameter is called: + +.. code-block:: nim + + echo 3 # calls `$` for `int` + +Whenever a user creates a specialized object, implementation of this procedure +provides for ``string`` representation. + +.. code-block:: nim + type + Person = object + name: string + age: int + + proc `$`(p: Person): string = # `$` always returns a string + result = p.name & " is " & + $p.age & # we *need* the `$` in front of p.age, which + # is natively an integer, to convert it to + # a string + " years old." + +While ``$p.name`` can also be used, the ``$`` operation on a string does +nothing. Note that we cannot rely on automatic conversion from an ``int`` to +a ``string`` like we can for the ``echo`` proc. + Strings are compared by their lexicographical order. All comparison operators are available. Strings can be indexed like arrays (lower bound is 0). Unlike arrays, they can be used in case statements: @@ -462,6 +490,11 @@ to an open array parameter. The openarray type cannot be nested: multidimensional openarrays are not supported because this is seldom needed and cannot be done efficiently. +.. code-block:: nim + proc testOpenArray(x: openArray[int]) = echo repr(x) + + testOpenArray([1,2,3]) # array[] + testOpenArray(@[1,2,3]) # seq[] Varargs ------- @@ -560,11 +593,12 @@ can also be defined with indentation instead of ``[]``: Objects provide many features that tuples do not. Object provide inheritance and information hiding. Objects have access to their type at runtime, so that -the ``of`` operator can be used to determine the object's type. +the ``of`` operator can be used to determine the object's type. The ``of`` operator +is similar to the ``instanceof`` operator in Java. .. code-block:: nim type - Person {.inheritable.} = object + Person = object of RootObj name*: string # the * means that `name` is accessible from other modules age: int # no * means that the field is hidden @@ -575,6 +609,7 @@ the ``of`` operator can be used to determine the object's type. student: Student person: Person assert(student of Student) # is true + assert(student of Person) # also true Object fields that should be visible from outside the defining module, have to be marked by ``*``. In contrast to tuples, different object types are @@ -593,6 +628,7 @@ an ``object`` type or a ``ref object`` type: .. code-block:: nim var student = Student(name: "Anton", age: 5, id: 3) +Note that, unlike tuples, objects require the field names along with their values. For a ``ref object`` type ``system.new`` is invoked implicitly. @@ -803,7 +839,7 @@ exclude ``nil`` as a valid value with the ``not nil`` annotation: p(x) The compiler ensures that every code path initializes variables which contain -not nilable pointers. The details of this analysis are still to be specified +non nilable pointers. The details of this analysis are still to be specified here. @@ -864,7 +900,9 @@ Future directions: * Builtin regions like ``private``, ``global`` and ``local`` will prove very useful for the upcoming OpenCL target. * Builtin "regions" can model ``lent`` and ``unique`` pointers. - +* An assignment operator can be attached to a region so that proper write + barriers can be generated. This would imply that the GC can be implemented + completely in user-space. Procedural type @@ -961,7 +999,7 @@ 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: 1) The procedure that is accessed resides in the current module. -2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_). +2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma <#pragmas-procvar-pragma>`_). 3) The procedure has a calling convention that differs from ``nimcall``. 4) The procedure is anonymous. @@ -1130,7 +1168,7 @@ that don't. Distinct types provide a means to introduce a new string type It is an essential property of abstract types that they **do not** imply a -subtype relation between the abtract type and its base type. Explict type +subtype relation between the abstract type and its base type. Explicit type conversions from ``string`` to ``SQL`` are allowed: .. code-block:: nim @@ -1195,3 +1233,27 @@ However, a ``void`` type cannot be inferred in generic code: The ``void`` type is only valid for parameters and return types; other symbols cannot have the type ``void``. + + +Auto type +--------- + +The ``auto`` type can only be used for return types and parameters. For return +types it causes the compiler to infer the type from the routine body: + +.. code-block:: nim + proc returnsInt(): auto = 1984 + +For parameters it currently creates implicitly generic routines: + +.. code-block:: nim + proc foo(a, b: auto) = discard + +Is the same as: + +.. code-block:: nim + proc foo[T1, T2](a: T1, b: T2) = discard + +However later versions of the language might change this to mean "infer the +parameters' types from the body". Then the above ``foo`` would be rejected as +the parameters' types can not be infered from an empty ``discard`` statement. |