Markdown code blocks part 4 (#20189)

No logic was added, just 8 more files have been migrated.
This commit is contained in:
Andrey Makarov 2022-08-12 21:33:43 +03:00 • committed by GitHub
commit 713f39083e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 365 additions and 341 deletions

View file

@ -18,11 +18,11 @@ General Guidelines
* (debatable) In nim sources, for links, prefer ``[link text](link.html)`` to `\`link text<link.html>\`_`:code: * (debatable) In nim sources, for links, prefer ``[link text](link.html)`` to `\`link text<link.html>\`_`:code:
since the syntax is simpler and markdown is more common (likewise, `nim rst2html`:cmd: also supports it in ``rst`` files). since the syntax is simpler and markdown is more common (likewise, `nim rst2html`:cmd: also supports it in ``rst`` files).
.. code-block:: nim ```nim
proc someproc*(s: string, foo: int) = proc someproc*(s: string, foo: int) =
## Use single backticks for inline code, e.g.: `s` or `someExpr(true)`. ## Use single backticks for inline code, e.g.: `s` or `someExpr(true)`.
## Use a backlash to follow with alphanumeric char: `int8`\s are great. ## Use a backlash to follow with alphanumeric char: `int8`\s are great.
```
Module-level documentation Module-level documentation
@ -32,23 +32,24 @@ Documentation of a module is placed at the top of the module itself. Each line o
Sometimes `##[ multiline docs containing code ]##` is preferable, see ``lib/pure/times.nim``. Sometimes `##[ multiline docs containing code ]##` is preferable, see ``lib/pure/times.nim``.
Code samples are encouraged, and should follow the general RST syntax: Code samples are encouraged, and should follow the general RST syntax:
.. code-block:: Nim ````Nim
## The `universe` module computes the answer to life, the universe, and everything. ## The `universe` module computes the answer to life, the universe, and everything.
## ##
## .. code-block:: ## ```
## doAssert computeAnswerString() == 42 ## doAssert computeAnswerString() == 42
## ```
````
Within this top-level comment, you can indicate the authorship and copyright of the code, which will be featured in the produced documentation. Within this top-level comment, you can indicate the authorship and copyright of the code, which will be featured in the produced documentation.
.. code-block:: Nim ```Nim
## This is the best module ever. It provides answers to everything! ## This is the best module ever. It provides answers to everything!
## ##
## :Author: Steve McQueen ## :Author: Steve McQueen
## :Copyright: 1965 ## :Copyright: 1965
## ##
```
Leave a space between the last line of top-level documentation and the beginning of Nim code (the imports, etc.). Leave a space between the last line of top-level documentation and the beginning of Nim code (the imports, etc.).
@ -57,28 +58,29 @@ Procs, Templates, Macros, Converters, and Iterators
The documentation of a procedure should begin with a capital letter and should be in present tense. Variables referenced in the documentation should be surrounded by single tick marks: The documentation of a procedure should begin with a capital letter and should be in present tense. Variables referenced in the documentation should be surrounded by single tick marks:
.. code-block:: Nim ```Nim
proc example1*(x: int) = proc example1*(x: int) =
## Prints the value of `x`. ## Prints the value of `x`.
echo x echo x
```
Whenever an example of usage would be helpful to the user, you should include one within the documentation in RST format as below. Whenever an example of usage would be helpful to the user, you should include one within the documentation in RST format as below.
.. code-block:: Nim ````Nim
proc addThree*(x, y, z: int8): int = proc addThree*(x, y, z: int8): int =
## Adds three `int8` values, treating them as unsigned and ## Adds three `int8` values, treating them as unsigned and
## truncating the result. ## truncating the result.
## ##
## .. code-block:: ## ```
## # things that aren't suitable for a `runnableExamples` go in code-block: ## # things that aren't suitable for a `runnableExamples` go in code-block:
## echo execCmdEx("git pull") ## echo execCmdEx("git pull")
## drawOnScreen() ## drawOnScreen()
## ```
runnableExamples: runnableExamples:
# `runnableExamples` is usually preferred to ``code-block``, when possible. # `runnableExamples` is usually preferred to ``code-block``, when possible.
doAssert addThree(3, 125, 6) == -122 doAssert addThree(3, 125, 6) == -122
result = x +% y +% z result = x +% y +% z
````
The command `nim doc`:cmd: will then correctly syntax highlight the Nim code within the documentation. The command `nim doc`:cmd: will then correctly syntax highlight the Nim code within the documentation.
@ -87,8 +89,7 @@ Types
Exported types should also be documented. This documentation can also contain code samples, but those are better placed with the functions to which they refer. Exported types should also be documented. This documentation can also contain code samples, but those are better placed with the functions to which they refer.
.. code-block:: Nim ```Nim
type type
NamedQueue*[T] = object ## Provides a linked data structure with names NamedQueue*[T] = object ## Provides a linked data structure with names
## throughout. It is named for convenience. I'm making ## throughout. It is named for convenience. I'm making
@ -96,12 +97,12 @@ Exported types should also be documented. This documentation can also contain co
name*: string ## The name of the item name*: string ## The name of the item
val*: T ## Its value val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue next*: ref NamedQueue[T] ## The next item in the queue
```
You have some flexibility when placing the documentation: You have some flexibility when placing the documentation:
.. code-block:: Nim ```Nim
type type
NamedQueue*[T] = object NamedQueue*[T] = object
## Provides a linked data structure with names ## Provides a linked data structure with names
@ -110,11 +111,11 @@ You have some flexibility when placing the documentation:
name*: string ## The name of the item name*: string ## The name of the item
val*: T ## Its value val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue next*: ref NamedQueue[T] ## The next item in the queue
```
Make sure to place the documentation beside or within the object. Make sure to place the documentation beside or within the object.
.. code-block:: Nim ```Nim
type type
## Bad: this documentation disappears because it annotates the `type` keyword ## Bad: this documentation disappears because it annotates the `type` keyword
## above, not `NamedQueue`. ## above, not `NamedQueue`.
@ -123,14 +124,14 @@ Make sure to place the documentation beside or within the object.
## is not what we want. ## is not what we want.
val*: T ## Its value val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue next*: ref NamedQueue[T] ## The next item in the queue
```
Var, Let, and Const Var, Let, and Const
------------------- -------------------
When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the `type` sections. When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the `type` sections.
.. code-block:: Nim ```Nim
const const
X* = 42 ## An awesome number. X* = 42 ## An awesome number.
SpreadArray* = [ SpreadArray* = [
@ -138,25 +139,26 @@ When declaring module-wide constants and values, documentation is encouraged. Th
[2,3,1], [2,3,1],
[3,1,2], [3,1,2],
] ## Doc comment for `SpreadArray`. ] ## Doc comment for `SpreadArray`.
```
Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (`#`). Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (`#`).
.. code-block:: Nim ```Nim
const const
BadMathVals* = [ BadMathVals* = [
3.14, # pi 3.14, # pi
2.72, # e 2.72, # e
0.58, # gamma 0.58, # gamma
] ## A bunch of badly rounded values. ] ## A bunch of badly rounded values.
```
Nim supports Unicode in comments, so the above can be replaced with the following: Nim supports Unicode in comments, so the above can be replaced with the following:
.. code-block:: Nim ```Nim
const const
BadMathVals* = [ BadMathVals* = [
3.14, # π 3.14, # π
2.72, # e 2.72, # e
0.58, # γ 0.58, # γ
] ## A bunch of badly rounded values (including π!). ] ## A bunch of badly rounded values (including π!).
```

View file

@ -22,11 +22,11 @@ DrNim's command-line options are the same as the Nim compiler's.
DrNim currently only checks the sections of your code that are marked DrNim currently only checks the sections of your code that are marked
via `staticBoundChecks: on`: via `staticBoundChecks: on`:
.. code-block:: nim ```nim
{.push staticBoundChecks: on.} {.push staticBoundChecks: on.}
# <--- code section here ----> # <--- code section here ---->
{.pop.} {.pop.}
```
DrNim currently only tries to prove array indexing or subrange checks, DrNim currently only tries to prove array indexing or subrange checks,
overflow errors are *not* prevented. Overflows will be checked for in overflow errors are *not* prevented. Overflows will be checked for in
@ -53,8 +53,7 @@ Motivating Example
The follow example highlights what DrNim can easily do, even The follow example highlights what DrNim can easily do, even
without additional annotations: without additional annotations:
.. code-block:: nim ```nim
{.push staticBoundChecks: on.} {.push staticBoundChecks: on.}
proc sum(a: openArray[int]): int = proc sum(a: openArray[int]): int =
@ -64,6 +63,7 @@ without additional annotations:
{.pop.} {.pop.}
echo sum([1, 2, 3]) echo sum([1, 2, 3])
```
This program contains a famous "index out of bounds" bug. DrNim This program contains a famous "index out of bounds" bug. DrNim
detects it and produces the following error message:: detects it and produces the following error message::
@ -125,8 +125,7 @@ Example: insertionSort
**Note**: This example does not yet work with DrNim. **Note**: This example does not yet work with DrNim.
.. code-block:: nim ```nim
import std / logic import std / logic
proc insertionSort(a: var openArray[int]) {. proc insertionSort(a: var openArray[int]) {.
@ -142,6 +141,7 @@ Example: insertionSort
{.invariant: forall(j in 1..k, i in 0..<j, j == t or a[i] <= a[j]).} {.invariant: forall(j in 1..k, i in 0..<j, j == t or a[i] <= a[j]).}
swap a[t], a[t-1] swap a[t], a[t-1]
dec t dec t
```
Unfortunately, the invariants required to prove that this code is correct take more Unfortunately, the invariants required to prove that this code is correct take more
code than the imperative instructions. However, this effort can be compensated code than the imperative instructions. However, this effort can be compensated
@ -155,14 +155,14 @@ This is required, but not sufficient to describe that a `sort` operation
was performed. For example, the same postcondition is true for this proc was performed. For example, the same postcondition is true for this proc
which doesn't sort at all: which doesn't sort at all:
.. code-block:: nim ```nim
import std / logic import std / logic
proc insertionSort(a: var openArray[int]) {. proc insertionSort(a: var openArray[int]) {.
ensures: forall(i in 1..<a.len, a[i-1] <= a[i]).} = ensures: forall(i in 1..<a.len, a[i-1] <= a[i]).} =
# does not sort, overwrites `a`'s contents! # does not sort, overwrites `a`'s contents!
for i in 0..<a.len: a[i] = i for i in 0..<a.len: a[i] = i
```

View file

@ -13,11 +13,12 @@ difficult is the ``newString`` proc: If it is simply wrapped, it
should not be evaluated at compile time! On other occasions it can should not be evaluated at compile time! On other occasions it can
and should be evaluated: and should be evaluated:
.. code-block:: nim ```nim
proc toUpper(s: string): string = proc toUpper(s: string): string =
result = newString(len(s)) result = newString(len(s))
for i in 0..len(s) - 1: for i in 0..len(s) - 1:
result[i] = toUpper(s[i]) result[i] = toUpper(s[i])
```
No, it really can always be evaluated. The code generator should transform No, it really can always be evaluated. The code generator should transform
``s = "\0\0\0..."`` back into ``s = newString(...)``. ``s = "\0\0\0..."`` back into ``s = newString(...)``.

View file

@ -41,10 +41,11 @@ recognize it as Nim source file).
If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf` If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf`
In your `main.nim`: In your `main.nim`:
.. code-block:: nim ```nim
include "xmlGen.nimf" include "xmlGen.nimf"
echo generateXML("John Smith","42") echo generateXML("John Smith","42")
```
Pipe operator Pipe operator
============= =============
@ -150,7 +151,7 @@ Example::
The filter transforms this into: The filter transforms this into:
.. code-block:: nim ```nim
proc generateHTMLPage(title, currentTab, content: string, proc generateHTMLPage(title, currentTab, content: string,
tabs: openArray[string]): string = tabs: openArray[string]): string =
result = "" result = ""
@ -173,6 +174,7 @@ The filter transforms this into:
" A dollar: $.\n" & " A dollar: $.\n" &
" </div>\n" & " </div>\n" &
"</body>\n") "</body>\n")
```
Each line that does not start with the meta character (ignoring leading Each line that does not start with the meta character (ignoring leading

View file

@ -26,8 +26,7 @@ code when `F9` is pressed. The important lines are marked with `#***`.
To install SDL2 you can use `nimble install sdl2`:cmd:. To install SDL2 you can use `nimble install sdl2`:cmd:.
.. code-block:: nim ```nim
# logic.nim # logic.nim
import sdl2 import sdl2
@ -83,10 +82,10 @@ To install SDL2 you can use `nimble install sdl2`:cmd:.
discard renderer.fillRect(rect) discard renderer.fillRect(rect)
delay(16) delay(16)
renderer.present() renderer.present()
```
.. code-block:: nim ```nim
# mymain.nim # mymain.nim
import logic import logic
@ -97,6 +96,7 @@ To install SDL2 you can use `nimble install sdl2`:cmd:.
destroy() destroy()
main() main()
```
Compile this example via: Compile this example via:
@ -107,12 +107,13 @@ Compile this example via:
Now start the program and KEEP it running! Now start the program and KEEP it running!
.. code:: cmd ```cmd
# Unix: # Unix:
mymain & mymain &
# or Windows (click on the .exe) # or Windows (click on the .exe)
mymain.exe mymain.exe
# edit # edit
```
For example, change the line: For example, change the line:
@ -146,7 +147,7 @@ One can use the special event handlers `beforeCodeReload` and
`afterCodeReload` to reset the state of a particular variable or to force `afterCodeReload` to reset the state of a particular variable or to force
the execution of certain statements: the execution of certain statements:
.. code-block:: Nim ```Nim
var var
settings = initTable[string, string]() settings = initTable[string, string]()
lastReload: Time lastReload: Time
@ -159,6 +160,7 @@ the execution of certain statements:
afterCodeReload: afterCodeReload:
lastReload = now() lastReload = now()
resetProgramState() resetProgramState()
```
On each code reload, Nim will first execute all `beforeCodeReload`:idx: On each code reload, Nim will first execute all `beforeCodeReload`:idx:
handlers registered in the previous version of the program and then all handlers registered in the previous version of the program and then all
@ -167,7 +169,7 @@ that any handlers appearing in modules that weren't reloaded will also be
executed. To prevent this behavior, one can guard the code with the executed. To prevent this behavior, one can guard the code with the
`hasModuleChanged()`:idx: API: `hasModuleChanged()`:idx: API:
.. code-block:: Nim ```Nim
import mydb import mydb
var myCache = initTable[Key, Value]() var myCache = initTable[Key, Value]()
@ -175,6 +177,7 @@ executed. To prevent this behavior, one can guard the code with the
afterCodeReload: afterCodeReload:
if hasModuleChanged(mydb): if hasModuleChanged(mydb):
resetCache(myCache) resetCache(myCache)
```
The hot code reloading is based on dynamic library hot swapping in the native The hot code reloading is based on dynamic library hot swapping in the native
targets and direct manipulation of the global namespace in the JavaScript targets and direct manipulation of the global namespace in the JavaScript
@ -203,8 +206,7 @@ runtime demands of the example code above. An example of compiling
``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed ``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed
with choosenim follows. with choosenim follows.
.. code:: console ```console
# Unix/MacOS # Unix/MacOS
# Make sure you are in the directory containing your .nim files # Make sure you are in the directory containing your .nim files
$ cd your-source-directory $ cd your-source-directory
@ -215,6 +217,7 @@ with choosenim follows.
# verify that you have two files named libnimhcr and libnimrtl in your # verify that you have two files named libnimhcr and libnimrtl in your
# source directory (.dll for Windows, .so for Unix, .dylib for MacOS) # source directory (.dll for Windows, .so for Unix, .dylib for MacOS)
```
All modules of the project will be compiled to separate dynamic link All modules of the project will be compiled to separate dynamic link
libraries placed in the `nimcache` directory. Please note that during libraries placed in the `nimcache` directory. Please note that during

View file

@ -10,10 +10,7 @@
.. contents:: .. contents::
.. raw:: html > "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
<blockquote><p>
"yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
</p></blockquote>
Note: this is mostly outdated, see instead `nimsuggest <nimsuggest.html>`_ Note: this is mostly outdated, see instead `nimsuggest <nimsuggest.html>`_
@ -246,11 +243,12 @@ skConst
| **Fourth column**: the type of the const value. | **Fourth column**: the type of the const value.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
const SOME_SEQUENCE = @[1, 2] const SOME_SEQUENCE = @[1, 2]
--> col 2: $MODULE.SOME_SEQUENCE --> col 2: $MODULE.SOME_SEQUENCE
col 3: seq[int] col 3: seq[int]
col 7: "" col 7: ""
```
skEnumField skEnumField
@ -260,11 +258,12 @@ skEnumField
| **Fourth column**: enum type grouping other enum fields. | **Fourth column**: enum type grouping other enum fields.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
Open(filename, fmWrite) Open(filename, fmWrite)
--> col 2: system.FileMode.fmWrite --> col 2: system.FileMode.fmWrite
col 3: FileMode col 3: FileMode
col 7: "" col 7: ""
```
skForVar skForVar
@ -274,13 +273,14 @@ skForVar
| **Fourth column**: type of the var. | **Fourth column**: type of the var.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc looper(filename = "tests.nim") = proc looper(filename = "tests.nim") =
for letter in filename: for letter in filename:
echo letter echo letter
--> col 2: $MODULE.looper.letter --> col 2: $MODULE.looper.letter
col 3: char col 3: char
col 7: "" col 7: ""
```
skIterator, skClosureIterator skIterator, skClosureIterator
@ -295,13 +295,14 @@ posterior instances of the iterator.
| **Fourth column**: signature of the iterator including return type. | **Fourth column**: signature of the iterator including return type.
| **Docstring**: docstring if available. | **Docstring**: docstring if available.
.. code-block:: nim ```nim
let let
text = "some text" text = "some text"
letters = toSeq(runes(text)) letters = toSeq(runes(text))
--> col 2: unicode.runes --> col 2: unicode.runes
col 3: iterator (string): Rune col 3: iterator (string): Rune
col 7: "iterates over any unicode character of the string `s`." col 7: "iterates over any unicode character of the string `s`."
```
skLabel skLabel
@ -311,13 +312,14 @@ skLabel
| **Fourth column**: always the empty string. | **Fourth column**: always the empty string.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc test(text: string) = proc test(text: string) =
var found = -1 var found = -1
block loops: block loops:
--> col 2: $MODULE.test.loops --> col 2: $MODULE.test.loops
col 3: "" col 3: ""
col 7: "" col 7: ""
```
skLet skLet
@ -327,12 +329,13 @@ skLet
| **Fourth column**: the type of the let variable. | **Fourth column**: the type of the let variable.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
let let
text = "some text" text = "some text"
--> col 2: $MODULE.text --> col 2: $MODULE.text
col 3: string col 3: string
col 7: "" col 7: ""
```
skMacro skMacro
@ -347,12 +350,13 @@ posterior instances of the macro.
| **Fourth column**: signature of the macro including return type. | **Fourth column**: signature of the macro including return type.
| **Docstring**: docstring if available. | **Docstring**: docstring if available.
.. code-block:: nim ```nim
proc testMacro() = proc testMacro() =
expect(EArithmetic): expect(EArithmetic):
--> col 2: idetools_api.expect --> col 2: idetools_api.expect
col 3: proc (varargs[expr], stmt): stmt col 3: proc (varargs[expr], stmt): stmt
col 7: "" col 7: ""
```
skMethod skMethod
@ -384,7 +388,7 @@ This may change in the future.
| **Fourth column**: signature of the method including return type. | **Fourth column**: signature of the method including return type.
| **Docstring**: docstring if available. | **Docstring**: docstring if available.
.. code-block:: nim ```nim
method eval(e: PExpr): int = quit "to override!" method eval(e: PExpr): int = quit "to override!"
method eval(e: PLiteral): int = e.x method eval(e: PLiteral): int = e.x
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b) method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
@ -392,6 +396,7 @@ This may change in the future.
--> col 2: $MODULE.eval --> col 2: $MODULE.eval
col 3: proc (PPlusExpr): int col 3: proc (PPlusExpr): int
col 7: "" col 7: ""
```
skParam skParam
@ -401,12 +406,13 @@ skParam
| **Fourth column**: the type of the parameter. | **Fourth column**: the type of the parameter.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc reader(filename = "tests.nim") = proc reader(filename = "tests.nim") =
let text = readFile(filename) let text = readFile(filename)
--> col 2: $MODULE.reader.filename --> col 2: $MODULE.reader.filename
col 3: string col 3: string
col 7: "" col 7: ""
```
skProc skProc
@ -425,7 +431,7 @@ returned by idetools returns also the pragmas for the proc.
| **Fourth column**: signature of the proc including return type. | **Fourth column**: signature of the proc including return type.
| **Docstring**: docstring if available. | **Docstring**: docstring if available.
.. code-block:: nim ```nim
open(filename, fmWrite) open(filename, fmWrite)
--> col 2: system.Open --> col 2: system.Open
col 3: proc (var File, string, FileMode, int): bool col 3: proc (var File, string, FileMode, int): bool
@ -434,6 +440,7 @@ returned by idetools returns also the pragmas for the proc.
Default mode is readonly. Returns true iff the file could be opened. Default mode is readonly. Returns true iff the file could be opened.
This throws no exception if the file could not be opened." This throws no exception if the file could not be opened."
```
skResult skResult
@ -443,12 +450,13 @@ skResult
| **Fourth column**: the type of the result. | **Fourth column**: the type of the result.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc getRandomValue() : int = proc getRandomValue() : int =
return 4 return 4
--> col 2: $MODULE.getRandomValue.result --> col 2: $MODULE.getRandomValue.result
col 3: int col 3: int
col 7: "" col 7: ""
```
skTemplate skTemplate
@ -463,7 +471,7 @@ posterior instances of the template.
| **Fourth column**: signature of the template including return type. | **Fourth column**: signature of the template including return type.
| **Docstring**: docstring if available. | **Docstring**: docstring if available.
.. code-block:: nim `````nim
let let
text = "some text" text = "some text"
letters = toSeq(runes(text)) letters = toSeq(runes(text))
@ -474,13 +482,15 @@ posterior instances of the template.
Example: Example:
.. code-block:: nim ```nim
let let
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = toSeq(filter(numeric) do (x: int) -> bool: odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
if x mod 2 == 1: if x mod 2 == 1:
result = true) result = true)
assert odd_numbers == @[1, 3, 5, 7, 9]" assert odd_numbers == @[1, 3, 5, 7, 9]"
```
`````
skType skType
@ -490,12 +500,13 @@ skType
| **Fourth column**: the type. | **Fourth column**: the type.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc writeTempFile() = proc writeTempFile() =
var output: File var output: File
--> col 2: system.File --> col 2: system.File
col 3: File col 3: File
col 7: "" col 7: ""
```
skVar skVar
@ -505,7 +516,7 @@ skVar
| **Fourth column**: the type of the var. | **Fourth column**: the type of the var.
| **Docstring**: always the empty string. | **Docstring**: always the empty string.
.. code-block:: nim ```nim
proc writeTempFile() = proc writeTempFile() =
var output: File var output: File
output.open("/tmp/somefile", fmWrite) output.open("/tmp/somefile", fmWrite)
@ -513,6 +524,7 @@ skVar
--> col 2: $MODULE.writeTempFile.output --> col 2: $MODULE.writeTempFile.output
col 3: File col 3: File
col 7: "" col 7: ""
```
Test suite Test suite

View file

@ -42,25 +42,25 @@ Bootstrapping the compiler
Compiling the compiler is a simple matter of running: Compiling the compiler is a simple matter of running:
.. code:: cmd ```cmd
nim c koch.nim nim c koch.nim
koch boot -d:release koch boot -d:release
```
For a debug version use: For a debug version use:
.. code:: cmd ```cmd
nim c koch.nim nim c koch.nim
koch boot koch boot
```
And for a debug version compatible with GDB: And for a debug version compatible with GDB:
.. code:: cmd ```cmd
nim c koch.nim nim c koch.nim
koch boot --debuginfo --linedir:on koch boot --debuginfo --linedir:on
```
The `koch`:cmd: program is Nim's maintenance script. It is a replacement for The `koch`:cmd: program is Nim's maintenance script. It is a replacement for
make and shell scripting with the advantage that it is much more portable. make and shell scripting with the advantage that it is much more portable.
@ -73,10 +73,10 @@ Reproducible builds
Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable. Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable.
.. code:: cmd ```cmd
export SOURCE_DATE_EPOCH=$(git log -n 1 --format=%at) export SOURCE_DATE_EPOCH=$(git log -n 1 --format=%at)
koch boot # or `./build_all.sh` koch boot # or `./build_all.sh`
```
Debugging the compiler Debugging the compiler
@ -98,10 +98,10 @@ focus on the changes introduced by that one specific commit.
compilation fails. This exit code tells `git bisect`:cmd: to skip the compilation fails. This exit code tells `git bisect`:cmd: to skip the
current commit: current commit:
.. code:: cmd ```cmd
git bisect start bad-commit good-commit git bisect start bad-commit good-commit
git bisect run ./koch temp -r c test-source.nim git bisect run ./koch temp -r c test-source.nim
```
You can also bisect using custom options to build the compiler, for example if You can also bisect using custom options to build the compiler, for example if
you don't need a debug version of the compiler (which runs slower), you can replace you don't need a debug version of the compiler (which runs slower), you can replace
@ -141,8 +141,7 @@ enabled. Here are compiler options that are of interest when debugging:
Another method to build and run the compiler is directly through `koch`:cmd:\: Another method to build and run the compiler is directly through `koch`:cmd:\:
.. code:: cmd ```cmd
koch temp [options] c test.nim koch temp [options] c test.nim
# (will build with js support) # (will build with js support)
@ -150,6 +149,7 @@ Another method to build and run the compiler is directly through `koch`:cmd:\:
# (will build with doc support) # (will build with doc support)
koch temp [options] doc test.nim koch temp [options] doc test.nim
```
Debug logging Debug logging
------------- -------------
@ -166,17 +166,16 @@ is being used. One very common way to achieve this is to use the `mdbg` conditio
which will be true only in contexts, processing expressions and statements from which will be true only in contexts, processing expressions and statements from
the currently compiled main module: the currently compiled main module:
.. code-block:: nim ```nim
# inside some compiler module # inside some compiler module
if mdbg: if mdbg:
debug someAstNode debug someAstNode
```
Using the `isCompilerDebug`:nim: condition along with inserting some statements Using the `isCompilerDebug`:nim: condition along with inserting some statements
into the testcase provides more granular logging: into the testcase provides more granular logging:
.. code-block:: nim ```nim
# compilermodule.nim # compilermodule.nim
if isCompilerDebug(): if isCompilerDebug():
debug someAstNode debug someAstNode
@ -186,21 +185,21 @@ into the testcase provides more granular logging:
{.define(nimCompilerDebug).} {.define(nimCompilerDebug).}
let a = 2.5 * 3 let a = 2.5 * 3
{.undef(nimCompilerDebug).} {.undef(nimCompilerDebug).}
```
Logging can also be scoped to a specific filename as well. This will of course Logging can also be scoped to a specific filename as well. This will of course
match against every module with that name. match against every module with that name.
.. code-block:: nim ```nim
if `??`(conf, n.info, "module.nim"): if `??`(conf, n.info, "module.nim"):
debug(n) debug(n)
```
The above examples also makes use of the `debug`:nim: proc, which is able to The above examples also makes use of the `debug`:nim: proc, which is able to
print a human-readable form of an arbitrary AST tree. Other common ways to print print a human-readable form of an arbitrary AST tree. Other common ways to print
information about the internal compiler types include: information about the internal compiler types include:
.. code-block:: nim ```nim
# pretty print PNode # pretty print PNode
# pretty prints the Nim ast # pretty prints the Nim ast
@ -246,23 +245,24 @@ information about the internal compiler types include:
# print the structure of any type # print the structure of any type
repr(someVar) repr(someVar)
```
Here are some other helpful utilities: Here are some other helpful utilities:
.. code-block:: nim ```nim
# how did execution reach this location? # how did execution reach this location?
writeStackTrace() writeStackTrace()
```
These procs may not already be imported by the module you're editing. These procs may not already be imported by the module you're editing.
You can import them directly for debugging: You can import them directly for debugging:
.. code-block:: nim ```nim
from astalgo import debug from astalgo import debug
from types import typeToString from types import typeToString
from renderer import renderTree from renderer import renderTree
from msgs import `??` from msgs import `??`
```
Native debugging Native debugging
---------------- ----------------
@ -280,12 +280,12 @@ and `exitingDebugSection()`:nim:.
* LLDB execute `command source tools/compiler.lldb` at startup * LLDB execute `command source tools/compiler.lldb` at startup
#. Use one of the scoping helpers like so: #. Use one of the scoping helpers like so:
.. code-block:: nim ```nim
if isCompilerDebug(): if isCompilerDebug():
enteringDebugSection() enteringDebugSection()
else: else:
exitingDebugSection() exitingDebugSection()
```
A caveat of this method is that all breakpoints and watchpoints are enabled or A caveat of this method is that all breakpoints and watchpoints are enabled or
disabled. Also, due to a bug, only breakpoints can be constrained for LLDB. disabled. Also, due to a bug, only breakpoints can be constrained for LLDB.
@ -448,8 +448,9 @@ Tests with GCC on Amd64 showed that it's really beneficial if the
Proper thunk generation is harder because the proc that is to wrap Proper thunk generation is harder because the proc that is to wrap
could stem from a complex expression: could stem from a complex expression:
.. code-block:: nim ```nim
receivesClosure(returnsDefaultCC[i]) receivesClosure(returnsDefaultCC[i])
```
A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require
an *additional* closure generation... Ok, not really, but it requires to pass an *additional* closure generation... Ok, not really, but it requires to pass
@ -460,17 +461,18 @@ to pass a proc pointer around via a generic `ref` type.
Example code: Example code:
.. code-block:: nim ```nim
proc add(x: int): proc (y: int): int {.closure.} = proc add(x: int): proc (y: int): int {.closure.} =
return proc (y: int): int = return proc (y: int): int =
return x + y return x + y
var add2 = add(2) var add2 = add(2)
echo add2(5) #OUT 7 echo add2(5) #OUT 7
```
This should produce roughly this code: This should produce roughly this code:
.. code-block:: nim ```nim
type type
Env = ref object Env = ref object
x: int # data x: int # data
@ -487,11 +489,12 @@ This should produce roughly this code:
var add2 = add(2) var add2 = add(2)
let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data) let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data)
echo tmp echo tmp
```
Beware of nesting: Beware of nesting:
.. code-block:: nim ```nim
proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} =
return lambda (y: int): proc (z: int): int {.closure.} = return lambda (y: int): proc (z: int): int {.closure.} =
return lambda (z: int): int = return lambda (z: int): int =
@ -499,10 +502,11 @@ Beware of nesting:
var add24 = add(2)(4) var add24 = add(2)(4)
echo add24(5) #OUT 11 echo add24(5) #OUT 11
```
This should produce roughly this code: This should produce roughly this code:
.. code-block:: nim ```nim
type type
EnvX = ref object EnvX = ref object
x: int # data x: int # data
@ -530,6 +534,7 @@ This should produce roughly this code:
var tmp2 = tmp.fn(4, tmp.data) var tmp2 = tmp.fn(4, tmp.data)
var add24 = tmp2.fn(4, tmp2.data) var add24 = tmp2.fn(4, tmp2.data)
echo add24(5) echo add24(5)
```
We could get rid of nesting environments by always inlining inner anon procs. We could get rid of nesting environments by always inlining inner anon procs.
@ -540,8 +545,7 @@ however.
Accumulator Accumulator
----------- -----------
.. code-block:: nim ```nim
proc getAccumulator(start: int): proc (): int {.closure} = proc getAccumulator(start: int): proc (): int {.closure} =
var i = start var i = start
return lambda: int = return lambda: int =
@ -560,6 +564,7 @@ Accumulator
var a = accumulator(3) var a = accumulator(3)
var b = accumulator(4) var b = accumulator(4)
echo a() + b() echo a() + b()
```
Internals Internals
@ -614,8 +619,7 @@ keeps the full `int literal(321)` type. Here is an example where that
difference matters. difference matters.
.. code-block:: nim ```nim
proc foo(arg: int8) = proc foo(arg: int8) =
echo "def" echo "def"
@ -624,14 +628,14 @@ difference matters.
let tmp2 = 123 let tmp2 = 123
foo(tmp2) # Error foo(tmp2) # Error
```
In a context with multiple overloads, the integer literal kind will In a context with multiple overloads, the integer literal kind will
always prefer the `int` type over all other types. If none of the always prefer the `int` type over all other types. If none of the
overloads is of type `int`, then there will be an error because of overloads is of type `int`, then there will be an error because of
ambiguity. ambiguity.
.. code-block:: nim ```nim
proc foo(arg: int) = proc foo(arg: int) =
echo "abc" echo "abc"
proc foo(arg: int8) = proc foo(arg: int8) =
@ -644,6 +648,7 @@ ambiguity.
echo "def" echo "def"
bar(123) # Error ambiguous call bar(123) # Error ambiguous call
```
In the compiler these integer literal types are represented with the In the compiler these integer literal types are represented with the
node kind `nkIntLit`, type kind `tyInt` and the member `n` of the type node kind `nkIntLit`, type kind `tyInt` and the member `n` of the type

View file

@ -8,10 +8,7 @@
.. include:: rstcommon.rst .. include:: rstcommon.rst
.. contents:: .. contents::
.. raw:: html > "A great chef is an artist that I truly respect" -- Robert Stack.
<blockquote><p>
"A great chef is an artist that I truly respect" -- Robert Stack.
</p></blockquote>
Introduction Introduction

View file

@ -30,17 +30,16 @@ The `void` type denotes the absence of any type. Parameters of
type `void` are treated as non-existent, `void` as a return type means that type `void` are treated as non-existent, `void` as a return type means that
the procedure does not return a value: the procedure does not return a value:
.. code-block:: nim ```nim
proc nothing(x, y: void): void = proc nothing(x, y: void): void =
echo "ha" echo "ha"
nothing() # writes "ha" to stdout nothing() # writes "ha" to stdout
```
The `void` type is particularly useful for generic code: The `void` type is particularly useful for generic code:
.. code-block:: nim ```nim
proc callProc[T](p: proc (x: T), x: T) = proc callProc[T](p: proc (x: T), x: T) =
when T is void: when T is void:
p() p()
@ -52,15 +51,16 @@ The `void` type is particularly useful for generic code:
callProc[int](intProc, 12) callProc[int](intProc, 12)
callProc[void](emptyProc) callProc[void](emptyProc)
```
However, a `void` type cannot be inferred in generic code: However, a `void` type cannot be inferred in generic code:
.. code-block:: nim ```nim
callProc(emptyProc) callProc(emptyProc)
# Error: type mismatch: got (proc ()) # Error: type mismatch: got (proc ())
# but expected one of: # but expected one of:
# callProc(p: proc (T), x: T) # callProc(p: proc (T), x: T)
```
The `void` type is only valid for parameters and return types; other symbols The `void` type is only valid for parameters and return types; other symbols
cannot have the type `void`. cannot have the type `void`.
@ -97,9 +97,7 @@ to a choice between `T.foo` and `U.foo`. During overload resolution,
the correct type of `foo` is decided from the context. If the type of `foo` is the correct type of `foo` is decided from the context. If the type of `foo` is
ambiguous, a static error will be produced. ambiguous, a static error will be produced.
.. code-block:: nim ```nim test = "nim c $1"
:test: "nim c $1"
{.experimental: "overloadableEnums".} {.experimental: "overloadableEnums".}
type type
@ -124,6 +122,7 @@ ambiguous, a static error will be produced.
of value2: echo "B" of value2: echo "B"
p value2 p value2
```
Package level objects Package level objects
@ -144,8 +143,7 @@ available.
Example: Example:
.. code-block:: nim ```nim
# module A (in an arbitrary package) # module A (in an arbitrary package)
type type
Pack.SomeObject = object # declare as incomplete object of package 'Pack' Pack.SomeObject = object # declare as incomplete object of package 'Pack'
@ -154,15 +152,16 @@ Example:
# Incomplete objects can be used as parameters: # Incomplete objects can be used as parameters:
proc myproc(x: SomeObject) = discard proc myproc(x: SomeObject) = discard
```
.. code-block:: nim ```nim
# module B (in package "Pack") # module B (in package "Pack")
type type
SomeObject* {.package.} = object # Use 'package' to complete the object SomeObject* {.package.} = object # Use 'package' to complete the object
s, t: string s, t: string
x, y: int x, y: int
```
This feature will likely be superseded in the future by support for This feature will likely be superseded in the future by support for
recursive module dependencies. recursive module dependencies.
@ -223,8 +222,7 @@ preface definitions inside a module.
Example: Example:
.. code-block:: nim ```nim
{.experimental: "codeReordering".} {.experimental: "codeReordering".}
proc foo(x: int) = proc foo(x: int) =
@ -234,14 +232,14 @@ Example:
echo(x) echo(x)
foo(10) foo(10)
```
Variables can also be reordered as well. Variables that are *initialized* (i.e. Variables can also be reordered as well. Variables that are *initialized* (i.e.
variables that have their declaration and assignment combined in a single variables that have their declaration and assignment combined in a single
statement) can have their entire initialization statement reordered. Be wary of statement) can have their entire initialization statement reordered. Be wary of
what code is executed at the top level: what code is executed at the top level:
.. code-block:: nim ```nim
{.experimental: "codeReordering".} {.experimental: "codeReordering".}
proc a() = proc a() =
@ -250,6 +248,7 @@ what code is executed at the top level:
var foo = 5 var foo = 5
a() # outputs: "5" a() # outputs: "5"
```
.. ..
TODO: Let's table this for now. This is an *experimental feature* and so the TODO: Let's table this for now. This is an *experimental feature* and so the
@ -260,8 +259,7 @@ what code is executed at the top level:
code reordering process, and not after. As an example, the output of this code reordering process, and not after. As an example, the output of this
code is the same as it would be with code reordering disabled. code is the same as it would be with code reordering disabled.
.. code-block:: nim ```nim
{.experimental: "codeReordering".} {.experimental: "codeReordering".}
proc x() = proc x() =
@ -270,12 +268,12 @@ what code is executed at the top level:
var foo = 4 var foo = 4
x() # "false" x() # "false"
```
It is important to note that reordering *only* works for symbols at top level It is important to note that reordering *only* works for symbols at top level
scope. Therefore, the following will *fail to compile:* scope. Therefore, the following will *fail to compile:*
.. code-block:: nim ```nim
{.experimental: "codeReordering".} {.experimental: "codeReordering".}
proc a() = proc a() =
@ -284,6 +282,7 @@ scope. Therefore, the following will *fail to compile:*
echo("Hello!") echo("Hello!")
a() a()
```
This feature will likely be replaced with a better solution to remove This feature will likely be replaced with a better solution to remove
the need for forward declarations. the need for forward declarations.
@ -295,8 +294,7 @@ Automatic dereferencing
Automatic dereferencing is performed for the first argument of a routine call. Automatic dereferencing is performed for the first argument of a routine call.
This feature has to be enabled via `{.experimental: "implicitDeref".}`: This feature has to be enabled via `{.experimental: "implicitDeref".}`:
.. code-block:: nim ```nim
{.experimental: "implicitDeref".} {.experimental: "implicitDeref".}
type type
@ -309,6 +307,7 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`:
let n = Node() let n = Node()
echo n.depth echo n.depth
# no need to write n[].depth # no need to write n[].depth
```
Special Operators Special Operators
@ -333,21 +332,21 @@ for a dot operator that can be matched against a re-written form of
the expression, where the unknown field or proc name is passed to the expression, where the unknown field or proc name is passed to
an `untyped` parameter: an `untyped` parameter:
.. code-block:: nim ```nim
a.b # becomes `.`(a, b) a.b # becomes `.`(a, b)
a.b(c, d) # becomes `.`(a, b, c, d) a.b(c, d) # becomes `.`(a, b, c, d)
```
The matched dot operators can be symbols of any callable kind (procs, The matched dot operators can be symbols of any callable kind (procs,
templates and macros), depending on the desired effect: templates and macros), depending on the desired effect:
.. code-block:: nim ```nim
template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)] template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)]
var js = parseJson("{ x: 1, y: 2}") var js = parseJson("{ x: 1, y: 2}")
echo js.x # outputs 1 echo js.x # outputs 1
echo js.y # outputs 2 echo js.y # outputs 2
```
The following dot operators are available: The following dot operators are available:
@ -366,9 +365,9 @@ operator `.=`
------------- -------------
This operator will be matched against assignments to missing fields. This operator will be matched against assignments to missing fields.
.. code-block:: nim ```nim
a.b = c # becomes `.=`(a, b, c) a.b = c # becomes `.=`(a, b, c)
```
Call operator Call operator
------------- -------------
@ -377,8 +376,7 @@ precedence over dot operators, however it does not match missing overloads
for existing routines. The experimental `callOperator` switch must be enabled for existing routines. The experimental `callOperator` switch must be enabled
to use this operator. to use this operator.
.. code-block:: nim ```nim
{.experimental: "callOperator".} {.experimental: "callOperator".}
template `()`(a: int, b: float): untyped = $(a, b) template `()`(a: int, b: float): untyped = $(a, b)
@ -402,6 +400,7 @@ to use this operator.
doAssert not compiles(a.b(c)) # gives a type mismatch error same as b(a, c) doAssert not compiles(a.b(c)) # gives a type mismatch error same as b(a, c)
doAssert (a.b)(c) == `()`(a.b, c) doAssert (a.b)(c) == `()`(a.b, c)
```
Extended macro pragmas Extended macro pragmas
@ -412,9 +411,10 @@ can also be applied to type, variable and constant declarations.
For types: For types:
.. code-block:: nim ```nim
type type
MyObject {.schema: "schema.protobuf".} = object MyObject {.schema: "schema.protobuf".} = object
```
This is translated to a call to the `schema` macro with a `nnkTypeDef` This is translated to a call to the `schema` macro with a `nnkTypeDef`
AST node capturing the left-hand side, remaining pragmas and the right-hand AST node capturing the left-hand side, remaining pragmas and the right-hand
@ -437,19 +437,21 @@ For variables and constants, it is largely the same, except a unary node with
the same kind as the section containing a single definition is passed to macros, the same kind as the section containing a single definition is passed to macros,
and macros can return any expression. and macros can return any expression.
.. code-block:: nim ```nim
var var
a = ... a = ...
b {.importc, foo, nodecl.} = ... b {.importc, foo, nodecl.} = ...
c = ... c = ...
```
Assuming `foo` is a macro or a template, this is roughly equivalent to: Assuming `foo` is a macro or a template, this is roughly equivalent to:
.. code-block:: nim ```nim
var a = ... var a = ...
foo: foo:
var b {.importc, nodecl.} = ... var b {.importc, nodecl.} = ...
var c = ... var c = ...
```
Symbols as template/macro calls Symbols as template/macro calls
@ -459,7 +461,7 @@ Templates and macros that take no arguments can be called as lone symbols,
i.e. without parentheses. This is useful for repeated uses of complex i.e. without parentheses. This is useful for repeated uses of complex
expressions that cannot conveniently be represented as runtime values. expressions that cannot conveniently be represented as runtime values.
.. code-block:: nim ```nim
type Foo = object type Foo = object
bar: int bar: int
@ -468,6 +470,7 @@ expressions that cannot conveniently be represented as runtime values.
assert bar == 10 assert bar == 10
bar = 15 bar = 15
assert bar == 15 assert bar == 15
```
In the future, this may require more specific information on template or macro In the future, this may require more specific information on template or macro
signatures to be used. Specializations for some applications of this may also signatures to be used. Specializations for some applications of this may also
@ -483,8 +486,7 @@ Not nil annotation
All types for which `nil` is a valid value can be annotated with the All types for which `nil` is a valid value can be annotated with the
`not nil` annotation to exclude `nil` as a valid value: `not nil` annotation to exclude `nil` as a valid value:
.. code-block:: nim ```nim
{.experimental: "notnil".} {.experimental: "notnil".}
type type
@ -500,6 +502,7 @@ All types for which `nil` is a valid value can be annotated with the
# and also this: # and also this:
var x: PObject var x: PObject
p(x) p(x)
```
The compiler ensures that every code path initializes variables which contain The compiler ensures that every code path initializes variables which contain
non-nilable pointers. The details of this analysis are still to be specified non-nilable pointers. The details of this analysis are still to be specified
@ -545,8 +548,7 @@ via a parameter that is not declared as a `var` parameter.
For example: For example:
.. code-block:: nim ```nim
{.experimental: "strictFuncs".} {.experimental: "strictFuncs".}
type type
@ -566,6 +568,7 @@ For example:
m.data = "yeah" # the mutation is here m.data = "yeah" # the mutation is here
# Error: 'mut' can have side effects # Error: 'mut' can have side effects
# an object reachable from 'n' is potentially mutated # an object reachable from 'n' is potentially mutated
```
The algorithm behind this analysis is described in The algorithm behind this analysis is described in
@ -585,23 +588,23 @@ A view type is a type that is or contains one of the following types:
For example: For example:
.. code-block:: nim ```nim
type type
View1 = openArray[byte] View1 = openArray[byte]
View2 = lent string View2 = lent string
View3 = Table[openArray[char], int] View3 = Table[openArray[char], int]
```
Exceptions to this rule are types constructed via `ptr` or `proc`. Exceptions to this rule are types constructed via `ptr` or `proc`.
For example, the following types are **not** view types: For example, the following types are **not** view types:
.. code-block:: nim ```nim
type type
NotView1 = proc (x: openArray[int]) NotView1 = proc (x: openArray[int])
NotView2 = ptr openArray[char] NotView2 = ptr openArray[char]
NotView3 = ptr array[4, lent int] NotView3 = ptr array[4, lent int]
```
The mutability aspect of a view type is not part of the type but part The mutability aspect of a view type is not part of the type but part
@ -618,8 +621,7 @@ it was borrowed from.
For example: For example:
.. code-block:: nim ```nim
{.experimental: "views".} {.experimental: "views".}
proc take(a: openArray[int]) = proc take(a: openArray[int]) =
@ -641,6 +643,7 @@ For example:
main(@[11, 22, 33]) main(@[11, 22, 33])
```
A local variable of a view type can borrow from a location A local variable of a view type can borrow from a location
@ -699,8 +702,7 @@ For the duration of the borrow operation, no mutations to the borrowed locations
may be performed except via the view that borrowed from the may be performed except via the view that borrowed from the
location. The borrowed location is said to be *sealed* during the borrow. location. The borrowed location is said to be *sealed* during the borrow.
.. code-block:: nim ```nim
{.experimental: "views".} {.experimental: "views".}
type type
@ -711,16 +713,17 @@ location. The borrowed location is said to be *sealed* during the borrow.
let v: lent Obj = s[0] # seal 's' let v: lent Obj = s[0] # seal 's'
s.setLen 0 # prevented at compile-time because 's' is sealed. s.setLen 0 # prevented at compile-time because 's' is sealed.
echo v.field echo v.field
```
The scope of the view does not matter: The scope of the view does not matter:
.. code-block:: nim ```nim
proc valid(s: var seq[Obj]) = proc valid(s: var seq[Obj]) =
let v: lent Obj = s[0] # begin of borrow let v: lent Obj = s[0] # begin of borrow
echo v.field # end of borrow echo v.field # end of borrow
s.setLen 0 # valid because 'v' isn't used afterwards s.setLen 0 # valid because 'v' isn't used afterwards
```
The analysis requires as much precision about mutations as is reasonably obtainable, The analysis requires as much precision about mutations as is reasonably obtainable,
@ -730,13 +733,13 @@ with `--experimental:strictFuncs`:option:.
The analysis is currently control flow insensitive: The analysis is currently control flow insensitive:
.. code-block:: nim ```nim
proc invalid(s: var seq[Obj]) = proc invalid(s: var seq[Obj]) =
let v: lent Obj = s[0] let v: lent Obj = s[0]
if false: if false:
s.setLen 0 s.setLen 0
echo v.field echo v.field
```
In this example, the compiler assumes that `s.setLen 0` invalidates the In this example, the compiler assumes that `s.setLen 0` invalidates the
borrow operation of `v` even though a human being can easily see that it borrow operation of `v` even though a human being can easily see that it
@ -824,8 +827,7 @@ arbitrary set of requirements that the matched type must satisfy.
Concepts are written in the following form: Concepts are written in the following form:
.. code-block:: nim ```nim
type type
Comparable = concept x, y Comparable = concept x, y
(x < y) is bool (x < y) is bool
@ -838,6 +840,7 @@ Concepts are written in the following form:
for value in s: for value in s:
value is T value is T
```
The concept matches if: The concept matches if:
@ -850,29 +853,28 @@ as `var`, `ref`, `ptr` and `static` to denote a more specific type of
instance. You can also apply the `type` modifier to create a named instance of instance. You can also apply the `type` modifier to create a named instance of
the type itself: the type itself:
.. code-block:: nim ```nim
type type
MyConcept = concept x, var v, ref r, ptr p, static s, type T MyConcept = concept x, var v, ref r, ptr p, static s, type T
... ...
```
Within the concept body, types can appear in positions where ordinary values Within the concept body, types can appear in positions where ordinary values
and parameters are expected. This provides a more convenient way to check for and parameters are expected. This provides a more convenient way to check for
the presence of callable symbols with specific signatures: the presence of callable symbols with specific signatures:
.. code-block:: nim ```nim
type type
OutputStream = concept var s OutputStream = concept var s
s.write(string) s.write(string)
```
In order to check for symbols accepting `type` params, you must prefix In order to check for symbols accepting `type` params, you must prefix
the type with the explicit `type` modifier. The named instance of the the type with the explicit `type` modifier. The named instance of the
type, following the `concept` keyword is also considered to have the type, following the `concept` keyword is also considered to have the
explicit modifier and will be matched only as a type. explicit modifier and will be matched only as a type.
.. code-block:: nim ```nim
type type
# Let's imagine a user-defined casting framework with operators # Let's imagine a user-defined casting framework with operators
# such as `val.to(string)` and `val.to(JSonValue)`. We can test # such as `val.to(string)` and `val.to(JSonValue)`. We can test
@ -890,6 +892,7 @@ explicit modifier and will be matched only as a type.
x is AdditiveMonoid x is AdditiveMonoid
-x is T -x is T
x - y is T x - y is T
```
Please note that the `is` operator allows one to easily verify the precise Please note that the `is` operator allows one to easily verify the precise
type signatures of the required operations, but since type inference and type signatures of the required operations, but since type inference and
@ -909,12 +912,12 @@ When you need to understand why the compiler is not matching a particular
concept and, as a result, a wrong overload is selected, you can apply the concept and, as a result, a wrong overload is selected, you can apply the
`explain` pragma to either the concept body or a particular call-site. `explain` pragma to either the concept body or a particular call-site.
.. code-block:: nim ```nim
type type
MyConcept {.explain.} = concept ... MyConcept {.explain.} = concept ...
overloadedProc(x, y, z) {.explain.} overloadedProc(x, y, z) {.explain.}
```
This will provide Hints in the compiler output either every time the concept is This will provide Hints in the compiler output either every time the concept is
not matched or only on the particular call-site. not matched or only on the particular call-site.
@ -925,8 +928,7 @@ Generic concepts and type binding rules
The concept types can be parametric just like the regular generic types: The concept types can be parametric just like the regular generic types:
.. code-block:: nim ```nim
### matrixalgo.nim ### matrixalgo.nim
import std/typetraits import std/typetraits
@ -986,6 +988,7 @@ The concept types can be parametric just like the regular generic types:
echo m.transposed.determinant echo m.transposed.determinant
setPerspectiveProjection projectionMatrix setPerspectiveProjection projectionMatrix
```
When the concept type is matched against a concrete type, the unbound type When the concept type is matched against a concrete type, the unbound type
parameters are inferred from the body of the concept in a way that closely parameters are inferred from the body of the concept in a way that closely
@ -999,11 +1002,11 @@ and `x.data is seq[T]`.
Unbound static params will be inferred from expressions involving the `==` Unbound static params will be inferred from expressions involving the `==`
operator and also when types dependent on them are being matched: operator and also when types dependent on them are being matched:
.. code-block:: nim ```nim
type type
MatrixReducer[M, N: static int; T] = concept x MatrixReducer[M, N: static int; T] = concept x
x.reduce(SquareMatrix[N, T]) is array[M, int] x.reduce(SquareMatrix[N, T]) is array[M, int]
```
The Nim compiler includes a simple linear equation solver, allowing it to The Nim compiler includes a simple linear equation solver, allowing it to
infer static params in some situations where integer arithmetic is involved. infer static params in some situations where integer arithmetic is involved.
@ -1014,8 +1017,7 @@ modifier to any of the otherwise inferable types to get a type that will be
matched without permanently inferring it. This may be useful when you need matched without permanently inferring it. This may be useful when you need
to match several procs accepting the same wide class of types: to match several procs accepting the same wide class of types:
.. code-block:: nim ```nim
type type
Enumerable[T] = concept e Enumerable[T] = concept e
for v in e: for v in e:
@ -1032,13 +1034,13 @@ to match several procs accepting the same wide class of types:
# it's also possible to give an alias name to a `bind many` type class # it's also possible to give an alias name to a `bind many` type class
type Enum = distinct Enumerable type Enum = distinct Enumerable
o.baz is Enum o.baz is Enum
```
On the other hand, using `bind once` types allows you to test for equivalent On the other hand, using `bind once` types allows you to test for equivalent
types used in multiple signatures, without actually requiring any concrete types used in multiple signatures, without actually requiring any concrete
types, thus allowing you to encode implementation-defined types: types, thus allowing you to encode implementation-defined types:
.. code-block:: nim ```nim
type type
MyConcept = concept x MyConcept = concept x
type T1 = auto type T1 = auto
@ -1049,6 +1051,7 @@ types, thus allowing you to encode implementation-defined types:
x.alpha(T2) x.alpha(T2)
x.omega(T2) # both procs must accept the same type x.omega(T2) # both procs must accept the same type
# and it must be a numeric sequence # and it must be a numeric sequence
```
As seen in the previous examples, you can refer to generic concepts such as As seen in the previous examples, you can refer to generic concepts such as
`Enumerable[T]` just by their short name. Much like the regular generic types, `Enumerable[T]` just by their short name. Much like the regular generic types,
@ -1066,9 +1069,7 @@ in any required way. For example, here is how one might define the classic
`Functor` concept from Haskell and then demonstrate that Nim's `Option[T]` `Functor` concept from Haskell and then demonstrate that Nim's `Option[T]`
type is an instance of it: type is an instance of it:
.. code-block:: nim ```nim test = "nim c $1"
:test: "nim c $1"
import std/[sugar, typetraits] import std/[sugar, typetraits]
type type
@ -1089,6 +1090,7 @@ type is an instance of it:
import std/options import std/options
echo Option[int] is Functor # prints true echo Option[int] is Functor # prints true
```
Concept derived values Concept derived values
@ -1098,8 +1100,7 @@ All top level constants or types appearing within the concept body are
accessible through the dot operator in procs where the concept was successfully accessible through the dot operator in procs where the concept was successfully
matched to a concrete type: matched to a concrete type:
.. code-block:: nim ```nim
type type
DateTime = concept t1, t2, type T DateTime = concept t1, t2, type T
const Min = T.MinDate const Min = T.MinDate
@ -1121,6 +1122,7 @@ matched to a concrete type:
deviation: float deviation: float
... ...
```
Concept refinement Concept refinement
@ -1133,8 +1135,7 @@ overload resolution, Nim will assign a higher precedence to the most specific
one. As an alternative way of defining concept refinements, you can use the one. As an alternative way of defining concept refinements, you can use the
object inheritance syntax involving the `of` keyword: object inheritance syntax involving the `of` keyword:
.. code-block:: nim ```nim
type type
Graph = concept g, type G of EquallyComparable, Copyable Graph = concept g, type G of EquallyComparable, Copyable
type type
@ -1168,6 +1169,7 @@ object inheritance syntax involving the `of` keyword:
proc f(g: IncidendeGraph) proc f(g: IncidendeGraph)
proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type
# matching the BidirectionalGraph concept # matching the BidirectionalGraph concept
```
.. ..
Converter type classes Converter type classes
@ -1177,8 +1179,7 @@ object inheritance syntax involving the `of` keyword:
a small set of simpler types. This is achieved with a `return` statement within a small set of simpler types. This is achieved with a `return` statement within
the concept body: the concept body:
.. code-block:: nim ```nim
type type
Stringable = concept x Stringable = concept x
$x is string $x is string
@ -1202,6 +1203,7 @@ object inheritance syntax involving the `of` keyword:
# the same call at the cost of additional instantiations # the same call at the cost of additional instantiations
# the varargs param will be converted to a tuple # the varargs param will be converted to a tuple
proc log(format: static string, varargs[distinct StringRef]) proc log(format: static string, varargs[distinct StringRef])
```
.. ..
@ -1229,8 +1231,7 @@ object inheritance syntax involving the `of` keyword:
a converter type class, which converts the regular instances of the matching a converter type class, which converts the regular instances of the matching
types to the corresponding VTable type. types to the corresponding VTable type.
.. code-block:: nim ```nim
type type
IntEnumerable = vtref Enumerable[int] IntEnumerable = vtref Enumerable[int]
@ -1243,6 +1244,7 @@ object inheritance syntax involving the `of` keyword:
proc addStream(o: var MyObject, e: OutputStream.vtref) = proc addStream(o: var MyObject, e: OutputStream.vtref) =
o.streams.add e o.streams.add e
```
The procs that will be included in the vtable are derived from the concept The procs that will be included in the vtable are derived from the concept
body and include all proc calls for which all param types were specified as body and include all proc calls for which all param types were specified as
@ -1272,9 +1274,9 @@ object inheritance syntax involving the `of` keyword:
The signature has to be: The signature has to be:
.. code-block:: nim ```nim
proc `=deepCopy`(x: T): T proc `=deepCopy`(x: T): T
```
This mechanism will be used by most data structures that support shared memory, This mechanism will be used by most data structures that support shared memory,
like channels, to implement thread safe automatic memory management. like channels, to implement thread safe automatic memory management.
@ -1289,7 +1291,7 @@ Dynamic arguments for bindSym
This experimental feature allows the symbol name argument of `macros.bindSym` This experimental feature allows the symbol name argument of `macros.bindSym`
to be computed dynamically. to be computed dynamically.
.. code-block:: nim ```nim
{.experimental: "dynamicBindSym".} {.experimental: "dynamicBindSym".}
import macros import macros
@ -1299,6 +1301,7 @@ to be computed dynamically.
echo callOp("+", 1, 2) echo callOp("+", 1, 2)
echo callOp("-", 5, 4) echo callOp("-", 5, 4)
```
Term rewriting macros Term rewriting macros
@ -1309,12 +1312,12 @@ a *name* but also a *pattern* that is searched for after the semantic checking
phase of the compiler: This means they provide an easy way to enhance the phase of the compiler: This means they provide an easy way to enhance the
compilation pipeline with user defined optimizations: compilation pipeline with user defined optimizations:
.. code-block:: nim ```nim
template optMul{`*`(a, 2)}(a: int): int = a + a template optMul{`*`(a, 2)}(a: int): int = a + a
let x = 3 let x = 3
echo x * 2 echo x * 2
```
The compiler now rewrites `x * 2` as `x + x`. The code inside the The compiler now rewrites `x * 2` as `x + x`. The code inside the
curly brackets is the pattern to match against. The operators `*`, `**`, curly brackets is the pattern to match against. The operators `*`, `**`,
@ -1332,8 +1335,7 @@ Once this limit has been passed, the term rewriting macro will be ignored.
Unfortunately optimizations are hard to get right and even this tiny example Unfortunately optimizations are hard to get right and even this tiny example
is **wrong**: is **wrong**:
.. code-block:: nim ```nim
template optMul{`*`(a, 2)}(a: int): int = a + a template optMul{`*`(a, 2)}(a: int): int = a + a
proc f(): int = proc f(): int =
@ -1341,12 +1343,12 @@ is **wrong**:
result = 55 result = 55
echo f() * 2 echo f() * 2
```
We cannot duplicate 'a' if it denotes an expression that has a side effect! We cannot duplicate 'a' if it denotes an expression that has a side effect!
Fortunately Nim supports side effect analysis: Fortunately Nim supports side effect analysis:
.. code-block:: nim ```nim
template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a + a template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a + a
proc f(): int = proc f(): int =
@ -1354,6 +1356,7 @@ Fortunately Nim supports side effect analysis:
result = 55 result = 55
echo f() * 2 # not optimized ;-) echo f() * 2 # not optimized ;-)
```
You can make one overload matching with a constraint and one without, and the You can make one overload matching with a constraint and one without, and the
one with a constraint will have precedence, and so you can handle both cases one with a constraint will have precedence, and so you can handle both cases
@ -1363,15 +1366,15 @@ So what about `2 * a`? We should tell the compiler `*` is commutative. We
cannot really do that however as the following code only swaps arguments cannot really do that however as the following code only swaps arguments
blindly: blindly:
.. code-block:: nim ```nim
template mulIsCommutative{`*`(a, b)}(a, b: int): int = b * a template mulIsCommutative{`*`(a, b)}(a, b: int): int = b * a
```
What optimizers really need to do is a *canonicalization*: What optimizers really need to do is a *canonicalization*:
.. code-block:: nim ```nim
template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b * a template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b * a
```
The `int{lit}` parameter pattern matches against an expression of The `int{lit}` parameter pattern matches against an expression of
type `int`, but only if it's a literal. type `int`, but only if it's a literal.
@ -1429,17 +1432,16 @@ The `alias` and `noalias` predicates refer not only to the matching AST,
but also to every other bound parameter; syntactically they need to occur after but also to every other bound parameter; syntactically they need to occur after
the ordinary AST predicates: the ordinary AST predicates:
.. code-block:: nim ```nim
template ex{a = b + c}(a: int{noalias}, b, c: int) = template ex{a = b + c}(a: int{noalias}, b, c: int) =
# this transformation is only valid if 'b' and 'c' do not alias 'a': # this transformation is only valid if 'b' and 'c' do not alias 'a':
a = b a = b
inc a, c inc a, c
```
Another example: Another example:
.. code-block:: nim ```nim
proc somefunc(s: string) = assert s == "variable" proc somefunc(s: string) = assert s == "variable"
proc somefunc(s: string{nkStrLit}) = assert s == "literal" proc somefunc(s: string{nkStrLit}) = assert s == "literal"
proc somefunc(s: string{nkRStrLit}) = assert s == r"raw" proc somefunc(s: string{nkRStrLit}) = assert s == r"raw"
@ -1454,6 +1456,7 @@ Another example:
somefunc("literal") somefunc("literal")
somefunc(r"raw") somefunc(r"raw")
somefunc("""triple""") somefunc("""triple""")
```
Pattern operators Pattern operators
@ -1467,21 +1470,21 @@ if they are written in infix notation.
The `|` operator if used as infix operator creates an ordered choice: The `|` operator if used as infix operator creates an ordered choice:
.. code-block:: nim ```nim
template t{0|1}(): untyped = 3 template t{0|1}(): untyped = 3
let a = 1 let a = 1
# outputs 3: # outputs 3:
echo a echo a
```
The matching is performed after the compiler performed some optimizations like The matching is performed after the compiler performed some optimizations like
constant folding, so the following does not work: constant folding, so the following does not work:
.. code-block:: nim ```nim
template t{0|1}(): untyped = 3 template t{0|1}(): untyped = 3
# outputs 1: # outputs 1:
echo 1 echo 1
```
The reason is that the compiler already transformed the 1 into "1" for The reason is that the compiler already transformed the 1 into "1" for
the `echo` statement. However, a term rewriting macro should not change the the `echo` statement. However, a term rewriting macro should not change the
@ -1494,20 +1497,19 @@ command line option or temporarily with the `patterns` pragma.
A pattern expression can be bound to a pattern parameter via the `expr{param}` A pattern expression can be bound to a pattern parameter via the `expr{param}`
notation: notation:
.. code-block:: nim ```nim
template t{(0|1|2){x}}(x: untyped): untyped = x + 1 template t{(0|1|2){x}}(x: untyped): untyped = x + 1
let a = 1 let a = 1
# outputs 2: # outputs 2:
echo a echo a
```
### The `~` operator ### The `~` operator
The `~` operator is the 'not' operator in patterns: The `~` operator is the 'not' operator in patterns:
.. code-block:: nim ```nim
template t{x = (~x){y} and (~x){z}}(x, y, z: bool) = template t{x = (~x){y} and (~x){z}}(x, y, z: bool) =
x = y x = y
if x: x = z if x: x = z
@ -1518,6 +1520,7 @@ The `~` operator is the 'not' operator in patterns:
c = false c = false
a = b and c a = b and c
echo a echo a
```
### The `*` operator ### The `*` operator
@ -1525,8 +1528,7 @@ The `~` operator is the 'not' operator in patterns:
The `*` operator can *flatten* a nested binary expression like `a & b & c` The `*` operator can *flatten* a nested binary expression like `a & b & c`
to `&(a, b, c)`: to `&(a, b, c)`:
.. code-block:: nim ```nim
var var
calls = 0 calls = 0
@ -1542,6 +1544,7 @@ to `&(a, b, c)`:
# check that it's been optimized properly: # check that it's been optimized properly:
doAssert calls == 1 doAssert calls == 1
```
The second operator of `*` must be a parameter; it is used to gather all the The second operator of `*` must be a parameter; it is used to gather all the
@ -1550,9 +1553,9 @@ is passed to `optConc` in `a` as a special list (of kind `nkArgList`)
which is flattened into a call expression; thus the invocation of `optConc` which is flattened into a call expression; thus the invocation of `optConc`
produces: produces:
.. code-block:: nim ```nim
`&&`("my", space & "awe", "some ", "concat") `&&`("my", space & "awe", "some ", "concat")
```
### The `**` operator ### The `**` operator
@ -1560,8 +1563,7 @@ produces:
The `**` is much like the `*` operator, except that it gathers not only The `**` is much like the `*` operator, except that it gathers not only
all the arguments, but also the matched operators in reverse polish notation: all the arguments, but also the matched operators in reverse polish notation:
.. code-block:: nim ```nim
import std/macros import std/macros
type type
@ -1582,6 +1584,7 @@ all the arguments, but also the matched operators in reverse polish notation:
var x, y, z: Matrix var x, y, z: Matrix
echo x + y * z - x echo x + y * z - x
```
This passes the expression `x + y * z - x` to the `optM` macro as This passes the expression `x + y * z - x` to the `optM` macro as
an `nnkArgList` node containing:: an `nnkArgList` node containing::
@ -1605,13 +1608,13 @@ Parameters in a pattern are type checked in the matching process. If a
parameter is of the type `varargs`, it is treated specially and can match parameter is of the type `varargs`, it is treated specially and can match
0 or more arguments in the AST to be matched against: 0 or more arguments in the AST to be matched against:
.. code-block:: nim ```nim
template optWrite{ template optWrite{
write(f, x) write(f, x)
((write|writeLine){w})(f, y) ((write|writeLine){w})(f, y)
}(x, y: varargs[untyped], f: File, w: untyped) = }(x, y: varargs[untyped], f: File, w: untyped) =
w(f, x, y) w(f, x, y)
```
noRewrite pragma noRewrite pragma
@ -1625,12 +1628,12 @@ e.g. when rewriting term to same term plus extra content.
`noRewrite` pragma can actually prevent further rewriting on marked code, `noRewrite` pragma can actually prevent further rewriting on marked code,
e.g. with given example `echo("ab")` will be rewritten just once: e.g. with given example `echo("ab")` will be rewritten just once:
.. code-block:: nim ```nim
template pwnEcho{echo(x)}(x: untyped) = template pwnEcho{echo(x)}(x: untyped) =
{.noRewrite.}: echo("pwned!") {.noRewrite.}: echo("pwned!")
echo "ab" echo "ab"
```
`noRewrite` pragma can be useful to control term-rewriting macros recursion. `noRewrite` pragma can be useful to control term-rewriting macros recursion.
@ -1642,13 +1645,13 @@ Example: Partial evaluation
The following example shows how some simple partial evaluation can be The following example shows how some simple partial evaluation can be
implemented with term rewriting: implemented with term rewriting:
.. code-block:: nim ```nim
proc p(x, y: int; cond: bool): int = proc p(x, y: int; cond: bool): int =
result = if cond: x + y else: x - y result = if cond: x + y else: x - y
template optP1{p(x, y, true)}(x, y: untyped): untyped = x + y template optP1{p(x, y, true)}(x, y: untyped): untyped = x + y
template optP2{p(x, y, false)}(x, y: untyped): untyped = x - y template optP2{p(x, y, false)}(x, y: untyped): untyped = x - y
```
Example: Hoisting Example: Hoisting
@ -1656,8 +1659,7 @@ Example: Hoisting
The following example shows how some form of hoisting can be implemented: The following example shows how some form of hoisting can be implemented:
.. code-block:: nim ```nim
import std/pegs import std/pegs
template optPeg{peg(pattern)}(pattern: string{lit}): Peg = template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
@ -1667,6 +1669,7 @@ The following example shows how some form of hoisting can be implemented:
for i in 0 .. 3: for i in 0 .. 3:
echo match("(a b c)", peg"'(' @ ')'") echo match("(a b c)", peg"'(' @ ')'")
echo match("W_HI_Le", peg"\y 'while'") echo match("W_HI_Le", peg"\y 'while'")
```
The `optPeg` template optimizes the case of a peg constructor with a string The `optPeg` template optimizes the case of a peg constructor with a string
literal, so that the pattern will only be parsed once at program startup and literal, so that the pattern will only be parsed once at program startup and
@ -1680,8 +1683,7 @@ AST based overloading
Parameter constraints can also be used for ordinary routine parameters; these Parameter constraints can also be used for ordinary routine parameters; these
constraints then affect ordinary overloading resolution: constraints then affect ordinary overloading resolution:
.. code-block:: nim ```nim
proc optLit(a: string{lit|`const`}) = proc optLit(a: string{lit|`const`}) =
echo "string literal" echo "string literal"
proc optLit(a: string) = proc optLit(a: string) =
@ -1696,6 +1698,7 @@ constraints then affect ordinary overloading resolution:
optLit("literal") optLit("literal")
optLit(constant) optLit(constant)
optLit(variable) optLit(variable)
```
However, the constraints `alias` and `noalias` are not available in However, the constraints `alias` and `noalias` are not available in
ordinary routines. ordinary routines.
@ -1735,8 +1738,7 @@ Spawn statement
The `spawn`:idx: statement can be used to pass a task to the thread pool: The `spawn`:idx: statement can be used to pass a task to the thread pool:
.. code-block:: nim ```nim
import std/threadpool import std/threadpool
proc processLine(line: string) = proc processLine(line: string) =
@ -1745,6 +1747,7 @@ The `spawn`:idx: statement can be used to pass a task to the thread pool:
for x in lines("myinput.txt"): for x in lines("myinput.txt"):
spawn processLine(x) spawn processLine(x)
sync() sync()
```
For reasons of type safety and implementation simplicity the expression For reasons of type safety and implementation simplicity the expression
that `spawn` takes is restricted: that `spawn` takes is restricted:
@ -1768,8 +1771,7 @@ a `data flow variable`:idx: `FlowVar[T]` that can be read from. The reading
with the `^` operator is **blocking**. However, one can use `blockUntilAny` to with the `^` operator is **blocking**. However, one can use `blockUntilAny` to
wait on multiple flow variables at the same time: wait on multiple flow variables at the same time:
.. code-block:: nim ```nim
import std/threadpool, ... import std/threadpool, ...
# wait until 2 out of 3 servers received the update: # wait until 2 out of 3 servers received the update:
@ -1781,6 +1783,7 @@ wait on multiple flow variables at the same time:
assert index >= 0 assert index >= 0
responses.del(index) responses.del(index)
discard blockUntilAny(responses) discard blockUntilAny(responses)
```
Data flow variables ensure that no data races are possible. Due to Data flow variables ensure that no data races are possible. Due to
technical limitations, not every type `T` can be used in technical limitations, not every type `T` can be used in
@ -1795,9 +1798,7 @@ Parallel statement
Example: Example:
.. code-block:: nim ```nim test = "nim c --threads:on $1"
:test: "nim c --threads:on $1"
# Compute pi in an inefficient way # Compute pi in an inefficient way
import std/[strutils, math, threadpool] import std/[strutils, math, threadpool]
{.experimental: "parallel".} {.experimental: "parallel".}
@ -1813,6 +1814,7 @@ Example:
result += ch[k] result += ch[k]
echo formatFloat(pi(5000)) echo formatFloat(pi(5000))
```
The parallel statement is the preferred mechanism to introduce parallelism in a The parallel statement is the preferred mechanism to introduce parallelism in a
@ -1853,8 +1855,7 @@ lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks
of the same level can only be acquired *at the same time* within a of the same level can only be acquired *at the same time* within a
single `locks` section: single `locks` section:
.. code-block:: nim ```nim
var a, b: TLock[2] var a, b: TLock[2]
var x: TLock[1] var x: TLock[1]
# invalid locking order: TLock[1] cannot be acquired before TLock[2]: # invalid locking order: TLock[1] cannot be acquired before TLock[2]:
@ -1874,14 +1875,14 @@ single `locks` section:
# valid locking order, locks of the same level acquired at the same time: # valid locking order, locks of the same level acquired at the same time:
{.locks: [a, b].}: {.locks: [a, b].}:
... ...
```
Here is how a typical multilock statement can be implemented in Nim. Note how Here is how a typical multilock statement can be implemented in Nim. Note how
the runtime check is required to ensure a global ordering for two locks `a` the runtime check is required to ensure a global ordering for two locks `a`
and `b` of the same lock level: and `b` of the same lock level:
.. code-block:: nim ```nim
template multilock(a, b: ptr TLock; body: untyped) = template multilock(a, b: ptr TLock; body: untyped) =
if cast[ByteAddress](a) < cast[ByteAddress](b): if cast[ByteAddress](a) < cast[ByteAddress](b):
pthread_mutex_lock(a) pthread_mutex_lock(a)
@ -1895,20 +1896,21 @@ and `b` of the same lock level:
finally: finally:
pthread_mutex_unlock(a) pthread_mutex_unlock(a)
pthread_mutex_unlock(b) pthread_mutex_unlock(b)
```
Whole routines can also be annotated with a `locks` pragma that takes a lock Whole routines can also be annotated with a `locks` pragma that takes a lock
level. This then means that the routine may acquire locks of up to this level. level. This then means that the routine may acquire locks of up to this level.
This is essential so that procs can be called within a `locks` section: This is essential so that procs can be called within a `locks` section:
.. code-block:: nim ```nim
proc p() {.locks: 3.} = discard proc p() {.locks: 3.} = discard
var a: TLock[4] var a: TLock[4]
{.locks: [a].}: {.locks: [a].}:
# p's locklevel (3) is strictly less than a's (4) so the call is allowed: # p's locklevel (3) is strictly less than a's (4) so the call is allowed:
p() p()
```
As usual, `locks` is an inferred effect and there is a subtype As usual, `locks` is an inferred effect and there is a subtype
@ -1924,8 +1926,7 @@ cannot be inferred statically, leading to compiler warnings. By using
`{.locks: "unknown".}`, the base method can be marked explicitly as `{.locks: "unknown".}`, the base method can be marked explicitly as
having unknown lock level as well: having unknown lock level as well:
.. code-block:: nim ```nim
type SomeBase* = ref object of RootObj type SomeBase* = ref object of RootObj
type SomeDerived* = ref object of SomeBase type SomeDerived* = ref object of SomeBase
memberProc*: proc () memberProc*: proc ()
@ -1934,5 +1935,6 @@ having unknown lock level as well:
method testMethod(g: SomeDerived) = method testMethod(g: SomeDerived) =
if g.memberProc != nil: if g.memberProc != nil:
g.memberProc() g.memberProc()
```
This feature may be removed in the future due to its practical difficulties. This feature may be removed in the future due to its practical difficulties.