diff --git a/doc/backends.md b/doc/backends.md index 8d49af119794b..4f8a2bffff35b 100644 --- a/doc/backends.md +++ b/doc/backends.md @@ -155,8 +155,7 @@ To wrap native code, take a look at the `c2nim tool 127 (non-ASCII) is classified as a `letter` and may thus be part of an identifier but later @@ -275,8 +281,8 @@ operator characters instead. The following keywords are reserved and cannot be used as identifiers: -.. code-block:: nim - :file: keywords.txt + ```nim file="keywords.txt" + ``` Some keywords are unused; they are reserved for future developments of the language. @@ -287,10 +293,11 @@ Identifier equality Two identifiers are considered equal if the following algorithm returns true: -.. code-block:: nim + ```nim proc sameIdentifier(a, b: string): bool = a[0] == b[0] and a.replace("_", "").toLowerAscii == b.replace("_", "").toLowerAscii + ``` That means only the first letters are compared in a case-sensitive manner. Other letters are compared case-insensitively within the ASCII range and underscores are ignored. @@ -323,10 +330,11 @@ If a keyword is enclosed in backticks it loses its keyword property and becomes Examples -.. code-block:: nim + ```nim var `var` = "Hello Stropping" + ``` -.. code-block:: nim + ```nim type Obj = object `type`: int @@ -340,6 +348,7 @@ Examples const `assert` = true assert `assert` + ``` String literals @@ -396,8 +405,9 @@ 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 + ```nim """"long string within quotes"""" + ``` Produces:: @@ -414,15 +424,15 @@ 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 - + ```nim var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab + ``` To produce a single `"` within a raw string literal, it has to be doubled: -.. code-block:: nim - + ```nim r"a""b" + ``` Produces:: @@ -563,24 +573,24 @@ cover most cases in a natural manner. In the following examples, `-1` is a single token: -.. code-block:: nim - + ```nim echo -1 echo(-1) echo [-1] echo 3,-1 "abc";-1 + ``` In the following examples, `-1` is parsed as two separate tokens (as `-`:tok: `1`:tok:): -.. code-block:: nim - + ```nim echo x-1 echo (int)-1 echo [a]-1 "abc"-1 + ``` The suffix starting with an apostrophe ('\'') is called a @@ -625,16 +635,14 @@ Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 instead of causing an overflow error. -Custom numeric literals -~~~~~~~~~~~~~~~~~~~~~~~ +### Custom numeric literals If the suffix is not predefined, then the suffix is assumed to be a call to a proc, template, macro or other callable identifier that is passed the string containing the literal. The callable identifier needs to be declared with a special ``'`` prefix: -.. code-block:: nim - + ```nim import strutils type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" proc `'u4`(n: string): u4 = @@ -642,20 +650,21 @@ with a special ``'`` prefix: result = (parseInt(n) and 0x0F).u4 var x = 5'u4 + ``` More formally, a custom numeric literal `123'custom` is transformed to r"123".`'custom` in the parsing step. There is no AST node kind that corresponds to this transformation. The transformation naturally handles the case that additional parameters are passed to the callee: -.. code-block:: nim - + ```nim import strutils type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" proc `'u4`(n: string; moreData: int): u4 = result = (parseInt(n) and 0x0F).u4 var x = 5'u4(123) + ``` Custom numeric literals are covered by the grammar rule named `CUSTOM_NUMERIC_LIT`. A custom numeric literal is a single token. @@ -717,12 +726,13 @@ Associativity Binary operators whose first character is `^` are right-associative, all other binary operators are left-associative. -.. code-block:: nim + ```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 ---------- @@ -768,19 +778,20 @@ Precedence level Operators First Whether an operator is used as a prefix operator is also affected by preceding whitespace (this parsing change was introduced with version 0.13.0): -.. code-block:: nim + ```nim echo $foo # is parsed as echo($foo) + ``` Spacing also determines whether `(a, b)` is parsed as an argument list of a call or whether it is parsed as a tuple constructor: -.. code-block:: nim + ```nim echo(1, 2) # pass 1 and 2 to echo -.. code-block:: nim + ```nim echo (1, 2) # pass the tuple (1, 2) to echo Dot-like operators @@ -808,9 +819,7 @@ Order of evaluation Order of evaluation is strictly left-to-right, inside-out as it is typical for most others imperative programming languages: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" var s = "" proc p(arg: int): int = @@ -820,14 +829,13 @@ imperative programming languages: discard p(p(1) + p(2)) doAssert s == "123" + ``` Assignments are not special, the left-hand-side expression is evaluated before the right-hand side: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" var v = 0 proc getI(): int = result = v @@ -845,6 +853,7 @@ right-hand side: someCopy(b[getI()], getI()) doAssert b == [1, 0, 0] + ``` Rationale: Consistency with overloaded assignment or assignment-like operations, @@ -855,9 +864,7 @@ However, the concept of "order of evaluation" is only applicable after the code was normalized: The normalization involves template expansions and argument reorderings that have been passed to named parameters: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" var s = "" proc p(): int = @@ -884,6 +891,7 @@ reorderings that have been passed to named parameters: construct(second = q(), first = p()) doAssert s == "qppqpq" + ``` Rationale: This is far easier to implement than hypothetical alternatives. @@ -920,8 +928,7 @@ of the Fibonacci series **at compile-time**. (This is a demonstration of flexibility in defining constants, not a recommended style for solving this problem.) -.. code-block:: nim - :test: "nim c $1" + ```nim test = "nim c $1" import std/strformat var fibN {.compileTime.}: int @@ -949,6 +956,7 @@ problem.) static: echo displayFib + ``` Restrictions on Compile-Time Execution @@ -1077,12 +1085,13 @@ example `int32 -> int16`). A `widening type conversion`:idx: converts a smaller type to a larger type (for example `int16 -> int32`). In Nim only widening type conversions are *implicit*: -.. code-block:: nim + ```nim var myInt16 = 5i16 var myInt: int myInt16 + 34 # of type `int16` myInt16 + myInt # of type `int` myInt16 + 2i32 # of type `int32` + ``` However, `int` literals are implicitly convertible to a smaller integer type if the literal's value fits this smaller type and such a conversion is less @@ -1099,11 +1108,12 @@ A subrange type is a range of values from an ordinal or floating-point type (the type). To define a subrange type, one must specify its limiting values -- the lowest and highest value of the type. For example: -.. code-block:: nim + ```nim type Subrange = range[0..5] PositiveFloat = range[0.0..Inf] Positive* = range[1..high(int)] # as defined in `system` + ``` `Subrange` is a subrange of an integer which can only hold the values 0 @@ -1163,12 +1173,13 @@ These exceptions inherit from the `FloatingPointDefect`:idx: base class. Nim provides the pragmas `nanChecks`:idx: and `infChecks`:idx: to control whether the IEEE exceptions are ignored or trap a Nim exception: -.. code-block:: nim + ```nim {.nanChecks: on, infChecks: on.} var a = 1.0 var b = 0.0 echo b / b # raises FloatInvalidOpDefect echo a / b # raises FloatOverflowDefect + ``` In the current implementation `FloatDivByZeroDefect` and `FloatInexactDefect` are never raised. `FloatOverflowDefect` is raised instead of @@ -1200,11 +1211,11 @@ The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined for the bool type. The `and` and `or` operators perform short-cut evaluation. Example: -.. code-block:: nim - + ```nim while p != nil and p.name != "xyz": # p.name is not evaluated if p == nil p = p.next + ``` The size of the bool type is one byte. @@ -1226,11 +1237,11 @@ Enumeration types Enumeration types define a new type whose values consist of the ones specified. The values are ordered. Example: -.. code-block:: nim - + ```nim type Direction = enum north, east, south, west + ``` Now the following holds:: @@ -1254,10 +1265,11 @@ explicitly given is assigned the value of the previous field + 1. An explicit ordered enum can have *holes*: -.. code-block:: nim + ```nim type TokenType = enum a = 2, b = 4, c = 89 # holes are valid + ``` However, it is then not ordinal anymore, so it is impossible to use these enums as an index type for arrays. The procedures `inc`, `dec`, `succ` @@ -1268,14 +1280,14 @@ The compiler supports the built-in stringify operator `$` for enumerations. The stringify's result can be controlled by explicitly giving the string values to use: -.. code-block:: nim - + ```nim type MyEnum = enum valueA = (0, "my value A"), valueB = "value B", valueC = 2, valueD = (3, "abc") + ``` As can be seen from the example, it is possible to both specify a field's ordinal value and its string value by using a tuple. It is also @@ -1287,14 +1299,14 @@ as the last attempt. Only non-ambiguous symbols are added to this scope. But one can always access these via type qualification written as `MyEnum.value`: -.. code-block:: nim - + ```nim type MyEnum {.pure.} = enum valueA, valueB, valueC, valueD, amb OtherEnum {.pure.} = enum valueX, valueY, valueZ, amb + ``` echo valueA # MyEnum.valueA @@ -1322,14 +1334,14 @@ 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 - + ```nim echo 3 # calls `$` for `int` + ``` Whenever a user creates a specialized object, implementation of this procedure provides for `string` representation. -.. code-block:: nim + ```nim type Person = object name: string @@ -1341,6 +1353,7 @@ provides for `string` representation. # 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 @@ -1350,12 +1363,12 @@ 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: -.. code-block:: nim - + ```nim case paramStr(i) of "-v": incl(options, optVerbose) of "-h", "-?": incl(options, optHelp) else: write(stdout, "invalid command line option!\n") + ``` Per convention, all strings are UTF-8 strings, but this is not enforced. For example, when reading strings from binary files, they are merely a sequence of @@ -1379,11 +1392,12 @@ A Nim `string` is implicitly convertible to `cstring` for convenience. If a Nim string is passed to a C-style variadic proc, it is implicitly converted to `cstring` too: -.. code-block:: nim + ```nim proc printf(formatstr: cstring) {.importc: "printf", varargs, header: "".} printf("This works %s", "as expected") + ``` Even though the conversion is implicit, it is not *safe*: The garbage collector does not consider a `cstring` to be a root and may collect the underlying @@ -1394,24 +1408,27 @@ to `cstring` are safe and will remain to be allowed. A `$` proc is defined for cstrings that returns a string. Thus to get a nim string from a cstring: -.. code-block:: nim + ```nim var str: string = "Hello!" var cstr: cstring = str var newstr: string = $cstr + ``` `cstring` literals shouldn't be modified. -.. code-block:: nim + ```nim var x = cstring"literals" x[1] = 'A' # This is wrong!!! + ``` If the `cstring` originates from a regular memory (not read-only memory), it can be modified: -.. code-block:: nim + ```nim var x = "123456" var s: cstring = x s[0] = 'u' # This is ok + ``` Structured types ---------------- @@ -1445,8 +1462,7 @@ A sequence may be passed to a parameter that is of type *open array*. Example: -.. code-block:: nim - + ```nim type IntArray = array[0..5, int] # an array that is indexed with 0..5 IntSeq = seq[int] # a sequence of integers @@ -1457,6 +1473,7 @@ Example: y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence let z = [1.0, 2, 3, 4] # the type of z is array[0..3, float] + ``` The lower bound of an array or sequence may be received by the built-in proc `low()`, the higher bound by `high()`. The length may be @@ -1474,8 +1491,7 @@ checks can be disabled via pragmas or invoking the compiler with the An array constructor can have explicit indexes for readability: -.. code-block:: nim - + ```nim type Values = enum valA, valB, valC @@ -1486,12 +1502,12 @@ An array constructor can have explicit indexes for readability: valB: "B", valC: "C" ] + ``` If an index is left out, `succ(lastIndex)` is used as the index value: -.. code-block:: nim - + ```nim type Values = enum valA, valB, valC, valD, valE @@ -1503,6 +1519,7 @@ value: valC: "C", "D", "e" ] + ``` @@ -1521,11 +1538,12 @@ 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 + ```nim proc testOpenArray(x: openArray[int]) = echo repr(x) testOpenArray([1,2,3]) # array[] testOpenArray(@[1,2,3]) # seq[] + ``` Varargs ------- @@ -1534,7 +1552,7 @@ A `varargs` parameter is an openarray parameter that additionally allows to pass a variable number of arguments to a procedure. The compiler converts the list of arguments to an array implicitly: -.. code-block:: nim + ```nim proc myWriteln(f: File, a: varargs[string]) = for s in items(a): write(f, s) @@ -1543,12 +1561,13 @@ converts the list of arguments to an array implicitly: myWriteln(stdout, "abc", "def", "xyz") # is transformed to: myWriteln(stdout, ["abc", "def", "xyz"]) + ``` This transformation is only done if the varargs parameter is the last parameter in the procedure header. It is also possible to perform type conversions in this context: -.. code-block:: nim + ```nim proc myWriteln(f: File, a: varargs[string, `$`]) = for s in items(a): write(f, s) @@ -1557,6 +1576,7 @@ type conversions in this context: myWriteln(stdout, 123, "abc", 4.0) # is transformed to: myWriteln(stdout, [$123, $"abc", $4.0]) + ``` In this example `$` is applied to any argument that is passed to the parameter `a`. (Note that `$` applied to strings is a nop.) @@ -1564,21 +1584,23 @@ parameter `a`. (Note that `$` applied to strings is a nop.) Note that an explicit array constructor passed to a `varargs` parameter is not wrapped in another implicit array construction: -.. code-block:: nim + ```nim proc takeV[T](a: varargs[T]) = discard takeV([123, 2, 1]) # takeV's T is "int", not "array of int" + ``` `varargs[typed]` is treated specially: It matches a variable list of arguments of arbitrary type but *always* constructs an implicit array. This is required so that the builtin `echo` proc does what is expected: -.. code-block:: nim + ```nim proc echo*(x: varargs[typed, `$`]) {...} echo @[1, 2, 3] # prints "@[1, 2, 3]" and not "123" + ``` Unchecked arrays @@ -1588,20 +1610,22 @@ 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 + ```nim type MySeq = object len, cap: int data: UncheckedArray[int] + ``` Produces roughly this C code: -.. code-block:: C + ```C typedef struct { NI len; NI cap; NI data[]; } MySeq; + ``` The base type of the unchecked array may not contain any GC'ed memory but this is currently not checked. @@ -1624,8 +1648,7 @@ must match the order of the tuple's definition. Different tuple-types are *equivalent* if they specify the same fields of the same type in the same order. The *names* of the fields also have to be the same. -.. code-block:: nim - + ```nim type Person = tuple[name: string, age: int] # type representing a person: # it consists of a name and an age. @@ -1638,15 +1661,17 @@ order. The *names* of the fields also have to be the same. assert Person is (string, int) assert (string, int) is Person assert Person isnot tuple[other: string, age: int] # `other` is a different identifier + ``` A tuple with one unnamed field can be constructed with the parentheses and a trailing comma: -.. code-block:: nim + ```nim proc echoUnaryTuple(a: (int,)) = echo a[0] echoUnaryTuple (1,) + ``` In fact, a trailing comma is allowed for every tuple construction. @@ -1657,11 +1682,12 @@ is compatible with the way the C compiler does it. For consistency with `object` declarations, tuples in a `type` section can also be defined with indentation instead of `[]`: -.. code-block:: nim + ```nim type Person = tuple # type representing a person name: string # a person consists of a name age: Natural # and an age + ``` Objects provide many features that tuples do not. Objects provide inheritance and the ability to hide fields from other modules. Objects with inheritance @@ -1669,7 +1695,7 @@ enabled have information about their type at runtime so that 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 + ```nim type Person = object of RootObj name*: string # the * means that `name` is accessible from other modules @@ -1683,6 +1709,7 @@ the `instanceof` operator in Java. 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 @@ -1691,7 +1718,7 @@ Objects that have no ancestor are implicitly `final` and thus have no hidden type information. One can use the `inheritable` pragma to introduce new object roots apart from `system.RootObj`. -.. code-block:: nim + ```nim type Person = object # example of a final object name*: string @@ -1699,6 +1726,7 @@ introduce new object roots apart from `system.RootObj`. Student = ref object of Person # Error: inheritance only works with non-final objects id: int + ``` The assignment operator for tuples and objects copies each component. The methods to override this copying behavior are described `here @@ -1712,7 +1740,7 @@ Objects can also be created with an `object construction expression`:idx: that has the syntax `T(fieldA: valueA, fieldB: valueB, ...)` where `T` is an `object` type or a `ref object` type: -.. code-block:: nim + ```nim type Student = object name: string @@ -1724,6 +1752,7 @@ an `object` type or a `ref object` type: var a3 = (ref Student)(name: "Anton", age: 5) # not all fields need to be mentioned, and they can be mentioned out of order: var a4 = Student(age: 5) + ``` Note that, unlike tuples, objects require the field names along with their values. For a `ref object` type `system.new` is invoked implicitly. @@ -1738,8 +1767,7 @@ enumerated type used for runtime type flexibility, mirroring the concepts of An example: -.. code-block:: nim - + ```nim # This is an example of how an abstract syntax tree could be modelled in Nim type NodeKind = enum # the different node types @@ -1776,6 +1804,7 @@ An example: rightOp: Node(kind: nkInt, intVal: 2)) # valid: does not change the active object branch: x.kind = nkSub + ``` As can be seen from the example, an advantage to an object hierarchy is that no casting between different object types is needed. Yet, access to invalid @@ -1793,12 +1822,12 @@ corresponding discriminator value must be specified as a constant expression. Instead of changing the active object branch, replace the old object in memory with a new one completely: -.. code-block:: nim - + ```nim var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4), rightOp: Node(kind: nkInt, intVal: 2)) # change the node's contents: x[] = NodeObj(kind: nkString, strVal: "abc") + ``` Starting with version 0.20 `system.reset` cannot be used anymore to support @@ -1815,8 +1844,7 @@ valid for the chosen object branch. A small example: -.. code-block:: nim - + ```nim let unknownKind = nkSub # invalid: unsafe initialization because the kind field is not statically known: @@ -1833,6 +1861,7 @@ A small example: # also valid, since unknownKindBounded can only contain the values nkAdd or nkSub let unknownKindBounded = range[nkAdd..nkSub](unknownKind) z = Node(kind: unknownKindBounded, leftOp: Node(), rightOp: Node()) + ``` cast uncheckedAssign @@ -1840,9 +1869,7 @@ cast uncheckedAssign Some restrictions for case objects can be disabled via a `{.cast(uncheckedAssign).}` section: -.. code-block:: nim - :test: "nim c $1" - + ```nim test="nim c $1" type TokenKind* = enum strLit, intLit @@ -1867,6 +1894,7 @@ Some restrictions for case objects can be disabled via a `{.cast(uncheckedAssign # inside the 'cast' section it is allowed to assign to the 't.kind' field directly: t.kind = intLit + ``` Set type @@ -1900,8 +1928,7 @@ The `.` (access a tuple/object field operator) and `[]` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: -.. code-block:: nim - + ```nim type Node = ref NodeObj NodeObj = object @@ -1913,6 +1940,7 @@ dereferencing operations for reference types: new(n) n.data = 9 # no need to write n[].data; in fact n[].data is highly discouraged! + ``` Automatic dereferencing can be performed for the first argument of a routine call, but this is an experimental feature and is described `here @@ -1920,9 +1948,10 @@ call, but this is an experimental feature and is described `here In order to simplify structural type checking, recursive tuples are not valid: -.. code-block:: nim + ```nim # invalid recursion type MyTuple = tuple[a: ref MyTuple] + ``` Likewise `T = ref T` is an invalid type. @@ -1930,12 +1959,12 @@ As a syntactical extension, `object` types can be anonymous if declared in a type section via the `ref object` or `ptr object` notations. This feature is useful if an object should only gain reference semantics: -.. code-block:: nim - + ```nim type Node = ref object le, ri: Node data: int + ``` To allocate a new traced object, the built-in procedure `new` has to be used. @@ -1957,20 +1986,20 @@ Dereferencing `nil` is an unrecoverable fatal runtime error (and not a panic). A successful dereferencing operation `p[]` implies that `p` is not nil. This can be exploited by the implementation to optimize code like: -.. code-block:: nim - + ```nim p[].field = 3 if p != nil: # if p were nil, `p[]` would have caused a crash already, # so we know `p` is always not nil here. action() + ``` Into: -.. code-block:: nim - + ```nim p[].field = 3 action() + ``` *Note*: This is not comparable to C's "undefined behavior" for @@ -1985,7 +2014,7 @@ traced references, strings, or sequences: in order to free everything properly, the built-in procedure `reset` has to be called before freeing the untraced memory manually: -.. code-block:: nim + ```nim type Data = tuple[x, y: int, s: string] @@ -2000,6 +2029,7 @@ memory manually: # free the memory: dealloc(d) + ``` Without the `reset` call the memory allocated for the `d.s` string would never be freed. The example also demonstrates two important features for @@ -2025,18 +2055,17 @@ an allowed value for a variable of a procedural type. Examples: -.. code-block:: nim - + ```nim proc printItem(x: int) = ... proc forEach(c: proc (x: int) {.cdecl.}) = ... forEach(printItem) # this will NOT compile because calling conventions differ + ``` -.. code-block:: nim - + ```nim type OnMouseMove = proc (x, y: int) {.closure.} @@ -2049,6 +2078,7 @@ Examples: # ok, 'onMouseMove' has the default calling convention, which is compatible # to 'closure': setOnMouseMove(onMouseMove) + ``` A subtle issue with procedural types is that the calling convention of the @@ -2131,8 +2161,7 @@ reverse operation. A distinct type is an ordinal type if its base type is an ordinal type. -Modeling currencies -~~~~~~~~~~~~~~~~~~~~ +### Modeling currencies A distinct type can be used to model different physical `units`:idx: with a numerical base type, for example. The following example models currencies. @@ -2140,7 +2169,7 @@ numerical base type, for example. The following example models currencies. Different currencies should not be mixed in monetary calculations. Distinct types are a perfect tool to model different currencies: -.. code-block:: nim + ```nim type Dollar = distinct int Euro = distinct int @@ -2151,19 +2180,21 @@ types are a perfect tool to model different currencies: echo d + 12 # Error: cannot add a number with no unit and a `Dollar` + ``` Unfortunately, `d + 12.Dollar` is not allowed either, because `+` is defined for `int` (among others), not for `Dollar`. So a `+` for dollars needs to be defined: -.. code-block:: + ``` proc `+` (x, y: Dollar): Dollar = result = Dollar(int(x) + int(y)) + ``` It does not make sense to multiply a dollar with a dollar, but with a number without unit; and the same holds for division: -.. code-block:: + ``` proc `*` (x: Dollar, y: int): Dollar = result = Dollar(int(x) * y) @@ -2171,6 +2202,7 @@ number without unit; and the same holds for division: result = Dollar(x * int(y)) proc `div` ... + ``` This quickly gets tedious. The implementations are trivial and the compiler should not generate all this code only to optimize it away later - after all @@ -2178,10 +2210,11 @@ should not generate all this code only to optimize it away later - after all The pragma `borrow`:idx: has been designed to solve this problem; in principle, it generates the above trivial implementations: -.. code-block:: nim + ```nim proc `*` (x: Dollar, y: int): Dollar {.borrow.} proc `*` (x: int, y: Dollar): Dollar {.borrow.} proc `div` (x: Dollar, y: int): Dollar {.borrow.} + ``` The `borrow` pragma makes the compiler use the same implementation as the proc that deals with the distinct type's base type, so no code is @@ -2190,9 +2223,7 @@ generated. But it seems all this boilerplate code needs to be repeated for the `Euro` currency. This can be solved with templates_. -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template additive(typ: typedesc) = proc `+` *(x, y: typ): typ {.borrow.} proc `-` *(x, y: typ): typ {.borrow.} @@ -2221,12 +2252,13 @@ currency. This can be solved with templates_. defineCurrency(Dollar, int) defineCurrency(Euro, int) + ``` The borrow pragma can also be used to annotate the distinct type to allow certain builtin operations to be lifted: -.. code-block:: nim + ```nim type Foo = object a, b: int @@ -2239,18 +2271,18 @@ certain builtin operations to be lifted: # field access now valid bb.a = 90 bb.s = "abc" + ``` Currently, only the dot accessor can be borrowed in this way. -Avoiding SQL injection attacks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Avoiding SQL injection attacks An SQL statement that is passed from Nim to an SQL database might be modeled as a string. However, using string templates and filling in the values is vulnerable to the famous `SQL injection attack`:idx:\: -.. code-block:: nim + ```nim import std/strutils proc query(db: DbHandle, statement: string) = ... @@ -2260,12 +2292,13 @@ values is vulnerable to the famous `SQL injection attack`:idx:\: db.query("SELECT FROM users WHERE name = '$1'" % username) # Horrible security hole, but the compiler does not mind! + ``` This can be avoided by distinguishing strings that contain SQL from strings that don't. Distinct types provide a means to introduce a new string type `SQL` that is incompatible with `string`: -.. code-block:: nim + ```nim type SQL = distinct string @@ -2276,13 +2309,14 @@ that don't. Distinct types provide a means to introduce a new string type db.query("SELECT FROM users WHERE name = '$1'" % username) # Static error: `query` expects an SQL string! + ``` It is an essential property of abstract types that they **do not** imply a subtype relation between the abstract type and its base type. Explicit type conversions from `string` to `SQL` are allowed: -.. code-block:: nim + ```nim import std/[strutils, sequtils] proc properQuote(s: string): SQL = @@ -2298,6 +2332,7 @@ conversions from `string` to `SQL` are allowed: result = SQL(string(frmt) % StrSeq(v)) db.query("SELECT FROM users WHERE name = '$1'".SQL % [username]) + ``` Now we have compile-time checking against SQL injection attacks. Since `"".SQL` is transformed to `SQL("")` no new syntax is needed for nice @@ -2312,18 +2347,21 @@ 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 + ```nim proc returnsInt(): auto = 1984 + ``` For parameters it currently creates implicitly generic routines: -.. code-block:: nim + ```nim proc foo(a, b: auto) = discard + ``` Is the same as: -.. code-block:: nim + ```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 @@ -2367,8 +2405,7 @@ Convertible relation A type `a` is **implicitly** convertible to type `b` iff the following algorithm returns true: -.. code-block:: nim - + ```nim proc isImplicitlyConvertible(a, b: PType): bool = if isSubtype(a, b): return true @@ -2398,6 +2435,7 @@ algorithm returns true: result = b == cstring of proc: result = typeEquals(a, b) or compatibleParametersAndEffects(a, b) + ``` We used the predicate `typeEquals(a, b)` for the "type equality" property and the predicate `isSubtype(a, b)` for the "subtype relation". @@ -2417,7 +2455,7 @@ are signed integers or if both are unsigned integers. A type `a` is **explicitly** convertible to type `b` iff the following algorithm returns true: -.. code-block:: nim + ```nim proc isIntegralType(t: PType): bool = result = isOrdinal(t) or t.kind in {float, float32, float64} @@ -2429,11 +2467,12 @@ algorithm returns true: if b == distinct and typeEquals(b.baseType, a): return true if isIntegralType(a) and isIntegralType(b): return true if isSubtype(a, b) or isSubtype(b, a): return true + ``` The convertible relation can be relaxed by a user-defined type `converter`:idx:. -.. code-block:: nim + ```nim converter toInt(x: char): int = result = ord(x) var @@ -2446,6 +2485,7 @@ The convertible relation can be relaxed by a user-defined type # one can use the explicit form too x = chr.toInt echo x # => 97 + ``` The type conversion `T(a)` is an L-value if `a` is an L-value and `typeEqualsOrDistinct(T, typeof(a))` holds. @@ -2506,7 +2546,7 @@ algorithm returns true:: Some examples: -.. code-block:: nim + ```nim proc takesInt(x: int) = echo "int" proc takesInt[T](x: T) = echo "T" proc takesInt(x: int16) = echo "int16" @@ -2518,6 +2558,7 @@ Some examples: takesInt(y) # "int16" var z: range[0..4] = 0 takesInt(z) # "T" + ``` If this algorithm returns "ambiguous" further disambiguation is performed: @@ -2525,7 +2566,7 @@ If the argument `a` matches both the parameter type `f` of `p` and `g` of `q` via a subtyping relation, the inheritance depth is taken into account: -.. code-block:: nim + ```nim type A = object of RootObj B = object of A @@ -2547,18 +2588,20 @@ into account: # but this is ambiguous: pp(c, c) + ``` Likewise, for generic matches, the most specialized generic type (that still matches) is preferred: -.. code-block:: nim + ```nim proc gen[T](x: ref ref T) = echo "ref ref T" proc gen[T](x: ref T) = echo "ref T" proc gen[T](x: T) = echo "T" var ri: ref int gen(ri) # "ref T" + ``` Overloading based on 'var T' @@ -2569,7 +2612,7 @@ 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 + ```nim proc sayHi(x: int): string = # matches a non-var int result = $x @@ -2584,6 +2627,7 @@ the argument is checked to be an `l-value`:idx:. sayHello(3) # 3 # 13 + ``` Lazy type resolution for untyped @@ -2597,10 +2641,11 @@ in overloading resolution, it's essential to have a way to pass unresolved expressions to a template or macro. This is what the meta-type `untyped` accomplishes: -.. code-block:: nim + ```nim template rem(x: untyped) = discard rem unresolvedExpression(undeclaredIdentifier) + ``` A parameter of type `untyped` always matches any argument (as long as there is any argument passed to it). @@ -2608,12 +2653,13 @@ any argument passed to it). But one has to watch out because other overloads might trigger the argument's resolution: -.. code-block:: nim + ```nim template rem(x: untyped) = discard proc rem[T](x: T) = discard # undeclared identifier: 'unresolvedExpression' rem unresolvedExpression(undeclaredIdentifier) + ``` `untyped` and `varargs[untyped]` are the only metatype that are lazy in this sense, the other metatypes `typed` and `typedesc` are not lazy. @@ -2632,7 +2678,7 @@ A called `iterator` yielding type `T` can be passed to a template or macro via a parameter typed as `untyped` (for unresolved expressions) or the type class `iterable` or `iterable[T]` (after type checking and overload resolution). -.. code-block:: nim + ```nim iterator iota(n: int): int = for i in 0.. 8: 9 else: 10 + ``` An if expression always results in a value, so the `else` part is required. `Elif` parts are also allowed. @@ -3383,7 +3467,7 @@ Case expression The `case` expression is again very similar to the case statement: -.. code-block:: nim + ```nim var favoriteFood = case animal of "dog": "bones" of "cat": "mice" @@ -3391,6 +3475,7 @@ The `case` expression is again very similar to the case statement: else: echo "I'm not sure what to serve, but everybody loves ice cream" "ice cream" + ``` As seen in the above example, the case expression can also introduce side effects. When multiple statements are given for a branch, Nim will use @@ -3404,23 +3489,25 @@ that uses the last expression under the block as the value. It is similar to the statement list expression, but the statement list expression does not open a new block scope. -.. code-block:: nim + ```nim let a = block: var fib = @[0, 1] for i in 0..10: fib.add fib[^1] + fib[^2] fib + ``` Table constructor ----------------- A table constructor is syntactic sugar for an array constructor: -.. code-block:: nim + ```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 @@ -3453,13 +3540,13 @@ can be used to convert from floating-point to integer or vice versa. Type conversion can also be used to disambiguate overloaded routines: -.. code-block:: nim - + ```nim proc p(x: int) = echo "int" proc p(x: string) = echo "string" let procVar = (proc(x: string))(p) procVar("a") + ``` Since operations on unsigned numbers wrap around and are unchecked so are type conversions to unsigned integers and between unsigned integers. The @@ -3482,15 +3569,17 @@ Type casts as if it would be of another type. Type casts are only needed for low-level programming and are inherently unsafe. -.. code-block:: nim + ```nim cast[int](x) + ``` The target type of a cast must be a concrete type, for instance, a target type that is a type class (which is non-concrete) would be invalid: -.. code-block:: nim + ```nim type Foo = int or float var x = cast[Foo](1) # Error: cannot cast to a non concrete type: 'Foo' + ``` Type casts should not be confused with *type conversions,* as mentioned in the prior section. Unlike type conversions, a type cast cannot change the underlying @@ -3509,8 +3598,7 @@ the address of variables. For easier interoperability with other compiled langua such as C, retrieving the address of a `let` variable, a parameter, or a `for` loop variable can be accomplished too: -.. code-block:: nim - + ```nim let t1 = "Hello" var t2 = t1 @@ -3521,15 +3609,17 @@ or a `for` loop variable can be accomplished too: # --> Hello # The following line also works echo repr(addr(t1)) + ``` The unsafeAddr operator ----------------------- The `unsafeAddr` operator is a deprecated alias for the `addr` operator: -.. code-block:: nim + ```nim let myArray = [1, 2, 3] foreignProcThatTakesAnAddr(unsafeAddr myArray) + ``` Procedures ========== @@ -3544,7 +3634,7 @@ 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 + ```nim # Using only commas proc foo(a, b: int, c, d: bool): int @@ -3553,31 +3643,35 @@ separation of types and subsequent identifiers more distinct. # 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. The value will be reevaluated every time the function is called. -.. code-block:: nim + ```nim # b is optional with 47 as its default value. proc foo(a: int, b: int = 47): int + ``` Just as the comma propagates the types from right to left until the first parameter or until a semicolon is hit, it also propagates the default value starting from the parameter declared with it. -.. code-block:: nim + ```nim # Both a and b are optional with 47 as their default values. proc foo(a, 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 + ```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 @@ -3585,8 +3679,7 @@ variable named `result`:idx: that represents the return value. Procs can be overloaded. The overloading resolution algorithm determines which proc is the best match for the arguments. Example: -.. code-block:: nim - + ```nim proc toLower(c: char): char = # toLower for characters if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) @@ -3597,10 +3690,11 @@ best match for the arguments. Example: result = newString(len(s)) for i in 0..len(s) - 1: result[i] = toLower(s[i]) # calls toLower for characters; no recursion! + ``` Calling a procedure can be done in many different ways: -.. code-block:: nim + ```nim proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ... # call with positional arguments # parameter bindings: @@ -3611,16 +3705,18 @@ Calling a procedure can be done in many different ways: callme(c='\t', y=1, x=0) # (x=0, y=1, s="", c='\t', b=false) # call as a command statement: no () needed: callme 0, 1, "abc", '\t' # (x=0, y=1, s="abc", c='\t', b=false) + ``` A procedure may call itself recursively. `Operators`:idx: are procedures with a special operator symbol as identifier: -.. code-block:: nim + ```nim proc `$` (x: int): string = # converts an integer to a string; this is a prefix operator. result = intToStr(x) + ``` Operators with one parameter are prefix operators, operators with two parameters are infix operators. (However, the parser distinguishes these from @@ -3631,10 +3727,11 @@ grammar explicitly. Any operator can be called like an ordinary proc with the \`opr\` notation. (Thus an operator can have more than two parameters): -.. code-block:: nim + ```nim proc `*+` (a, b, c: int): int = # Multiply and add result = a * b + c + ``` assert `*+`(3, 4, 6) == `+`(`*`(a, b), c) @@ -3645,8 +3742,7 @@ Export marker If a declared symbol is marked with an `asterisk`:idx: it is exported from the current module: -.. code-block:: nim - + ```nim proc exportedEcho*(s: string) = echo s proc `*`*(a: string; b: int): string = result = newStringOfCap(a.len * b) @@ -3657,6 +3753,7 @@ current module: type ExportedType* = object exportedField*: int + ``` Method call syntax @@ -3669,12 +3766,12 @@ there are no remaining arguments: `obj.len` (instead of `len(obj)`). 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 - + ```nim echo "abc".len # is the same as echo len "abc" echo "abc".toUpper() echo {'a', 'b', 'c'}.card 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. @@ -3698,7 +3795,7 @@ 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 different; for this, a special setter syntax is needed: -.. code-block:: nim + ```nim # Module asocket type Socket* = ref object of RootObj @@ -3717,24 +3814,26 @@ different; for this, a special setter syntax is needed: ## `host` because the builtin dot access is preferred if it is ## available: s.host + ``` -.. code-block:: nim + ```nim # module B import asocket var s: Socket new s s.host = 34 # same as `host=`(s, 34) + ``` A proc defined as `f=` (with the trailing `=`) is called a `setter`:idx:. A setter can be called explicitly via the common backticks notation: -.. code-block:: nim - + ```nim proc `f=`(x: MyObject; value: string) = discard `f=`(myObject, "value") + ``` `f=` can be called implicitly in the pattern @@ -3755,7 +3854,7 @@ means `echo f 1, f 2` is parsed as `echo(f(1), f(2))` and not as `echo(f(1, f(2)))`. The method call syntax may be used to provide one more argument in this case: -.. code-block:: nim + ```nim proc optarg(x: int, y: int = 0): int = x + y proc singlearg(x: int): int = 20*x @@ -3765,6 +3864,7 @@ more argument in this case: 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 <#procedures-anonymous-procs>`_), `if`, @@ -3784,8 +3884,7 @@ the closure and its enclosing scope (i.e. any modifications made to them are visible in both places). The closure environment may be allocated on the heap or on the stack if the compiler determines that this would be safe. -Creating closures in loops -~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Creating closures in loops Since closures capture local variables by reference it is often not wanted behavior inside loop bodies. See `closureScope @@ -3798,11 +3897,12 @@ Anonymous procedures Unnamed procedures can be used as lambda expressions to pass into other procedures: -.. code-block:: nim + ```nim var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"] cities.sort(proc (x, y: string): int = cmp(x.len, y.len)) + ``` Procs as expressions can appear both as nested procs and inside top-level @@ -3817,7 +3917,7 @@ As a special convenience notation that keeps most elements of a regular proc expression, the `do` keyword can be used to pass anonymous procedures to routines: -.. code-block:: nim + ```nim var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"] sort(cities) do (x, y: string) -> int: @@ -3826,6 +3926,7 @@ anonymous procedures to routines: # Less parentheses using the method plus command syntax: cities = cities.map do (x: string) -> string: "City of " & x + ``` `do` is written after the parentheses enclosing the regular proc params. The proc expression represented by the `do` block is appended to the routine @@ -3837,7 +3938,7 @@ however `do` without parameters or pragmas is treated as a normal statement list. This allows macros to receive both indented statement lists as an argument in inline calls, as well as a direct mirror of Nim's routine syntax. -.. code-block:: nim + ```nim # Passing a statement list to an inline macro: macroResults.add quote do: if not `ex`: @@ -3846,19 +3947,22 @@ argument in inline calls, as well as a direct mirror of Nim's routine syntax. # Processing a routine definition in a macro: rpc(router, "add") do (a, b: int) -> int: result = a + b + ``` Func ---- The `func` keyword introduces a shortcut for a `noSideEffect`:idx: proc. -.. code-block:: nim + ```nim func binarySearch[T](a: openArray[T]; elem: T): int + ``` Is short for: -.. code-block:: nim + ```nim proc binarySearch[T](a: openArray[T]; elem: T): int {.noSideEffect.} + ``` @@ -3876,7 +3980,7 @@ A type bound operator is a `proc` or `func` whose name starts with `=` but isn't A type bound operator declared for a type applies to the type regardless of whether the operator is in scope (including if it is private). -.. code-block:: nim + ```nim # foo.nim: var witness* = 0 type Foo[T] = object @@ -3896,6 +4000,7 @@ the operator is in scope (including if it is private). doAssert witness == 2 # will still be called upon exiting scope doAssert witness == 3 + ``` Type bound operators are: `=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`. @@ -3937,7 +4042,7 @@ Var parameters -------------- The type of a parameter may be prefixed with the `var` keyword: -.. code-block:: nim + ```nim proc divmod(a, b: int; res, remainder: var int) = res = a div b remainder = a mod b @@ -3948,6 +4053,7 @@ The type of a parameter may be prefixed with the `var` keyword: divmod(8, 5, x, y) # modifies x and y assert x == 1 assert y == 3 + ``` In the example, `res` and `remainder` are `var parameters`. Var parameters can be modified by the procedure and the changes are @@ -3955,7 +4061,7 @@ visible to the caller. The argument passed to a var parameter has to be an l-value. Var parameters are implemented as hidden pointers. The above example is equivalent to: -.. code-block:: nim + ```nim proc divmod(a, b: int; res, remainder: ptr int) = res[] = a div b remainder[] = a mod b @@ -3965,11 +4071,12 @@ above example is equivalent to: divmod(8, 5, addr(x), addr(y)) assert x == 1 assert y == 3 + ``` In the examples, var parameters or pointers are used to provide two return values. This can be done in a cleaner way by returning a tuple: -.. code-block:: nim + ```nim proc divmod(a, b: int): tuple[res, remainder: int] = (a div b, a mod b) @@ -3977,13 +4084,15 @@ return values. This can be done in a cleaner way by returning a tuple: assert t.res == 1 assert t.remainder == 3 + ``` One can use `tuple unpacking`:idx: to access the tuple's fields: -.. code-block:: nim + ```nim var (x, y) = divmod(8, 5) # tuple unpacking assert x == 1 assert y == 3 + ``` **Note**: `var` parameters are never necessary for efficient parameter @@ -3997,7 +4106,7 @@ Var return type A proc, converter, or iterator may return a `var` type which means that the returned value is an l-value and can be modified by the caller: -.. code-block:: nim + ```nim var g = 0 proc writeAccessToG(): var int = @@ -4005,21 +4114,24 @@ returned value is an l-value and can be modified by the caller: writeAccessToG() = 6 assert g == 6 + ``` It is a static error if the implicitly introduced pointer could be used to access a location beyond its lifetime: -.. code-block:: nim + ```nim proc writeAccessToG(): var int = var g = 0 result = g # Error! + ``` For iterators, a component of a tuple return type can have a `var` type too: -.. code-block:: nim + ```nim iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] = for i in 0..a.high: yield (i, a[i]) + ``` In the standard library every name of a routine that returns a `var` type starts with the prefix `m` per convention. @@ -4027,14 +4139,14 @@ starts with the prefix `m` per convention. .. include:: manual/var_t_return.md -Future directions -~~~~~~~~~~~~~~~~~ +### Future directions Later versions of Nim can be more precise about the borrowing rule with a syntax like: -.. code-block:: nim + ```nim proc foo(other: Y; container: var X): var T from container + ``` Here `var T from container` explicitly exposes that the location is derived from the second parameter (called @@ -4060,7 +4172,7 @@ receives a hidden mutable parameter representing `result`. Informally: -.. code-block:: nim + ```nim proc p(): BigT = ... var x = p() @@ -4072,6 +4184,7 @@ Informally: var x; p(x) p(x) + ``` Let `T`'s be `p`'s return type. NRVO applies for `T` @@ -4081,8 +4194,7 @@ in other words, it applies for "big" structures. If `p` can raise an exception, NRVO applies regardless. This can produce observable differences in behavior: -.. code-block:: nim - + ```nim type BigT = array[16, int] @@ -4099,6 +4211,7 @@ observable differences in behavior: doAssert x == [0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0] main() + ``` However, the current implementation produces a warning in these cases. @@ -4125,7 +4238,7 @@ Procedures always use static dispatch. Methods use dynamic dispatch. For dynamic dispatch to work on an object it should be a reference type. -.. code-block:: nim + ```nim type Expression = ref object of RootObj ## abstract base class for an expression Literal = ref object of Expression @@ -4153,6 +4266,7 @@ type. result.b = b 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 @@ -4177,9 +4291,7 @@ Multi-methods In a multi-method, all parameters that have an object type are used for the dispatching: -.. code-block:: nim - :test: "nim c --multiMethods:on $1" - + ```nim test = "nim c --multiMethods:on $1" type Thing = ref object of RootObj Unit = ref object of Thing @@ -4198,6 +4310,7 @@ dispatching: new a new b collide(a, b) # output: 2 + ``` Inhibit dynamic method resolution via procCall ----------------------------------------------- @@ -4206,9 +4319,7 @@ Dynamic method resolution can be inhibited via the builtin `system.procCall`:idx This is somewhat comparable to the `super`:idx: keyword that traditional OOP languages offer. -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" type Thing = ref object of RootObj Unit = ref object of Thing @@ -4221,6 +4332,7 @@ languages offer. # Call the base method: procCall m(Thing(a)) echo "1" + ``` Iterators and the for statement @@ -4243,7 +4355,7 @@ reached, the data is bound to the `for` loop variables and control continues in the body of the `for` loop. The iterator's local variables and execution state are automatically saved between calls. Example: -.. code-block:: nim + ```nim # this definition exists in the system module iterator items*(a: string): char {.inline.} = var i = 0 @@ -4253,15 +4365,17 @@ state are automatically saved between calls. Example: for ch in items("hello world"): # `ch` is an iteration variable echo ch + ``` The compiler generates code as if the programmer would have written this: -.. code-block:: nim + ```nim var i = 0 while i < len(a): var ch = a[i] echo ch inc(i) + ``` 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 @@ -4275,8 +4389,9 @@ If the for loop expression `e` does not denote an iterator and the for loop has exactly 1 variable, the for loop expression is rewritten to `items(e)`; ie. an `items` iterator is implicitly invoked: -.. code-block:: nim + ```nim for x in [1,2,3]: echo x + ``` If the for loop has exactly 2 variables, a `pairs` iterator is implicitly invoked. @@ -4305,7 +4420,7 @@ templates, macros, and other inline iterators. In contrast to that, a `closure iterator`:idx: can be passed around more freely: -.. code-block:: nim + ```nim iterator count0(): int {.closure.} = yield 0 @@ -4320,6 +4435,7 @@ In contrast to that, a `closure iterator`:idx: can be passed around more freely: invoke(count0) invoke(count2) + ``` Closure iterators and inline iterators have some restrictions: @@ -4338,7 +4454,7 @@ 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: -.. code-block:: nim + ```nim # simple tasking: type Task = iterator (ticker: int) @@ -4368,6 +4484,7 @@ a `collaborative tasking`:idx: system: inc ticker runTasks(a1, a2) + ``` The builtin `system.finished` can be used to determine if an iterator has finished its operation; no exception is raised on an attempt to invoke an @@ -4376,7 +4493,7 @@ iterator that has already finished its work. Note that `system.finished` is error prone to use because it only returns `true` one iteration after the iterator has finished: -.. code-block:: nim + ```nim iterator mycount(a, b: int): int {.closure.} = var x = a while x <= b: @@ -4392,15 +4509,17 @@ Note that `system.finished` is error prone to use because it only returns 2 3 0 + ``` Instead this code has to be used: -.. code-block:: nim + ```nim var c = mycount # instantiate the iterator while true: let value = c(1, 3) if finished(c): break # and discard 'value'! echo value + ``` It helps to think that the iterator actually returns a pair `(value, done)` and `finished` is used to access the hidden `done` @@ -4411,7 +4530,7 @@ Closure iterators are *resumable functions* and so one has to provide the arguments to every call. To get around this limitation one can capture parameters of an outer factory proc: -.. code-block:: nim + ```nim proc mycount(a, b: int): iterator (): int = result = iterator (): int = var x = a @@ -4423,10 +4542,11 @@ parameters of an outer factory proc: for f in foo(): echo f + ``` The call can be made more like an inline iterator with a for loop macro: -.. code-block:: nim + ```nim import std/macros macro toItr(x: ForLoopStmt): untyped = let expr = x[0] @@ -4440,6 +4560,7 @@ The call can be made more like an inline iterator with a for loop macro: for f in toItr(mycount(1, 4)): # using early `proc mycount` echo f + ``` Because of full backend function call aparatus involvment, closure iterator invocation is typically higher cost than inline iterators. Adornment by @@ -4449,7 +4570,7 @@ The factory `proc`, as an ordinary procedure, can be recursive. The above macro allows such recursion to look much like a recursive iterator would. For example: -.. code-block:: nim + ```nim proc recCountDown(n: int): iterator(): int = result = iterator(): int = if n > 0: @@ -4459,6 +4580,7 @@ would. For example: for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1 echo i + ``` See also see `iterable <#overloading-resolution-iterable>`_ for passing iterators to templates and macros. @@ -4469,12 +4591,13 @@ Converters A converter is like an ordinary proc except that it enhances the "implicitly convertible" type relation (see `Convertible relation`_): -.. code-block:: nim + ```nim # bad style ahead: Nim is not C. converter toBool(x: int): bool = x != 0 if 4: echo "compiles" + ``` A converter can also be explicitly invoked for improved readability. Note that @@ -4488,7 +4611,7 @@ Type sections Example: -.. code-block:: nim + ```nim type # example demonstrating mutually recursive types Node = ref object # an object managed by the garbage collector (ref) le, ri: Node # left and right subtrees @@ -4498,6 +4621,7 @@ Example: name: string # the symbol's name line: int # the line the symbol was declared in code: Node # the symbol's abstract syntax tree + ``` A type section begins with the `type` keyword. It contains multiple type definitions. A type definition binds a type to a name. Type definitions @@ -4515,7 +4639,7 @@ Try statement Example: -.. code-block:: nim + ```nim # read the first two lines of a text file that should contain numbers # and tries to add them var @@ -4533,6 +4657,7 @@ Example: echo "Unknown exception!" finally: close(f) + ``` The statements after the `try` are executed in sequential order unless @@ -4561,19 +4686,21 @@ Try can also be used as an expression; the type of the `try` branch then needs to fit the types of `except` branches, but the type of the `finally` branch always has to be `void`: -.. code-block:: nim + ```nim from std/strutils import parseInt let x = try: parseInt("133a") except: -1 finally: echo "hi" + ``` To prevent confusing code there is a parsing limitation; if the `try` follows a `(` it has to be written as a one liner: -.. code-block:: nim + ```nim let x = (try: parseInt("133a") except: -1) + ``` Except clauses @@ -4582,59 +4709,65 @@ Except clauses Within an `except` clause it is possible to access the current exception using the following syntax: -.. code-block:: nim + ```nim try: # ... except IOError as e: # Now use "e" echo "I/O error: " & e.msg + ``` Alternatively, it is possible to use `getCurrentException` to retrieve the exception that has been raised: -.. code-block:: nim + ```nim try: # ... except IOError: let e = getCurrentException() # Now use "e" + ``` Note that `getCurrentException` always returns a `ref Exception` type. If a variable of the proper type is needed (in the example above, `IOError`), one must convert it explicitly: -.. code-block:: nim + ```nim try: # ... except IOError: let e = (ref IOError)(getCurrentException()) # "e" is now of the proper type + ``` However, this is seldom needed. The most common case is to extract an error message from `e`, and for such situations, it is enough to use `getCurrentExceptionMsg`: -.. code-block:: nim + ```nim try: # ... except: echo getCurrentExceptionMsg() + ``` Custom exceptions ----------------- It is possible to create custom exceptions. A custom exception is a custom type: -.. code-block:: nim + ```nim type LoadError* = object of Exception + ``` Ending the custom exception's name with `Error` is recommended. Custom exceptions can be raised just like any other exception, e.g.: -.. code-block:: nim + ```nim raise newException(LoadError, "Failed to load data") + ``` Defer statement --------------- @@ -4646,20 +4779,17 @@ below. Any statements following the `defer` in the current block will be considered to be in an implicit try block: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" proc main = var f = open("numbers.txt", fmWrite) defer: close(f) f.write "abc" f.write "def" + ``` Is rewritten to: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" proc main = var f = open("numbers.txt") try: @@ -4667,13 +4797,12 @@ Is rewritten to: f.write "def" finally: close(f) + ``` When `defer` is at the outermost scope of a template/macro, its scope extends to the block where the template is called from: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template safeOpenDefer(f, path) = var f = open(path, fmWrite) defer: close(f) @@ -4694,6 +4823,7 @@ to the block where the template is called from: try: f.write "abc" # adds a lexical scope finally: close(f) + ``` Top-level `defer` statements are not supported since it's unclear what such a statement should refer to. @@ -4704,8 +4834,9 @@ Raise statement Example: -.. code-block:: nim + ```nim raise newException(IOError, "IO failed") + ``` Apart from built-in operations like array indexing, memory allocation, etc. the `raise` statement is the only way to raise an exception. @@ -4739,9 +4870,7 @@ It is possible to raise/catch imported C++ exceptions. Types imported using `importcpp` can be raised or caught. Exceptions are raised by value and caught by reference. Example: -.. code-block:: nim - :test: "nim cpp -r $1" - + ```nim test = "nim cpp -r $1" type CStdException {.importcpp: "std::exception", header: "", inheritable.} = object ## does not inherit from `RootObj`, so we use `inheritable` instead @@ -4772,6 +4901,7 @@ caught by reference. Example: doAssert $b == "foo3" fn() + ``` **Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available for imported exceptions from C++. One needs to use the `except ImportedException as x:` syntax @@ -4793,31 +4923,28 @@ Nim supports exception tracking. The `raises`:idx: pragma can be used to explicitly define which exceptions a proc/iterator/method/converter is allowed to raise. The compiler verifies this: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" proc p(what: bool) {.raises: [IOError, OSError].} = if what: raise newException(IOError, "IO") else: raise newException(OSError, "OS") + ``` An empty `raises` list (`raises: []`) means that no exception may be raised: -.. code-block:: nim + ```nim proc p(): bool {.raises: [].} = try: unsafeCall() result = true except: result = false + ``` A `raises` list can also be attached to a proc type. This affects type compatibility: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 type Callback = proc (s: string) {.raises: [IOError].} var @@ -4827,6 +4954,7 @@ compatibility: raise newException(OSError, "OS") c = p # type error + ``` For a routine `p`, the compiler uses inference rules to determine the set of @@ -4858,18 +4986,18 @@ Exceptions inheriting from `system.Defect` are not tracked with the `.raises: []` exception tracking mechanism. This is more consistent with the built-in operations. The following code is valid: -.. code-block:: nim - + ```nim proc mydiv(a, b): int {.raises: [].} = a div b # can raise an DivByZeroDefect + ``` And so is: -.. code-block:: nim - + ```nim proc mydiv(a, b): int {.raises: [].} = if b == 0: raise newException(DivByZeroDefect, "division by zero") else: result = a div b + ``` The reason for this is that `DivByZeroDefect` inherits from `Defect` and @@ -4883,7 +5011,7 @@ EffectsOf annotation Rules 1-2 of the exception tracking inference rules (see the previous section) ensure the following works: -.. code-block:: nim + ```nim proc weDontRaiseButMaybeTheCallback(callback: proc()) {.raises: [], effectsOf: callback.} = callback() @@ -4893,6 +5021,7 @@ ensure the following works: proc use() {.raises: [].} = # doesn't compile! Can raise IOError! weDontRaiseButMaybeTheCallback(doRaise) + ``` As can be seen from the example, a parameter of type `proc (...)` can be annotated as `.effectsOf`. Such a parameter allows for effect polymorphism: @@ -4902,10 +5031,7 @@ that `callback` raises. So in many cases a callback does not cause the compiler to be overly conservative in its effect analysis: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 {.push warningAsError[Effect]: on.} {.experimental: "strictEffects".} @@ -4928,6 +5054,7 @@ conservative in its effect analysis: proc harmfull {.raises: [].} = # does not compile, `sort` can now raise Exception toSort.sort cmpE + ``` @@ -4938,16 +5065,14 @@ 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 effect is a means to *tag* a routine and to perform checks against this tag: -.. code-block:: nim - :test: "nim c --warningAsError:Effect:on $1" - :status: 1 - + ```nim test = "nim c --warningAsError:Effect:on $1" status = 1 type IO = object ## input/output effect proc readLine(): string {.tags: [IO].} = discard 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 also be attached to a proc type. This affects type compatibility. @@ -4976,18 +5101,19 @@ so that it can be used for debugging routines marked as `noSideEffect`. `func` is syntactic sugar for a proc with no side effects: -.. code-block:: nim + ```nim func `+` (x, y: int): int + ``` To override the compiler's side effect analysis a `{.noSideEffect.}` `cast` pragma block can be used: -.. code-block:: nim - + ```nim func f() = {.cast(noSideEffect).}: echo "test" + ``` **Side effects are usually inferred. The inference for side effects is analogous to the inference for exception tracking.** @@ -5012,8 +5138,7 @@ Routines that are imported from C are always assumed to be `gcsafe`. To override the compiler's gcsafety analysis a `{.cast(gcsafe).}` pragma block can be used: -.. code-block:: nim - + ```nim var someGlobal: string = "some string here" perThread {.threadvar.}: string @@ -5021,6 +5146,7 @@ be used: proc setPerThread() = {.cast(gcsafe).}: deepCopy(perThread, someGlobal) + ``` See also: @@ -5036,13 +5162,14 @@ The `effects` pragma has been designed to assist the programmer with the effects analysis. It is a statement that makes the compiler output all inferred effects up to the `effects`'s position: -.. code-block:: nim + ```nim proc p(what: bool) = if what: raise newException(IOError, "IO") {.effects.} else: raise newException(OSError, "OS") + ``` The compiler produces a hint message that `IOError` can be raised. `OSError` is not listed as it cannot be raised in the branch the `effects` pragma @@ -5058,9 +5185,7 @@ introduce type parameters or to instantiate a generic proc, iterator, or type. The following example shows how a generic binary tree can be modeled: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" type BinaryTree*[T] = ref object # BinaryTree is a generic type with # generic param `T` @@ -5114,6 +5239,7 @@ The following example shows how a generic binary tree can be modeled: add(root, "world") # instantiates the second `add` proc for str in preorder(root): stdout.writeLine(str) + ``` The `T` is called a `generic type parameter`:idx: or a `type variable`:idx:. @@ -5125,13 +5251,14 @@ The `is` operator is evaluated during semantic analysis to check for type equivalence. It is therefore very useful for type specialization within generic code: -.. code-block:: nim + ```nim type Table[Key, Value] = object keys: seq[Key] values: seq[Value] when not (Key is string): # empty value for strings used for optimization deletedKeys: seq[bool] + ``` Type classes @@ -5165,20 +5292,22 @@ name that will match any instantiation of the generic type. Type classes can be combined using the standard boolean operators to form more complex type classes: -.. code-block:: nim + ```nim # create a type class that will match all tuple and object types type RecordType = tuple or object proc printFields[T: RecordType](rec: T) = for key, value in fieldPairs(rec): echo key, " = ", value + ``` Type constraints on generic parameters can be grouped with `,` and propagation stops with `;`, similarly to parameters for macros and templates: -.. code-block:: nim + ```nim proc fn1[T; U, V: SomeFloat]() = discard # T is unconstrained template fn2(t; u, v: SomeFloat) = discard # t is unconstrained + ``` Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data types in ML-like languages, it should be understood that type classes are static @@ -5189,20 +5318,22 @@ runtime type dynamism, unlike object variants or methods. As an example, the following would not compile: -.. code-block:: nim + ```nim type TypeClass = int | string var foo: TypeClass = 2 # foo's type is resolved to an int here foo = "this will fail" # error here, because foo is an int + ``` Nim allows for type classes and regular types to be specified as `type constraints`:idx: of the generic type parameter: -.. code-block:: nim + ```nim proc onlyIntOrString[T: int|string](x, y: T) = discard onlyIntOrString(450, 616) # valid onlyIntOrString(5.0, 0.0) # type mismatch onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time + ``` Implicit generics @@ -5210,14 +5341,14 @@ Implicit generics A type class can be used directly as the parameter's type. -.. code-block:: nim - + ```nim # create a type class that will match all tuple and object types type RecordType = tuple or object proc printFields(rec: RecordType) = for key, value in fieldPairs(rec): echo key, " = ", value + ``` Procedures utilizing type classes in such a manner are considered to be @@ -5228,7 +5359,7 @@ By default, during overload resolution, each named type class will bind to exactly one concrete type. We call such type classes `bind once`:idx: types. Here is an example taken directly from the system module to illustrate this: -.. code-block:: nim + ```nim proc `==`*(x, y: tuple): bool = ## requires `x` and `y` to be of the same tuple type ## generic `==` operator for tuples that is lifted from the components @@ -5236,6 +5367,7 @@ Here is an example taken directly from the system module to illustrate this: result = true for a, b in fields(x, y): if a != b: result = false + ``` 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. Such @@ -5245,72 +5377,72 @@ 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: -.. code-block:: nim + ```nim type Matrix[T, Rows, Columns] = object ... proc `[]`(m: Matrix, row, col: int): Matrix.T = m.data[col * high(Matrix.Columns) + row] + ``` Here are more examples that illustrate implicit generics: -.. code-block:: nim - + ```nim proc p(t: Table; k: Table.Key): Table.Value # is roughly the same as: proc p[Key, Value](t: Table[Key, Value]; k: Key): Value + ``` -.. code-block:: nim - + ```nim proc p(a: Table, b: Table) # is roughly the same as: proc p[Key, Value](a, b: Table[Key, Value]) + ``` -.. code-block:: nim - + ```nim proc p(a: Table, b: distinct Table) # is roughly the same as: proc p[Key, Value, KeyB, ValueB](a: Table[Key, Value], b: Table[KeyB, ValueB]) + ``` `typedesc` used as a parameter type also introduces an implicit generic. `typedesc` has its own set of rules: -.. code-block:: nim - + ```nim proc p(a: typedesc) # is roughly the same as: proc p[T](a: typedesc[T]) + ``` `typedesc` is a "bind many" type class: -.. code-block:: nim - + ```nim proc p(a, b: typedesc) # is roughly the same as: proc p[T, T2](a: typedesc[T], b: typedesc[T2]) + ``` A parameter of type `typedesc` is itself usable as a type. If it is used as a type, it's the underlying type. (In other words, one level of "typedesc"-ness is stripped off: -.. code-block:: nim - + ```nim proc p(a: typedesc; b: a) = discard # is roughly the same as: @@ -5319,6 +5451,7 @@ of "typedesc"-ness is stripped off: # hence this is a valid call: p(int, 4) # as parameter 'a' requires a type, but 'b' requires a value. + ``` Generic inference restrictions @@ -5327,10 +5460,7 @@ Generic inference restrictions The types `var T` and `typedesc[T]` cannot be inferred in a generic instantiation. The following is not allowed: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 proc g[T](f: proc(x: T); x: T) = f(x) @@ -5347,14 +5477,14 @@ instantiation. The following is not allowed: # also not allowed: explicit instantiation via 'var int' g[var int](v, i) + ``` Symbol lookup in generics ------------------------- -Open and Closed symbols -~~~~~~~~~~~~~~~~~~~~~~~ +### Open and Closed symbols The symbol binding rules in generics are slightly subtle: There are "open" and "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation @@ -5364,9 +5494,7 @@ and every other symbol is closed. Open symbols are looked up in two different contexts: Both the context at definition and the context at instantiation are considered: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" type Index = distinct int @@ -5376,6 +5504,7 @@ at definition and the context at instantiation are considered: var b = (0, 0.Index) echo a == b # works! + ``` In the example, the generic `==` for tuples (as defined in the system module) uses the `==` operators of the tuple's components. However, the `==` for @@ -5388,15 +5517,14 @@ Mixin statement A symbol can be forced to be open by a `mixin`:idx: declaration: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" proc create*[T](): ref T = # there is no overloaded 'init' here, so we need to state that it's an # open symbol explicitly: mixin init new result init result + ``` `mixin` statements only make sense in templates and generics. @@ -5409,7 +5537,7 @@ can be used to explicitly declare identifiers that should be bound early (i.e. the identifiers should be looked up in the scope of the template/generic definition): -.. code-block:: nim + ```nim # Module A var lastId = 0 @@ -5418,12 +5546,14 @@ definition): bind lastId inc(lastId) lastId + ``` -.. code-block:: nim + ```nim # Module B import A echo genId() + ``` But a `bind` is rarely useful because symbol binding from the definition scope is the default. @@ -5437,16 +5567,15 @@ Delegating bind statements The following example outlines a problem that can arise when generic instantiations cross multiple different modules: -.. code-block:: nim - + ```nim # module A proc genericA*[T](x: T) = mixin init init(x) + ``` -.. code-block:: nim - + ```nim import C # module B @@ -5455,19 +5584,20 @@ instantiations cross multiple different modules: # not available when `genericB` is instantiated: bind init genericA(x) + ``` -.. code-block:: nim - + ```nim # module C type O = object proc init*(x: var O) = discard + ``` -.. code-block:: nim - + ```nim # module main import B, C genericB O() + ``` In module B has an `init` proc from module C in its scope that is not taken into account when `genericB` is instantiated which leads to the @@ -5486,12 +5616,13 @@ The syntax to *invoke* a template is the same as calling a procedure. Example: -.. code-block:: nim + ```nim template `!=` (a, b: untyped): untyped = # this definition exists in the System module not (a == b) assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) + ``` The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact templates: @@ -5513,24 +5644,21 @@ An `untyped` parameter means that symbol lookups and type resolution is not performed before the expression is passed to the template. This means that *undeclared* identifiers, for example, can be passed to the template: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template declareInt(x: untyped) = var x: int declareInt(x) # valid x = 3 + ``` -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 template declareInt(x: typed) = var x: int declareInt(x) # invalid, because x has not been declared and so it has no type + ``` A template where every parameter is `untyped` is called an `immediate`:idx: template. For historical reasons, templates can be explicitly annotated with @@ -5548,9 +5676,7 @@ Passing a code block to a template One can pass a block of statements as the last argument to a template following the special `:` syntax: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template withFile(f, fn, mode, actions: untyped): untyped = var f: File if open(f, fn, mode): @@ -5564,6 +5690,7 @@ following the special `:` syntax: withFile(txt, "ttempl3.txt", fmWrite): # special colon txt.writeLine("line 1") txt.writeLine("line 2") + ``` In the example, the two `writeLine` statements are bound to the `actions` parameter. @@ -5573,10 +5700,7 @@ Usually, to pass a block of code to a template, the parameter that accepts the block needs to be of type `untyped`. Because symbol lookups are then delayed until template instantiation time: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 template t(body: typed) = proc p = echo "hey" block: @@ -5584,6 +5708,7 @@ delayed until template instantiation time: t: p() # fails with 'undeclared identifier: p' + ``` The above code fails with the error message that `p` is not declared. The reason for this is that the `p()` body is type-checked before getting @@ -5591,9 +5716,7 @@ passed to the `body` parameter and type checking in Nim implies symbol lookups. The same code works with `untyped` as the passed body is not required to be type-checked: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template t(body: untyped) = proc p = echo "hey" block: @@ -5601,6 +5724,7 @@ type-checked: t: p() # compiles + ``` Varargs of untyped @@ -5609,12 +5733,11 @@ Varargs of untyped In addition to the `untyped` meta-type that prevents type checking, there is also `varargs[untyped]` so that not even the number of parameters is fixed: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template hideIdentifiers(x: varargs[untyped]) = discard hideIdentifiers(undeclared1, undeclared2) + ``` However, since a template cannot iterate over varargs, this feature is generally much more useful for macros. @@ -5626,7 +5749,7 @@ Symbol binding in templates A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are bound from the definition scope of the template: -.. code-block:: nim + ```nim # Module A var lastId = 0 @@ -5634,12 +5757,14 @@ bound from the definition scope of the template: template genId*: untyped = inc(lastId) lastId + ``` -.. code-block:: nim + ```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` statements. @@ -5651,9 +5776,7 @@ Identifier construction In templates, identifiers can be constructed with the backticks notation: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template typedef(name: untyped, typ: typedesc) = type `T name`* {.inject.} = typ @@ -5661,6 +5784,7 @@ In templates, identifiers can be constructed with the backticks notation: typedef(myint, int) var x: PMyInt + ``` In the example, `name` is instantiated with `myint`, so \`T name\` becomes `Tmyint`. @@ -5673,7 +5797,7 @@ A parameter `p` in a template is even substituted in the expression `x.p`. Thus, template arguments can be used as field names and a global symbol can be shadowed by the same argument name even when fully qualified: -.. code-block:: nim + ```nim # module 'm' type @@ -5687,10 +5811,11 @@ 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 + ```nim # module 'm' type @@ -5705,6 +5830,7 @@ But the global symbol can properly be captured by a `bind` statement: tstLev(levA) # produces: 'levA levB' + ``` Hygiene in templates @@ -5713,9 +5839,7 @@ Hygiene in templates Per default, templates are `hygienic`:idx:\: Local identifiers declared in a template cannot be accessed in the instantiation context: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template newException*(exceptn: typedesc, message: string): untyped = var e: ref exceptn # e is implicitly gensym'ed here @@ -5726,6 +5850,7 @@ template cannot be accessed in the instantiation context: # so this works: let e = "message" raise newException(IoError, e) + ``` Whether a symbol that is declared in a template is exposed to the instantiation @@ -5737,7 +5862,7 @@ is `gensym` and for `proc`, `iterator`, `converter`, `template`, `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 + ```nim template withFile(f, fn, mode: untyped, actions: untyped): untyped = block: var f: File # since 'f' is a template param, it's injected implicitly @@ -5746,16 +5871,18 @@ template parameter, it is an `inject`'ed symbol: withFile(txt, "ttempl3.txt", fmWrite): txt.writeLine("line 1") txt.writeLine("line 2") + ``` The `inject` and `gensym` pragmas are second class annotations; they have no semantics outside of a template definition and cannot be abstracted over: -.. code-block:: nim + ```nim {.pragma myInject: inject.} template t() = var x {.myInject.}: int # does NOT work + ``` To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for @@ -5767,9 +5894,7 @@ and `namedParameterCall(field = value)` syntactic constructs. The reason for this is that code like -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" type T = object f: int @@ -5777,6 +5902,7 @@ The reason for this is that code like template tmp(x: T) = let f = 34 echo x.f, T(f: 4) + ``` should work as expected. @@ -5784,10 +5910,7 @@ should work as expected. However, this means that the method call syntax is not available for `gensym`'ed symbols: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 template tmp(x) = type T {.gensym.} = int @@ -5795,6 +5918,7 @@ However, this means that the method call syntax is not available for echo x.T # invalid: instead use: 'echo T(x)'. tmp(12) + ``` Limitations of the method call syntax @@ -5805,32 +5929,28 @@ symbol lookup and type checking) before it can be decided that it needs to be rewritten to `f(x)`. Therefore the dot syntax has some limitations when it is used to invoke templates/macros: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 template declareVar(name: untyped) = const name {.inject.} = 45 # Doesn't compile: unknownIdentifier.declareVar + ``` It is also not possible to use fully qualified identifiers with module symbol in method call syntax. The order in which the dot operator binds to symbols prohibits this. -.. code-block:: nim - :test: "nim c $1" - :status: 1 - - import std/sequtils + ```nim test = "nim c $1" status = 1 + import std/sequtils - var myItems = @[1,3,3,7] - let N1 = count(myItems, 3) # OK - let N2 = sequtils.count(myItems, 3) # fully qualified, OK - let N3 = myItems.count(3) # OK - let N4 = myItems.sequtils.count(3) # illegal, `myItems.sequtils` can't be resolved + var myItems = @[1,3,3,7] + let N1 = count(myItems, 3) # OK + let N2 = sequtils.count(myItems, 3) # fully qualified, OK + let N3 = myItems.count(3) # OK + let N4 = myItems.sequtils.count(3) # illegal, `myItems.sequtils` can't be resolved + ``` This means that when for some reason a procedure needs a disambiguation through the module name, the call needs to be @@ -5873,9 +5993,7 @@ Debug example The following example implements a powerful `debug` command that accepts a variable number of arguments: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" # to work with Nim syntax trees, we need an API that is defined in the # `macros` module: import std/macros @@ -5903,10 +6021,11 @@ variable number of arguments: a[1] = 45 debug(a[0], a[1], x) + ``` The macro call expands to: -.. code-block:: nim + ```nim write(stdout, "a[0]") write(stdout, ": ") writeLine(stdout, a[0]) @@ -5918,6 +6037,7 @@ The macro call expands to: write(stdout, "x") write(stdout, ": ") writeLine(stdout, x) + ``` Arguments that are passed to a `varargs` parameter are wrapped in an array @@ -5934,9 +6054,7 @@ instantiating context. There is a way to use bound identifiers (aka `symbols`:idx:) instead of using unbound identifiers. The `bindSym` builtin can be used for that: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" import std/macros macro debug(n: varargs[typed]): untyped = @@ -5954,10 +6072,11 @@ builtin can be used for that: a[1] = 45 debug(a[0], a[1], x) + ``` The macro call expands to: -.. code-block:: nim + ```nim write(stdout, "a[0]") write(stdout, ": ") writeLine(stdout, a[0]) @@ -5969,6 +6088,7 @@ The macro call expands to: write(stdout, "x") write(stdout, ": ") writeLine(stdout, x) + ``` However, the symbols `write`, `writeLine` and `stdout` are already bound and are not looked up again. As the example shows, `bindSym` does work with @@ -5986,7 +6106,7 @@ Macros can receive `of`, `elif`, `else`, `except`, `finally` and `do` blocks (including their different forms such as `do` with routine parameters) as arguments if called in statement form. -.. code-block:: nim + ```nim macro performWithUndo(task, undo: untyped) = ... performWithUndo do: @@ -6006,6 +6126,7 @@ as arguments if called in statement form. echo "Buzz" else: echo num + ``` For loop macro @@ -6014,9 +6135,7 @@ For loop macro A macro that takes as its only input parameter an expression of the special type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" import std/macros macro example(loop: ForLoopStmt) = @@ -6026,18 +6145,18 @@ type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: result.add newCall(bindSym"echo", loop[0]) for item in example([1, 2, 3]): discard + ``` Expands to: -.. code-block:: nim + ```nim for item in items([1, 2, 3]): echo item + ``` Another example: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" import std/macros macro enumerate(x: ForLoopStmt): untyped = @@ -6069,6 +6188,7 @@ Another example: # names for `a` and `b` here to avoid redefinition errors for a, b in enumerate(10, [1, 2, 3, 5]): echo a, " ", b + ``` Case statement macros @@ -6079,8 +6199,7 @@ for certain types. The following is an example of such an implementation for tuples, leveraging the existing equality operator for tuples (as provided in `system.==`): -.. code-block:: nim - :test: "nim c $1" + ```nim test = "nim c $1" import std/macros macro `case`(n: tuple): untyped = @@ -6102,6 +6221,7 @@ for tuples, leveraging the existing equality operator for tuples of ("foo", 78): echo "yes" of ("bar", 88): echo "no" else: discard + ``` `case` macros are subject to overload resolution. The type of the `case` statement's selector expression is matched against the type @@ -6121,8 +6241,7 @@ static[T] As their name suggests, static parameters must be constant expressions: -.. code-block:: nim - + ```nim proc precompiledRegex(pattern: static string): RegEx = var res {.global.} = re(pattern) return res @@ -6132,6 +6251,7 @@ As their name suggests, static parameters must be constant expressions: precompiledRegex(paramStr(1)) # Error, command-line options # are not constant expressions + ``` For the purposes of code generation, all static params are treated as @@ -6140,8 +6260,7 @@ supplied value (or combination of values). Static params can also appear in the signatures of generic types: -.. code-block:: nim - + ```nim type Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T] # Note how `Number` is just a type constraint here, while @@ -6152,6 +6271,7 @@ Static params can also appear in the signatures of generic types: var m1: AffineTransform3D[float] # OK var m2: AffineTransform2D[string] # Error, `string` is not a `Number` + ``` Please note that `static T` is just a syntactic convenience for the underlying generic type `static[T]`. The type param can be omitted to obtain the type @@ -6161,10 +6281,11 @@ instantiating `static` with another type class. One can force an expression to be evaluated at compile time as a constant expression by coercing it to a corresponding `static` type: -.. code-block:: nim + ```nim import std/math echo static(fac(5)), " ", static[bool](16.isPowerOfTwo) + ``` The compiler will report any failure to evaluate the expression or a possible type mismatch error. @@ -6186,30 +6307,30 @@ They will be instantiated for each unique combination of supplied types, and within the body of the proc, the name of each param will refer to the bound concrete type: -.. code-block:: nim - + ```nim proc new(T: typedesc): ref T = echo "allocating ", T.name new(result) var n = Node.new var tree = new(BinaryTree[int]) + ``` When multiple type params are present, they will bind freely to different types. To force a bind-once behavior, one can use an explicit generic param: -.. code-block:: nim + ```nim proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U]) + ``` Once bound, type params can appear in the rest of the proc signature: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template declareVariableWithType(T: typedesc, value: T) = var x: T = value declareVariableWithType int, 42 + ``` Overload resolution can be further influenced by constraining the set @@ -6217,9 +6338,7 @@ of types that will match the type param. This works in practice by attaching attributes to types via templates. The constraint can be a concrete type or a type class. -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" template maxval(T: typedesc[int]): int = high(int) template maxval(T: typedesc[float]): float = Inf @@ -6235,13 +6354,13 @@ concrete type or a type class. echo "is int a number? ", isNumber(int) echo "is float a number? ", isNumber(float) echo "is RootObj a number? ", isNumber(RootObj) + ``` Passing `typedesc` is almost identical, just with the difference that the macro is not instantiated generically. The type expression is simply passed as a `NimNode` to the macro, like everything else. -.. code-block:: nim - + ```nim import std/macros macro forwardType(arg: typedesc): typedesc = @@ -6250,6 +6369,7 @@ simply passed as a `NimNode` to the macro, like everything else. result = tmp var tmp: forwardType(int) + ``` typeof operator --------------- @@ -6261,10 +6381,10 @@ One can obtain the type of a given expression by constructing a `typeof` value from it (in many other languages this is known as the `typeof`:idx: operator): -.. code-block:: nim - + ```nim var x = 0 var y: typeof(x) # y has type int + ``` If `typeof` is used to determine the result type of a proc/iterator/converter @@ -6273,9 +6393,7 @@ interpretation, where `c` is an iterator, is preferred over the other interpretations, but this behavior can be changed by passing `typeOfProc` as the second argument to `typeof`: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" iterator split(s: string): string = discard proc split(s: string): seq[string] = discard @@ -6283,6 +6401,7 @@ passing `typeOfProc` as the second argument to `typeof`: assert typeof("a b c".split) is string assert typeof("a b c".split, typeOfProc) is seq[string] + ``` @@ -6306,7 +6425,7 @@ The algorithm for compiling modules is: This is best illustrated by an example: -.. code-block:: nim + ```nim # Module A type T1* = int # Module A exports the type `T1` @@ -6316,9 +6435,10 @@ This is best illustrated by an example: var i = p(3) # works because B has been parsed completely here main() + ``` -.. code-block:: nim + ```nim # Module B import A # A is not parsed here! Only the already known symbols # of A are imported. @@ -6327,6 +6447,7 @@ This is best illustrated by an example: # this works because the compiler has already # added T1 to A's interface symbol table result = x + 1 + ``` Import statement @@ -6336,14 +6457,12 @@ After the `import` statement, a list of module names can follow or a single module name followed by an `except` list to prevent some symbols from being imported: -.. code-block:: nim - :test: "nim c $1" - :status: 1 - + ```nim test = "nim c $1" status = 1 import std/strutils except `%`, toUpperAscii # doesn't work then: echo "$1" % "abc".toUpperAscii + ``` It is not checked that the `except` list is really exported from the module. @@ -6360,21 +6479,24 @@ The `include` statement does something fundamentally different than importing a module: it merely includes the contents of a file. The `include` statement is useful to split up a large module into several files: -.. code-block:: nim + ```nim include fileA, fileB, fileC + ``` The `include` statement can be used outside of the top level, as such: -.. code-block:: nim + ```nim # Module A echo "Hello World!" + ``` -.. code-block:: nim + ```nim # Module B proc main() = include A main() # => Hello World! + ``` Module names in imports @@ -6382,29 +6504,33 @@ Module names in imports A module alias can be introduced via the `as` keyword: -.. code-block:: nim + ```nim import std/strutils as su, std/sequtils as qu echo su.format("$1", "lalelu") + ``` The original module name is then not accessible. The notations `path/to/module` or `"path/to/module"` can be used to refer to a module in subdirectories: -.. code-block:: nim + ```nim import lib/pure/os, "lib/pure/times" + ``` Note that the module name is still `strutils` and not `lib/pure/strutils` and so one **cannot** do: -.. code-block:: nim + ```nim import lib/pure/strutils echo lib/pure/strutils.toUpperAscii("abc") + ``` Likewise, the following does not make sense as the name is `strutils` already: -.. code-block:: nim + ```nim import lib/pure/strutils as strutils + ``` Collective imports from a directory @@ -6416,8 +6542,9 @@ from the same directory. Path names are syntactically either Nim identifiers or string literals. If the path name is not a valid Nim identifier it needs to be a string literal: -.. code-block:: nim + ```nim import "gfx/3d/somemodule" # in quotes because '3d' is not a valid Nim identifier + ``` Pseudo import/include paths @@ -6445,14 +6572,13 @@ After the `from` statement, a module name follows followed by an `import` to list the symbols one likes to use without explicit full qualification: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" from std/strutils import `%` echo "$1" % "abc" # 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 @@ -6465,34 +6591,38 @@ Export statement An `export` statement can be used for symbol forwarding so that client modules don't need to import a module's dependencies: -.. code-block:: nim + ```nim # module B type MyObject* = object + ``` -.. code-block:: nim + ```nim # module A import B export B.MyObject proc `$`*(x: MyObject): string = "my object" + ``` -.. code-block:: nim + ```nim # module C import A # B.MyObject has been imported implicitly here: var x: MyObject echo $x + ``` When the exported symbol is another module, all of its definitions will be forwarded. One can use an `except` list to exclude some of the symbols. Notice that when exporting, one needs to specify only the module name: -.. code-block:: nim + ```nim import foo/bar/baz export baz + ``` @@ -6503,8 +6633,8 @@ the block in which the declaration occurred. The range where the identifier is known is the scope of the identifier. The exact scope of an identifier depends on the way it was declared. -Block scope -~~~~~~~~~~~ +### Block scope + The *scope* of a variable declared in the declaration part of a block is valid from the point of declaration until the end of the block. If a block contains a second block, in which the identifier is redeclared, @@ -6514,8 +6644,8 @@ identifier cannot be redefined in the same block, except if valid for procedure or iterator overloading purposes. -Tuple or object scope -~~~~~~~~~~~~~~~~~~~~~ +### Tuple or object scope + The field identifiers inside a tuple or object definition are valid in the following places: @@ -6523,8 +6653,8 @@ following places: * Field designators of a variable of the given tuple/object type. * In all descendant types of the object type. -Module scope -~~~~~~~~~~~~ +### 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 module. @@ -6533,15 +6663,17 @@ If a module imports an identifier by two different modules, each occurrence of the identifier has to be qualified unless it is an overloaded procedure or iterator in which case the overloading resolution takes place: -.. code-block:: nim + ```nim # Module A var x*: string + ``` -.. code-block:: nim + ```nim # Module B var x*: int + ``` -.. code-block:: nim + ```nim # Module C import A, B write(stdout, x) # error: x is ambiguous @@ -6549,6 +6681,7 @@ iterator in which case the overloading resolution takes place: var x = 4 write(stdout, x) # not ambiguous: uses the module C's x + ``` Packages @@ -6589,14 +6722,16 @@ deprecated pragma The deprecated pragma is used to mark a symbol as deprecated: -.. code-block:: nim + ```nim proc p() {.deprecated.} var x {.deprecated.}: char + ``` This pragma can also take in an optional warning string to relay to developers. -.. code-block:: nim + ```nim proc thing(x: bool) {.deprecated: "use thong instead".} + ``` @@ -6608,23 +6743,23 @@ 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 implicitly declared `compileTime`: -.. code-block:: nim + ```nim proc astHelper(n: NimNode): NimNode = result = n + ``` Is the same as: -.. code-block:: nim + ```nim proc astHelper(n: NimNode): NimNode {.compileTime.} = result = n + ``` `compileTime` variables are available at runtime too. This simplifies certain idioms where variables are filled at compile-time (for example, lookup tables) but accessed at runtime: -.. code-block:: nim - :test: "nim c -r $1" - + ```nim test = "nim c -r $1" import std/macros var nameToProc {.compileTime.}: seq[(string, proc (): string {.nimcall.})] @@ -6642,6 +6777,7 @@ but accessed at runtime: proc baz: string {.registerProc.} = "baz" doAssert nameToProc[2][1]() == "baz" + ``` noreturn pragma @@ -6655,20 +6791,22 @@ The `acyclic` pragma can be used for object types to mark them as acyclic even though they seem to be cyclic. This is an **optimization** for the garbage collector to not consider objects of this type as part of a cycle: -.. code-block:: nim + ```nim type Node = ref NodeObj NodeObj {.acyclic.} = object left, right: Node data: string + ``` Or if we directly use a ref object: -.. code-block:: nim + ```nim type Node {.acyclic.} = ref object left, right: Node data: string + ``` In the example, a tree structure is declared with the `Node` type. Note that the type definition is recursive and the GC has to assume that objects of @@ -6696,7 +6834,7 @@ because the semantics of Nim require deep copying of sequences and strings. This can be expensive, especially if sequences are used to build a tree structure: -.. code-block:: nim + ```nim type NodeKind = enum nkLeaf, nkInner Node {.shallow.} = object @@ -6705,6 +6843,7 @@ structure: strVal: string of nkInner: children: seq[Node] + ``` pure pragma @@ -6739,9 +6878,10 @@ annotate a symbol (like an iterator or proc). The *usage* of the symbol then triggers a static error. This is especially useful to rule out that some operation is valid due to overloading and type conversions: -.. code-block:: nim + ```nim ## check that underlying int values are compared and not the pointers: proc `==`(x, y: ptr int): bool {.error.} + ``` fatal pragma @@ -6750,9 +6890,10 @@ The `fatal` pragma is used to make the compiler output an error message with the given content. In contrast to the `error` pragma, the compilation is guaranteed to be aborted by this pragma. Example: -.. code-block:: nim + ```nim when not defined(objc): {.fatal: "Compile this program with the objc command!".} + ``` warning pragma -------------- @@ -6769,13 +6910,13 @@ line pragma The `line` pragma can be used to affect line information of the annotated statement, as seen in stack backtraces: -.. code-block:: nim - + ```nim template myassert*(cond: untyped, msg = "") = if not cond: # change run-time line information of the 'raise' statement: {.line: instantiationInfo().}: raise newException(AssertionDefect, msg) + ``` If the `line` pragma is used with a parameter, the parameter needs be a `tuple[filename: string, line: int]`. If it is used without a parameter, @@ -6788,7 +6929,7 @@ The `linearScanEnd` pragma can be used to tell the compiler how to compile a Nim `case`:idx: statement. Syntactically it has to be used as a statement: -.. code-block:: nim + ```nim case myInt of 0: echo "most common case" @@ -6797,6 +6938,7 @@ statement: echo "second most common case" of 2: echo "unlikely: use branch table" else: echo "unlikely too: use branch table for ", myInt + ``` In the example, the case branches `0` and `1` are much more common than the other cases. Therefore the generated assembler code should test for these @@ -6816,8 +6958,7 @@ The `computedGoto` pragma can be used to tell the compiler how to compile a Nim `case`:idx: in a `while true` statement. Syntactically it has to be used as a statement inside the loop: -.. code-block:: nim - + ```nim type MyEnum = enum enumA, enumB, enumC, enumD, enumE @@ -6849,6 +6990,7 @@ Syntactically it has to be used as a statement inside the loop: inc(pc) vm() + ``` As the example shows, `computedGoto` is mostly useful for interpreters. If the underlying backend (C compiler) does not support the computed goto @@ -6898,9 +7040,10 @@ callconv cdecl|... Specifies the default calling convention for Example: -.. code-block:: nim + ```nim {.checks: off, optimization: speed.} # compile without runtime checks and optimize for speed + ``` push and pop pragmas @@ -6908,16 +7051,17 @@ push and pop pragmas The `push/pop`:idx: pragmas are very similar to the option directive, but are used to override the settings temporarily. Example: -.. code-block:: nim + ```nim {.push checks: off.} # compile this section without runtime checks as it is # speed critical # ... some code ... {.pop.} # restore old settings + ``` `push/pop`:idx: can switch on/off some standard library pragmas, example: -.. code-block:: nim + ```nim {.push inline.} proc thisIsInlined(): int = 42 func willBeInlined(): float = 42.0 @@ -6931,6 +7075,7 @@ but are used to override the settings temporarily. Example: {.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.} proc sample(): bool = true {.pop.} + ``` For third party pragmas, it depends on its implementation but uses the same syntax. @@ -6952,10 +7097,11 @@ The `global` pragma can be applied to a variable within a proc to instruct the compiler to store it in a global location and initialize it once at program startup. -.. code-block:: nim + ```nim proc isHexNumber(s: string): bool = var pattern {.global.} = re"[0-9a-fA-F]+" result = s.match(pattern) + ``` When used within a generic proc, a separate unique global variable will be created for each instantiation of the proc. The order of initialization of @@ -6970,8 +7116,9 @@ user. A mechanism for disabling certain messages is provided: Each hint and warning message contains a symbol in brackets. This is the message's identifier that can be used to enable or disable it: -.. code-block:: Nim + ```Nim {.hint[LineTooLong]: off.} # turn off the hint about too long lines + ``` This is often better than disabling all warnings at once. @@ -6983,7 +7130,7 @@ Nim produces a warning for symbols that are not exported and not used either. The `used` pragma can be attached to a symbol to suppress this warning. This is particularly useful when the symbol was generated by a macro: -.. code-block:: nim + ```nim template implementArithOps(T) = proc echoAdd(a, b: T) {.used.} = echo a + b @@ -6993,18 +7140,19 @@ is particularly useful when the symbol was generated by a macro: # no warning produced for the unused 'echoSub' implementArithOps(int) echoAdd 3, 5 + ``` `used` can also be used as a top-level statement to mark a module as "used". This prevents the "Unused import" warning: -.. code-block:: nim - + ```nim # module: debughelper.nim when defined(nimHasUsed): # 'import debughelper' is so useful for debugging # that Nim shouldn't produce a warning for that import, # even if currently unused: {.used.} + ``` experimental pragma @@ -7018,7 +7166,7 @@ is uncertain (it may be removed at any time). See the Example: -.. code-block:: nim + ```nim import std/threadpool {.experimental: "parallel".} @@ -7031,6 +7179,7 @@ Example: spawn threadedEcho("echo in parallel", i) useParallel() + ``` As a top-level statement, the experimental pragma enables a feature for the @@ -7038,8 +7187,7 @@ rest of the module it's enabled in. This is problematic for macro and generic instantiations that cross a module scope. Currently, these usages have to be put into a `.push/pop` environment: -.. code-block:: nim - + ```nim # client.nim proc useParallel*[T](unused: T) = # use a generic T here to show the problem. @@ -7049,12 +7197,13 @@ put into a `.push/pop` environment: echo "echo in parallel" {.pop.} + ``` -.. code-block:: nim - + ```nim import client useParallel(1) + ``` Implementation Specific Pragmas @@ -7069,17 +7218,19 @@ Bitsize pragma The `bitsize` pragma is for object field members. It declares the field as a bitfield in C/C++. -.. code-block:: Nim + ```Nim type mybitfield = object flag {.bitsize:1.}: cuint + ``` generates: -.. code-block:: C + ```C struct mybitfield { unsigned int flag:1; }; + ``` Align pragma @@ -7092,25 +7243,25 @@ alignments that are weaker than other align pragmas on the same declaration are ignored. Alignments that are weaker than the alignment requirement of the type are ignored. -.. code-block:: Nim - - type - sseType = object - sseData {.align(16).}: array[4, float32] + ```Nim + type + sseType = object + sseData {.align(16).}: array[4, float32] - # every object will be aligned to 128-byte boundary - Data = object - x: char - cacheline {.align(128).}: array[128, char] # over-aligned array of char, + # every object will be aligned to 128-byte boundary + Data = object + x: char + cacheline {.align(128).}: array[128, char] # over-aligned array of char, - proc main() = - echo "sizeof(Data) = ", sizeof(Data), " (1 byte + 127 bytes padding + 128-byte array)" - # output: sizeof(Data) = 256 (1 byte + 127 bytes padding + 128-byte array) - echo "alignment of sseType is ", alignof(sseType) - # output: alignment of sseType is 16 - var d {.align(2048).}: Data # this instance of data is aligned even stricter + proc main() = + echo "sizeof(Data) = ", sizeof(Data), " (1 byte + 127 bytes padding + 128-byte array)" + # output: sizeof(Data) = 256 (1 byte + 127 bytes padding + 128-byte array) + echo "alignment of sseType is ", alignof(sseType) + # output: alignment of sseType is 16 + var d {.align(2048).}: Data # this instance of data is aligned even stricter - main() + main() + ``` This pragma has no effect on the JS backend. @@ -7146,10 +7297,11 @@ 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 + ```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. @@ -7162,10 +7314,11 @@ 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`:c:\: -.. code-block:: Nim + ```Nim type PFile {.importc: "FILE*", header: "".} = 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 constant contains the header file: As usual for C, a system header file is enclosed @@ -7180,10 +7333,11 @@ IncompleteStruct pragma The `incompleteStruct` pragma tells the compiler to not use the underlying C `struct`:c: in a `sizeof` expression: -.. code-block:: Nim + ```Nim type DIR* {.importc: "DIR", header: "", pure, incompleteStruct.} = object + ``` Compile pragma @@ -7191,8 +7345,9 @@ Compile pragma The `compile` pragma can be used to compile and link a C/C++ source file with the project: -.. code-block:: Nim + ```Nim {.compile: "myfile.cpp".} + ``` **Note**: Nim computes a SHA1 checksum and only recompiles the file if it has changed. One can use the `-f`:option: command-line option to force @@ -7200,8 +7355,9 @@ the recompilation of the file. Since 1.4 the `compile` pragma is also available with this syntax: -.. code-block:: Nim + ```Nim {.compile("myfile.cpp", "--custom flags here").} + ``` As can be seen in the example, this new variant allows for custom flags that are passed to the C compiler when the file is recompiled. @@ -7211,8 +7367,9 @@ Link pragma ----------- The `link` pragma can be used to link an additional file with the project: -.. code-block:: Nim + ```Nim {.link: "myfile.o".} + ``` passc pragma @@ -7220,15 +7377,17 @@ passc pragma The `passc` pragma can be used to pass additional parameters to the C compiler like one would using the command-line switch `--passc`:option:\: -.. code-block:: Nim + ```Nim {.passc: "-Wall -Werror".} + ``` Note that one can use `gorge` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: -.. code-block:: Nim + ```Nim {.passc: gorge("pkg-config --cflags sdl").} + ``` localPassC pragma @@ -7237,10 +7396,11 @@ The `localPassC` pragma can be used to pass additional parameters to the C compiler, but only for the C/C++ file that is produced from the Nim module the pragma resides in: -.. code-block:: Nim + ```Nim # Module A.nim # Produces: A.nim.cpp {.localPassC: "-Wall -Werror".} # Passed when compiling A.nim.cpp + ``` passl pragma @@ -7248,15 +7408,17 @@ passl pragma The `passl` pragma can be used to pass additional parameters to the linker like one would be using the command-line switch `--passl`:option:\: -.. code-block:: Nim + ```Nim {.passl: "-lSDLmain -lSDL".} + ``` Note that one can use `gorge` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: -.. code-block:: Nim + ```Nim {.passl: gorge("pkg-config --libs sdl").} + ``` Emit pragma @@ -7268,7 +7430,7 @@ extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. Example: -.. code-block:: Nim + ```Nim {.emit: """ static int cvariable = 420; """.} @@ -7281,17 +7443,19 @@ Example: {.pop.} embedsC() + ``` ``nimbase.h`` defines `NIM_EXTERNC`:c: C macro that can be used for `extern "C"`:cpp: code to work with both `nim c`:cmd: and `nim cpp`:cmd:, e.g.: -.. code-block:: Nim + ```Nim proc foobar() {.importc:"$1".} {.emit: """ #include NIM_EXTERNC void fun(){} """.} + ``` .. note:: For backward compatibility, if the argument to the `emit` statement is a single string literal, Nim symbols can be referred to via backticks. @@ -7301,7 +7465,7 @@ For a top-level emit statement, the section where in the generated C/C++ file the code should be emitted can be influenced via the prefixes `/*TYPESECTION*/`:c: or `/*VARSECTION*/`:c: or `/*INCLUDESECTION*/`:c:\: -.. code-block:: Nim + ```Nim {.emit: """/*TYPESECTION*/ struct Vector3 { public: @@ -7315,6 +7479,7 @@ the code should be emitted can be influenced via the prefixes x: cfloat proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl} + ``` ImportCpp pragma @@ -7332,7 +7497,7 @@ in general. The generated code then uses the C++ method calling syntax: `obj->method(arg)`:cpp:. In combination with the `header` and `emit` pragmas this allows *sloppy* interfacing with libraries written in C++: -.. code-block:: Nim + ```Nim # Horrible example of how to interface with a C++ engine ... ;-) {.link: "/usr/lib/libIrrlicht.so".} @@ -7358,26 +7523,26 @@ pragmas this allows *sloppy* interfacing with libraries written in C++: header: irr, importcpp: "createDevice(@)".} proc run(device: IrrlichtDevice): bool {. header: irr, importcpp: "#.run(@)".} + ``` The compiler needs to be told to generate C++ (command `cpp`:option:) for this to work. The conditional symbol `cpp` is defined when the compiler emits C++ code. -Namespaces -~~~~~~~~~~ +### Namespaces The *sloppy interfacing* example uses `.emit` to produce `using namespace`:cpp: declarations. It is usually much better to instead refer to the imported name via the `namespace::identifier`:cpp: notation: -.. code-block:: nim + ```nim type IrrlichtDeviceObj {.header: irr, importcpp: "irr::IrrlichtDevice".} = object + ``` -Importcpp for enums -~~~~~~~~~~~~~~~~~~~ +### 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: @@ -7385,8 +7550,7 @@ annotated with the C++ enum type, like in this example: (This turned out to be the simplest way to implement it.) -Importcpp for procs -~~~~~~~~~~~~~~~~~~~ +### Importcpp for procs Note that the `importcpp` variant for procs uses a somewhat cryptic pattern language for maximum flexibility: @@ -7399,30 +7563,34 @@ language for maximum flexibility: For example: -.. code-block:: nim + ```nim proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".} var x: ptr CppObj cppMethod(x[], 1, 2, 3) + ``` Produces: -.. code-block:: C + ```C x->CppMethod(1, 2, 3) + ``` As a special rule to keep backward 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 + ```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 + ```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 @@ -7434,17 +7602,18 @@ capabilities: For example: -.. code-block:: nim - + ```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 + ```C x = SystemManager::getSubsystem() + ``` - ``#@`` is a special case to support a `cnew` operation. It is required so @@ -7454,30 +7623,32 @@ Produces: For example C++'s `new`:cpp: operator can be "imported" like this: -.. code-block:: nim + ```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 + ```C x = new Foo(3, 4) + ``` However, depending on the use case `new Foo`:cpp: can also be wrapped like this instead: -.. code-block:: nim + ```nim proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".} let x = newFoo(3, 4) + ``` -Wrapping constructors -~~~~~~~~~~~~~~~~~~~~~ +### Wrapping constructors Sometimes a C++ class has a private copy constructor and so code like `Class c = Class(1,2);`:cpp: must not be generated but instead @@ -7486,13 +7657,13 @@ 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 + ```nim # a better constructor of 'Foo': proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.} + ``` -Wrapping destructors -~~~~~~~~~~~~~~~~~~~~ +### 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 @@ -7500,20 +7671,18 @@ not wrapping the destructor at all! However, when it needs to be invoked explicitly, it needs to be wrapped. The pattern language provides everything that is required: -.. code-block:: nim + ```nim proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".} + ``` -Importcpp for objects -~~~~~~~~~~~~~~~~~~~~~ +### Importcpp for objects Generic `importcpp`'ed objects are mapped to C++ templates. This means that one can import C++'s templates rather easily without the need for a pattern language for object types: -.. code-block:: nim - :test: "nim cpp $1" - + ```nim test = "nim cpp $1" type StdMap[K, V] {.importcpp: "std::map", header: "".} = object proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. @@ -7521,32 +7690,34 @@ language for object types: var x: StdMap[cint, cdouble] x[6] = 91.4 + ``` Produces: -.. code-block:: C + ```C std::map 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 - + ```nim type VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object var x: VectorIterator[cint] - + ``` Produces: - .. code-block:: C + ```C std::vector::iterator x; + ``` ImportJs pragma @@ -7567,7 +7738,7 @@ 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 + ```Nim # horrible example of how to interface with GNUStep ... {.passl: "-lobjc".} @@ -7602,6 +7773,7 @@ allows *sloppy* interfacing with libraries written in Objective C: var g = newGreeter() g.greet(12, 34) g.free() + ``` The compiler needs to be told to generate Objective C (command `objc`:option:) for this to work. The conditional symbol ``objc`` is defined when the compiler @@ -7620,28 +7792,32 @@ and $2 is the name of the variable. The following Nim code: -.. code-block:: nim + ```nim var a {.codegenDecl: "$# progmem $#".}: int + ``` will generate this C code: -.. code-block:: c + ```c int progmem a + ``` For procedures, $1 is the return type of the procedure, $2 is the name of the procedure, and $3 is the parameter list. The following nim code: -.. code-block:: nim + ```nim proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} = echo "realistic interrupt handler" + ``` will generate this code: -.. code-block:: c + ```c __interrupt void myinterrupt() + ``` `cppNonPod` pragma @@ -7651,11 +7827,12 @@ The `.cppNonPod` pragma should be used for non-POD `importcpp` types so that the work properly (in particular regarding constructor and destructor) for `.threadvar` variables. This requires `--tlsEmulation:off`:option:. -.. code-block:: nim + ```nim type Foo {.cppNonPod, importcpp, header: "funs.h".} = object x: cint proc main()= var a {.threadvar.}: Foo + ``` compile-time define pragmas @@ -7675,12 +7852,14 @@ pragma description `booldefine`:idx: Reads in a build-time define as a bool ================= ============================================ -.. code-block:: nim - const FooBar {.intdefine.}: int = 5 - echo FooBar + ```nim + const FooBar {.intdefine.}: int = 5 + echo FooBar + ``` -.. code:: cmd - nim c -d:FooBar=42 foobar.nim + ```cmd + nim c -d:FooBar=42 foobar.nim + ``` In the above example, providing the `-d`:option: flag causes the symbol `FooBar` to be overwritten at compile-time, printing out 42. If the @@ -7704,7 +7883,7 @@ They cannot be imported from a module. Example: -.. code-block:: nim + ```nim when appType == "lib": {.pragma: rtl, exportc, dynlib, cdecl.} else: @@ -7712,6 +7891,7 @@ Example: proc p*(a, b: int): int {.rtl.} = result = a + b + ``` In the example, a new pragma named `rtl` is introduced that either imports a symbol from a dynamic library or exports the symbol for dynamic library @@ -7724,17 +7904,18 @@ It is possible to define custom typed pragmas. Custom pragmas do not affect code generation directly, but their presence can be detected by macros. Custom pragmas are defined using templates annotated with pragma `pragma`: -.. code-block:: nim + ```nim template dbTable(name: string, table_space: string = "") {.pragma.} template dbKey(name: string = "", primary_key: bool = false) {.pragma.} template dbForeignKey(t: typedesc) {.pragma.} template dbIgnore {.pragma.} + ``` Consider this stylized example of a possible Object Relation Mapping (ORM) implementation: -.. code-block:: nim + ```nim const tblspace {.strdefine.} = "dev" # switch for dev, test and prod environments type @@ -7750,6 +7931,7 @@ implementation: read_access: bool write_access: bool admin_acess: bool + ``` In this example, custom pragmas are used to describe how Nim objects are mapped to the schema of the relational database. Custom pragmas can have @@ -7772,18 +7954,20 @@ More examples with custom pragmas: - Better serialization/deserialization control: - .. code-block:: nim + ```nim type MyObj = object a {.dontSerialize.}: int b {.defaultDeserialize: 5.}: int c {.serializationKey: "_c".}: string + ``` - Adopting type for gui inspector in a game engine: - .. code-block:: nim + ```nim type MyComponent = object position {.editable, animatable.}: Vector3 alpha {.editRange: [0.0..1.0], animatable.}: float32 + ``` Macro pragmas @@ -7794,28 +7978,32 @@ where this is possible include when attached to routine (procs, iterators, etc) declarations or routine type expressions. The compiler will perform the following simple syntactic transformations: -.. code-block:: nim + ```nim template command(name: string, def: untyped) = discard proc p() {.command("print").} = discard + ``` This is translated to: -.. code-block:: nim + ```nim command("print"): proc p() = discard + ``` ------ -.. code-block:: nim + ```nim type AsyncEventHandler = proc (x: Event) {.async.} + ``` This is translated to: -.. code-block:: nim + ```nim type AsyncEventHandler = async(proc (x: Event)) + ``` ------ @@ -7867,8 +8055,9 @@ is not set to C, other pragmas are available: * `importobjc `_ * `importjs `_ -.. code-block:: Nim + ```Nim proc p(s: cstring) {.importc: "prefix$1".} + ``` In the example, the external name of `p` is set to `prefixp`. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. @@ -7881,17 +8070,19 @@ procedure to C. Enums and constants can't be exported. The optional argument is a string containing the C identifier. If the argument is missing, the C name is the Nim identifier *exactly as spelled*: -.. code-block:: Nim + ```Nim proc callme(formatstr: cstring) {.exportc: "callMe", varargs.} + ``` Note that this pragma is somewhat of a misnomer: Other backends do provide the same feature under the same name. The string literal passed to `exportc` can be a format string: -.. code-block:: Nim + ```Nim proc p(s: string) {.exportc: "prefix$1".} = echo s + ``` In the example, the external name of `p` is set to `prefixp`. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. @@ -7906,9 +8097,10 @@ Extern pragma Like `exportc` or `importc`, the `extern` pragma affects name mangling. The string literal passed to `extern` can be a format string: -.. code-block:: Nim + ```Nim proc p(s: string) {.extern: "prefix$1".} = echo s + ``` In the example, the external name of `p` is set to `prefixp`. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. @@ -7920,10 +8112,11 @@ Bycopy pragma The `bycopy` pragma can be applied to an object or tuple type and instructs the compiler to pass the type by value to procs: -.. code-block:: nim + ```nim type Vector {.bycopy.} = object x, y, z: float + ``` The Nim compiler automatically determines whether a parameter is passed by value or by reference based on the parameter type's size. If a parameter must be passed by value or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. @@ -7941,10 +8134,11 @@ 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: -.. code-block:: Nim + ```Nim proc printf(formatstr: cstring) {.nodecl, varargs.} printf("hallo %s", "world") # "world" will be passed as C string + ``` Union pragma @@ -7977,9 +8171,10 @@ 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). The non-optional argument has to be the name of the dynamic library: -.. code-block:: Nim + ```Nim proc gtk_image_new(): PGtkWidget {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.} + ``` In general, importing a dynamic library does not require any special linker options or linking with import libraries. This also implies that no *devel* @@ -7987,9 +8182,10 @@ packages need to be installed. The `dynlib` import mechanism supports a versioning scheme: -.. code-block:: nim + ```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):: @@ -8005,7 +8201,7 @@ At runtime, the dynamic library is searched for (in this order):: The `dynlib` pragma supports not only constant strings as an argument but also string expressions in general: -.. code-block:: nim + ```nim import std/os proc getDllName: string = @@ -8016,6 +8212,7 @@ string expressions in general: 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. @@ -8035,8 +8232,9 @@ With the `dynlib` pragma, a procedure can also be exported to a dynamic library. The pragma then has no argument and has to be used in conjunction with the `exportc` pragma: -.. code-block:: Nim + ```Nim proc exportme(): int {.cdecl, exportc, dynlib.} + ``` This is only useful if the program is compiled as a dynamic library via the `--app:lib`:option: command-line option. @@ -8085,8 +8283,9 @@ A variable can be marked with the `threadvar` pragma, which makes it a `thread-local`:idx: variable; Additionally, this implies all the effects of the `global` pragma. -.. code-block:: nim + ```nim var checkpoints* {.threadvar.}: seq[string] + ``` Due to implementation restrictions, thread-local variables cannot be initialized within the `var` section. (Every thread-local variable needs to @@ -8118,23 +8317,21 @@ pragmas: Guards and locks sections ------------------------- -Protecting global variables -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Protecting global variables Object fields and global variables can be annotated via a `guard` pragma: -.. code-block:: nim - + ```nim import std/locks var glock: Lock var gdata {.guard: glock.}: int + ``` The compiler then ensures that every access of `gdata` is within a `locks` section: -.. code-block:: nim - + ```nim proc invalid = # invalid: unguarded access: echo gdata @@ -8143,6 +8340,7 @@ section: # valid access: {.locks: [glock].}: echo gdata + ``` Top level accesses to `gdata` are always allowed so that it can be initialized conveniently. It is *assumed* (but not enforced) that every top level statement @@ -8152,8 +8350,7 @@ The `locks` section deliberately looks ugly because it has no runtime semantics and should not be used directly! It should only be used in templates that also implement some form of locking at runtime: -.. code-block:: nim - + ```nim template lock(a: Lock; body: untyped) = pthread_mutex_lock(a) {.locks: [a].}: @@ -8161,13 +8358,13 @@ that also implement some form of locking at runtime: body finally: pthread_mutex_unlock(a) + ``` The guard does not need to be of any particular type. It is flexible enough to model low level lockfree mechanisms: -.. code-block:: nim - + ```nim var dummyLock {.compileTime.}: int var atomicCounter {.guard: dummyLock.}: int @@ -8177,6 +8374,7 @@ model low level lockfree mechanisms: x echo atomicRead(atomicCounter) + ``` The `locks` pragma takes a list of lock expressions `locks: [a, b, ...]` @@ -8184,8 +8382,7 @@ in order to support *multi lock* statements. Why these are essential is explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. -Protecting general locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Protecting general locations The `guard` annotation can also be used to protect fields within an object. The guard then needs to be another field within the same object or a @@ -8194,8 +8391,7 @@ global variable. Since objects can reside on the heap or on the stack, this greatly enhances the expressivity of the language: -.. code-block:: nim - + ```nim import std/locks type @@ -8207,12 +8403,12 @@ the expressivity of the language: for i in 0..counters.high: lock counters[i].L: inc counters[i].v + ``` The access to field `x.v` is allowed since its guard `x.L` is active. After template expansion, this amounts to: -.. code-block:: nim - + ```nim proc incCounters(counters: var openArray[ProtectedCounter]) = for i in 0..counters.high: pthread_mutex_lock(counters[i].L) @@ -8221,6 +8417,7 @@ After template expansion, this amounts to: inc counters[i].v finally: pthread_mutex_unlock(counters[i].L) + ``` There is an analysis that checks that `counters[i].L` is the lock that corresponds to the protected location `counters[i].v`. This analysis is called @@ -8232,8 +8429,8 @@ Two paths are considered equivalent if they are syntactically the same. This means the following compiles (for now) even though it really should not: -.. code-block:: nim - + ```nim {.locks: [a[i].L].}: inc i access a[i].v + ``` diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 3968163c58d47..81d4cc51ecd06 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -1463,8 +1463,7 @@ The operators `*`, `**`, `|`, `~` have a special meaning in patterns if they are written in infix notation. -The `|` operator -~~~~~~~~~~~~~~~~~~ +### The `|` operator The `|` operator if used as infix operator creates an ordered choice: @@ -1490,8 +1489,7 @@ semantics anyway. In fact, they can be deactivated with the `--patterns:off`:opt command line option or temporarily with the `patterns` pragma. -The `{}` operator -~~~~~~~~~~~~~~~~~~~ +### The `{}` operator A pattern expression can be bound to a pattern parameter via the `expr{param}` notation: @@ -1504,8 +1502,7 @@ notation: echo a -The `~` operator -~~~~~~~~~~~~~~~~~~ +### The `~` operator The `~` operator is the 'not' operator in patterns: @@ -1523,8 +1520,7 @@ The `~` operator is the 'not' operator in patterns: echo a -The `*` operator -~~~~~~~~~~~~~~~~~~ +### The `*` operator The `*` operator can *flatten* a nested binary expression like `a & b & c` to `&(a, b, c)`: @@ -1559,8 +1555,7 @@ produces: `&&`("my", space & "awe", "some ", "concat") -The `**` operator -~~~~~~~~~~~~~~~~~~~ +### The `**` operator The `**` is much like the `*` operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation: diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt index d2e1f96f65ef6..1929a7b919c07 100644 --- a/doc/sets_fragment.txt +++ b/doc/sets_fragment.txt @@ -52,8 +52,7 @@ operation meaning `excl(A, elem)` same as `A = A - {elem}` ================== ======================================================== -Bit fields -~~~~~~~~~~ +### Bit fields Sets are often used to define a type for the *flags* of a procedure. This is a cleaner (and type safe) solution than defining integer diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 1721674c8b397..bca877c2fac32 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -11,9 +11,9 @@ ## packages/docutils/rst ## ================================== ## -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ------------------------------------------ ## Nim-flavored reStructuredText and Markdown -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ------------------------------------------ ## ## This module implements a `reStructuredText`:idx: (RST) and ## `Markdown`:idx: parser. @@ -290,7 +290,7 @@ type proc rstnodeToRefname*(n: PRstNode): string proc addNodes*(n: PRstNode): string -proc getFieldValue*(n: PRstNode, fieldname: string): string +proc getFieldValue*(n: PRstNode, fieldname: string): string {.gcsafe.} proc getArgument*(n: PRstNode): string # ----------------------------- scanner part -------------------------------- @@ -1675,19 +1675,33 @@ proc parseMarkdownCodeblockFields(p: var RstParser): PRstNode = field.add(fieldBody) result.add(field) +proc mayLoadFile(p: RstParser, result: var PRstNode) = + var filename = strip(getFieldValue(result, "file"), + chars = Whitespace + {'"'}) + if filename != "": + if roSandboxDisabled notin p.s.options: + let tok = p.tok[p.idx-2] + rstMessage(p, meSandboxedDirective, "file", tok.line, tok.col) + var path = p.findRelativeFile(filename) + if path == "": rstMessage(p, meCannotOpenFile, filename) + var n = newRstNode(rnLiteralBlock) + n.add newLeaf(readFile(path)) + result.sons[2] = n + proc parseMarkdownCodeblock(p: var RstParser): PRstNode = result = newRstNodeA(p, rnCodeBlock) + result.sons.setLen(3) let line = curLine(p) let baseCol = currentTok(p).col let baseSym = currentTok(p).symbol # usually just ``` inc p.idx result.info = lineInfo(p) var args = newRstNode(rnDirArg) - var fields: PRstNode = nil if currentTok(p).kind == tkWord: args.add(newLeaf(p)) inc p.idx - fields = parseMarkdownCodeblockFields(p) + result.sons[1] = parseMarkdownCodeblockFields(p) + mayLoadFile(p, result) else: args = nil var n = newLeaf("") @@ -1712,11 +1726,11 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = else: n.text.add(currentTok(p).symbol) inc p.idx - var lb = newRstNode(rnLiteralBlock) - lb.add(n) - result.add(args) - result.add(fields) - result.add(lb) + result.sons[0] = args + if result.sons[2] == nil: + var lb = newRstNode(rnLiteralBlock) + lb.add(n) + result.sons[2] = lb proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = var desc, link = "" @@ -1802,9 +1816,12 @@ proc parseFootnoteName(p: var RstParser, reference: bool): PRstNode = p.idx = i proc isMarkdownCodeBlock(p: RstParser): bool = + template allowedSymbol: bool = + (currentTok(p).symbol[0] == '`' or + roPreferMarkdown in p.s.options and currentTok(p).symbol[0] == '~') result = (roSupportMarkdown in p.s.options and currentTok(p).kind in {tkPunct, tkAdornment} and - currentTok(p).symbol[0] == '`' and # tilde ~ is not supported + allowedSymbol and currentTok(p).symbol.len >= 3) proc parseInline(p: var RstParser, father: PRstNode) = @@ -2580,9 +2597,7 @@ proc getColumns(p: RstParser, cols: var RstCols, startIdx: int): int = if p.tok[result].kind == tkIndent: inc result proc checkColumns(p: RstParser, cols: RstCols) = - var - i = p.idx - col = 0 + var i = p.idx if p.tok[i].symbol[0] != '=': rstMessage(p, mwRstStyle, "only tables with `=` columns specification are allowed") @@ -3208,16 +3223,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = ## file. This behaviour is disabled in sandboxed mode and can be re-enabled ## with the `roSandboxDisabled` flag. result = parseDirective(p, rnCodeBlock, {hasArg, hasOptions}, parseLiteralBlock) - var filename = strip(getFieldValue(result, "file")) - if filename != "": - if roSandboxDisabled notin p.s.options: - let tok = p.tok[p.idx-2] - rstMessage(p, meSandboxedDirective, "file", tok.line, tok.col) - var path = p.findRelativeFile(filename) - if path == "": rstMessage(p, meCannotOpenFile, filename) - var n = newRstNode(rnLiteralBlock) - n.add newLeaf(readFile(path)) - result.sons[2] = n + mayLoadFile(p, result) # Extend the field block if we are using our custom Nim extension. if nimExtension: diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 823697336badc..6550a26135988 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -471,21 +471,34 @@ suite "RST parsing": rnLeaf '.' """) + let expectCodeBlock = dedent""" + rnCodeBlock + [nil] + [nil] + rnLiteralBlock + rnLeaf ' + let a = 1 + ```' + """ + test "Markdown code blocks with more > 3 backticks": check(dedent""" ```` let a = 1 ``` - ````""".toAst == - dedent""" - rnCodeBlock - [nil] - [nil] - rnLiteralBlock - rnLeaf ' + ````""".toAst == expectCodeBlock) + + test "Markdown code blocks with ~~~": + check(dedent""" + ~~~ let a = 1 - ```' - """) + ``` + ~~~""".toAst == expectCodeBlock) + check(dedent""" + ~~~~~ + let a = 1 + ``` + ~~~~~""".toAst == expectCodeBlock) test "Markdown code blocks with Nim-specific arguments": check(dedent""" diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 7fae4ba8b68a0..3a9e79bf7d854 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -552,7 +552,7 @@ context1 context2 """ - let output1 = input1.toHtml + let output1 = input1.toHtml(preferRst) doAssert "