From d314e215751c044c020cc6272d30e6c77ce051ca Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 9 Aug 2022 22:22:16 +0300 Subject: [PATCH] Markdown code blocks part 4 No logic was added, just 8 more files have been migrated. --- doc/docstyle.md | 58 ++++---- doc/drnim.md | 16 +-- doc/effects.txt | 3 +- doc/filters.md | 6 +- doc/hcr.md | 37 ++--- doc/idetools.md | 194 ++++++++++++++------------ doc/intern.md | 111 ++++++++------- doc/koch.md | 5 +- doc/manual_experimental.md | 276 +++++++++++++++++++------------------ 9 files changed, 365 insertions(+), 341 deletions(-) diff --git a/doc/docstyle.md b/doc/docstyle.md index df1f36dad842..79f7b4e105a6 100644 --- a/doc/docstyle.md +++ b/doc/docstyle.md @@ -18,11 +18,11 @@ General Guidelines * (debatable) In nim sources, for links, prefer ``[link text](link.html)`` to `\`link text\`_`:code: 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) = ## Use single backticks for inline code, e.g.: `s` or `someExpr(true)`. ## Use a backlash to follow with alphanumeric char: `int8`\s are great. + ``` 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``. 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. ## - ## .. 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. -.. code-block:: Nim - + ```Nim ## This is the best module ever. It provides answers to everything! ## ## :Author: Steve McQueen ## :Copyright: 1965 ## + ``` 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: -.. code-block:: Nim - + ```Nim proc example1*(x: int) = ## Prints the value of `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. -.. code-block:: Nim - + ````Nim proc addThree*(x, y, z: int8): int = ## Adds three `int8` values, treating them as unsigned and ## truncating the result. ## - ## .. code-block:: - ## # things that aren't suitable for a `runnableExamples` go in code-block: - ## echo execCmdEx("git pull") - ## drawOnScreen() + ## ``` + ## # things that aren't suitable for a `runnableExamples` go in code-block: + ## echo execCmdEx("git pull") + ## drawOnScreen() + ## ``` runnableExamples: # `runnableExamples` is usually preferred to ``code-block``, when possible. doAssert addThree(3, 125, 6) == -122 result = x +% y +% z + ```` 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. -.. code-block:: Nim - + ```Nim type NamedQueue*[T] = object ## Provides a linked data structure with names ## 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 val*: T ## Its value next*: ref NamedQueue[T] ## The next item in the queue + ``` You have some flexibility when placing the documentation: -.. code-block:: Nim - + ```Nim type NamedQueue*[T] = object ## 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 val*: T ## Its value next*: ref NamedQueue[T] ## The next item in the queue + ``` Make sure to place the documentation beside or within the object. -.. code-block:: Nim - + ```Nim type ## Bad: this documentation disappears because it annotates the `type` keyword ## above, not `NamedQueue`. @@ -123,14 +124,14 @@ Make sure to place the documentation beside or within the object. ## is not what we want. val*: T ## Its value next*: ref NamedQueue[T] ## The next item in the queue + ``` 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. -.. code-block:: Nim - + ```Nim const X* = 42 ## An awesome number. SpreadArray* = [ @@ -138,25 +139,26 @@ When declaring module-wide constants and values, documentation is encouraged. Th [2,3,1], [3,1,2], ] ## 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 (`#`). -.. code-block:: Nim - + ```Nim const BadMathVals* = [ 3.14, # pi 2.72, # e 0.58, # gamma ] ## A bunch of badly rounded values. + ``` Nim supports Unicode in comments, so the above can be replaced with the following: -.. code-block:: Nim - + ```Nim const BadMathVals* = [ 3.14, # π 2.72, # e 0.58, # γ ] ## A bunch of badly rounded values (including π!). + ``` diff --git a/doc/drnim.md b/doc/drnim.md index 070cd17871f9..036ae0d147de 100644 --- a/doc/drnim.md +++ b/doc/drnim.md @@ -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 via `staticBoundChecks: on`: -.. code-block:: nim - + ```nim {.push staticBoundChecks: on.} # <--- code section here ----> {.pop.} + ``` DrNim currently only tries to prove array indexing or subrange checks, 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 without additional annotations: -.. code-block:: nim - + ```nim {.push staticBoundChecks: on.} proc sum(a: openArray[int]): int = @@ -64,6 +63,7 @@ without additional annotations: {.pop.} echo sum([1, 2, 3]) + ``` This program contains a famous "index out of bounds" bug. DrNim detects it and produces the following error message:: @@ -125,8 +125,7 @@ Example: insertionSort **Note**: This example does not yet work with DrNim. -.. code-block:: nim - + ```nim import std / logic proc insertionSort(a: var openArray[int]) {. @@ -142,6 +141,7 @@ Example: insertionSort {.invariant: forall(j in 1..k, i in 0..\n" & "\n") + ``` Each line that does not start with the meta character (ignoring leading diff --git a/doc/hcr.md b/doc/hcr.md index dd25e39b37cb..285a862821de 100644 --- a/doc/hcr.md +++ b/doc/hcr.md @@ -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:. -.. code-block:: nim - + ```nim # logic.nim import sdl2 @@ -83,10 +82,10 @@ To install SDL2 you can use `nimble install sdl2`:cmd:. discard renderer.fillRect(rect) delay(16) renderer.present() + ``` -.. code-block:: nim - + ```nim # mymain.nim import logic @@ -97,42 +96,44 @@ To install SDL2 you can use `nimble install sdl2`:cmd:. destroy() main() + ``` Compile this example via: -```cmd + ```cmd nim c --hotcodereloading:on mymain.nim -``` + ``` Now start the program and KEEP it running! -.. code:: cmd + ```cmd # Unix: mymain & # or Windows (click on the .exe) mymain.exe # edit + ``` For example, change the line: -```nim + ```nim discard renderer.setDrawColor(255, 128, 128, 0) -``` + ``` into: -```nim + ```nim discard renderer.setDrawColor(255, 255, 128, 0) -``` + ``` (This will change the color of the rectangle.) Then recompile the project, but do not restart or quit the mymain.exe program! -```cmd + ```cmd nim c --hotcodereloading:on mymain.nim -``` + ``` Now give the `mymain` SDL window the focus, press F9, and watch the updated version of the program. @@ -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 the execution of certain statements: -.. code-block:: Nim + ```Nim var settings = initTable[string, string]() lastReload: Time @@ -159,6 +160,7 @@ the execution of certain statements: afterCodeReload: lastReload = now() resetProgramState() + ``` On each code reload, Nim will first execute all `beforeCodeReload`:idx: 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 `hasModuleChanged()`:idx: API: -.. code-block:: Nim + ```Nim import mydb var myCache = initTable[Key, Value]() @@ -175,6 +177,7 @@ executed. To prevent this behavior, one can guard the code with the afterCodeReload: if hasModuleChanged(mydb): resetCache(myCache) + ``` 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 @@ -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 with choosenim follows. -.. code:: console - + ```console # Unix/MacOS # Make sure you are in the directory containing your .nim files $ cd your-source-directory @@ -215,6 +217,7 @@ with choosenim follows. # verify that you have two files named libnimhcr and libnimrtl in your # source directory (.dll for Windows, .so for Unix, .dylib for MacOS) + ``` All modules of the project will be compiled to separate dynamic link libraries placed in the `nimcache` directory. Please note that during diff --git a/doc/idetools.md b/doc/idetools.md index dcafaf45f4b3..21a1b1e342c2 100644 --- a/doc/idetools.md +++ b/doc/idetools.md @@ -10,10 +10,7 @@ .. contents:: -.. raw:: html -

- "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32. -

+> "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32. Note: this is mostly outdated, see instead `nimsuggest `_ @@ -246,11 +243,12 @@ skConst | **Fourth column**: the type of the const value. | **Docstring**: always the empty string. -.. code-block:: nim - const SOME_SEQUENCE = @[1, 2] - --> col 2: $MODULE.SOME_SEQUENCE - col 3: seq[int] - col 7: "" + ```nim + const SOME_SEQUENCE = @[1, 2] + --> col 2: $MODULE.SOME_SEQUENCE + col 3: seq[int] + col 7: "" + ``` skEnumField @@ -260,11 +258,12 @@ skEnumField | **Fourth column**: enum type grouping other enum fields. | **Docstring**: always the empty string. -.. code-block:: nim - Open(filename, fmWrite) - --> col 2: system.FileMode.fmWrite - col 3: FileMode - col 7: "" + ```nim + Open(filename, fmWrite) + --> col 2: system.FileMode.fmWrite + col 3: FileMode + col 7: "" + ``` skForVar @@ -274,13 +273,14 @@ skForVar | **Fourth column**: type of the var. | **Docstring**: always the empty string. -.. code-block:: nim - proc looper(filename = "tests.nim") = - for letter in filename: - echo letter - --> col 2: $MODULE.looper.letter - col 3: char - col 7: "" + ```nim + proc looper(filename = "tests.nim") = + for letter in filename: + echo letter + --> col 2: $MODULE.looper.letter + col 3: char + col 7: "" + ``` skIterator, skClosureIterator @@ -295,13 +295,14 @@ posterior instances of the iterator. | **Fourth column**: signature of the iterator including return type. | **Docstring**: docstring if available. -.. code-block:: nim - let - text = "some text" - letters = toSeq(runes(text)) - --> col 2: unicode.runes - col 3: iterator (string): Rune - col 7: "iterates over any unicode character of the string `s`." + ```nim + let + text = "some text" + letters = toSeq(runes(text)) + --> col 2: unicode.runes + col 3: iterator (string): Rune + col 7: "iterates over any unicode character of the string `s`." + ``` skLabel @@ -311,13 +312,14 @@ skLabel | **Fourth column**: always the empty string. | **Docstring**: always the empty string. -.. code-block:: nim - proc test(text: string) = - var found = -1 - block loops: - --> col 2: $MODULE.test.loops - col 3: "" - col 7: "" + ```nim + proc test(text: string) = + var found = -1 + block loops: + --> col 2: $MODULE.test.loops + col 3: "" + col 7: "" + ``` skLet @@ -327,12 +329,13 @@ skLet | **Fourth column**: the type of the let variable. | **Docstring**: always the empty string. -.. code-block:: nim - let - text = "some text" - --> col 2: $MODULE.text - col 3: string - col 7: "" + ```nim + let + text = "some text" + --> col 2: $MODULE.text + col 3: string + col 7: "" + ``` skMacro @@ -347,12 +350,13 @@ posterior instances of the macro. | **Fourth column**: signature of the macro including return type. | **Docstring**: docstring if available. -.. code-block:: nim - proc testMacro() = - expect(EArithmetic): - --> col 2: idetools_api.expect - col 3: proc (varargs[expr], stmt): stmt - col 7: "" + ```nim + proc testMacro() = + expect(EArithmetic): + --> col 2: idetools_api.expect + col 3: proc (varargs[expr], stmt): stmt + col 7: "" + ``` skMethod @@ -384,14 +388,15 @@ This may change in the future. | **Fourth column**: signature of the method including return type. | **Docstring**: docstring if available. -.. code-block:: nim - method eval(e: PExpr): int = quit "to override!" - method eval(e: PLiteral): int = e.x - method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b) - echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) - --> col 2: $MODULE.eval - col 3: proc (PPlusExpr): int - col 7: "" + ```nim + method eval(e: PExpr): int = quit "to override!" + method eval(e: PLiteral): int = e.x + method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b) + echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) + --> col 2: $MODULE.eval + col 3: proc (PPlusExpr): int + col 7: "" + ``` skParam @@ -401,12 +406,13 @@ skParam | **Fourth column**: the type of the parameter. | **Docstring**: always the empty string. -.. code-block:: nim - proc reader(filename = "tests.nim") = - let text = readFile(filename) - --> col 2: $MODULE.reader.filename - col 3: string - col 7: "" + ```nim + proc reader(filename = "tests.nim") = + let text = readFile(filename) + --> col 2: $MODULE.reader.filename + col 3: string + col 7: "" + ``` skProc @@ -425,15 +431,16 @@ returned by idetools returns also the pragmas for the proc. | **Fourth column**: signature of the proc including return type. | **Docstring**: docstring if available. -.. code-block:: nim - open(filename, fmWrite) - --> col 2: system.Open - col 3: proc (var File, string, FileMode, int): bool - col 7: - "Opens a file named `filename` with given `mode`. + ```nim + open(filename, fmWrite) + --> col 2: system.Open + col 3: proc (var File, string, FileMode, int): bool + col 7: + "Opens a file named `filename` with given `mode`. - Default mode is readonly. Returns true iff the file could be opened. - This throws no exception if the file could not 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." + ``` skResult @@ -443,12 +450,13 @@ skResult | **Fourth column**: the type of the result. | **Docstring**: always the empty string. -.. code-block:: nim - proc getRandomValue() : int = - return 4 - --> col 2: $MODULE.getRandomValue.result - col 3: int - col 7: "" + ```nim + proc getRandomValue() : int = + return 4 + --> col 2: $MODULE.getRandomValue.result + col 3: int + col 7: "" + ``` skTemplate @@ -463,7 +471,7 @@ posterior instances of the template. | **Fourth column**: signature of the template including return type. | **Docstring**: docstring if available. -.. code-block:: nim + `````nim let text = "some text" letters = toSeq(runes(text)) @@ -474,13 +482,15 @@ posterior instances of the template. Example: - .. code-block:: nim + ```nim let numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] odd_numbers = toSeq(filter(numeric) do (x: int) -> bool: if x mod 2 == 1: result = true) assert odd_numbers == @[1, 3, 5, 7, 9]" + ``` + ````` skType @@ -490,12 +500,13 @@ skType | **Fourth column**: the type. | **Docstring**: always the empty string. -.. code-block:: nim - proc writeTempFile() = - var output: File - --> col 2: system.File - col 3: File - col 7: "" + ```nim + proc writeTempFile() = + var output: File + --> col 2: system.File + col 3: File + col 7: "" + ``` skVar @@ -505,14 +516,15 @@ skVar | **Fourth column**: the type of the var. | **Docstring**: always the empty string. -.. code-block:: nim - proc writeTempFile() = - var output: File - output.open("/tmp/somefile", fmWrite) - output.write("test") - --> col 2: $MODULE.writeTempFile.output - col 3: File - col 7: "" + ```nim + proc writeTempFile() = + var output: File + output.open("/tmp/somefile", fmWrite) + output.write("test") + --> col 2: $MODULE.writeTempFile.output + col 3: File + col 7: "" + ``` Test suite diff --git a/doc/intern.md b/doc/intern.md index b64db3233c8f..baabfb1927c1 100644 --- a/doc/intern.md +++ b/doc/intern.md @@ -42,25 +42,25 @@ Bootstrapping the compiler Compiling the compiler is a simple matter of running: -.. code:: cmd - + ```cmd nim c koch.nim koch boot -d:release + ``` For a debug version use: -.. code:: cmd - + ```cmd nim c koch.nim koch boot + ``` And for a debug version compatible with GDB: -.. code:: cmd - + ```cmd nim c koch.nim koch boot --debuginfo --linedir:on + ``` 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. @@ -73,10 +73,10 @@ Reproducible builds Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable. -.. code:: cmd - + ```cmd export SOURCE_DATE_EPOCH=$(git log -n 1 --format=%at) koch boot # or `./build_all.sh` + ``` 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 current commit: -.. code:: cmd - + ```cmd git bisect start bad-commit good-commit 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 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 for debugging: Another method to build and run the compiler is directly through `koch`:cmd:\: -.. code:: cmd - + ```cmd koch temp [options] c test.nim # (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) koch temp [options] doc test.nim + ``` 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 the currently compiled main module: -.. code-block:: nim - + ```nim # inside some compiler module if mdbg: debug someAstNode + ``` Using the `isCompilerDebug`:nim: condition along with inserting some statements into the testcase provides more granular logging: -.. code-block:: nim - + ```nim # compilermodule.nim if isCompilerDebug(): debug someAstNode @@ -186,21 +185,21 @@ into the testcase provides more granular logging: {.define(nimCompilerDebug).} let a = 2.5 * 3 {.undef(nimCompilerDebug).} + ``` Logging can also be scoped to a specific filename as well. This will of course match against every module with that name. -.. code-block:: nim - + ```nim if `??`(conf, n.info, "module.nim"): debug(n) + ``` 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 information about the internal compiler types include: -.. code-block:: nim - + ```nim # pretty print PNode # pretty prints the Nim ast @@ -246,23 +245,24 @@ information about the internal compiler types include: # print the structure of any type repr(someVar) + ``` Here are some other helpful utilities: -.. code-block:: nim - + ```nim # how did execution reach this location? writeStackTrace() + ``` These procs may not already be imported by the module you're editing. You can import them directly for debugging: -.. code-block:: nim - + ```nim from astalgo import debug from types import typeToString from renderer import renderTree from msgs import `??` + ``` Native debugging ---------------- @@ -280,12 +280,12 @@ and `exitingDebugSection()`:nim:. * LLDB execute `command source tools/compiler.lldb` at startup #. Use one of the scoping helpers like so: -.. code-block:: nim - + ```nim if isCompilerDebug(): enteringDebugSection() else: exitingDebugSection() + ``` 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. @@ -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 could stem from a complex expression: -.. code-block:: nim + ```nim receivesClosure(returnsDefaultCC[i]) + ``` 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 @@ -460,17 +461,18 @@ to pass a proc pointer around via a generic `ref` type. Example code: -.. code-block:: nim + ```nim proc add(x: int): proc (y: int): int {.closure.} = return proc (y: int): int = return x + y var add2 = add(2) echo add2(5) #OUT 7 + ``` This should produce roughly this code: -.. code-block:: nim + ```nim type Env = ref object x: int # data @@ -487,11 +489,12 @@ This should produce roughly this code: var add2 = add(2) let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data) echo tmp + ``` Beware of nesting: -.. code-block:: nim + ```nim proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = return lambda (y: int): proc (z: int): int {.closure.} = return lambda (z: int): int = @@ -499,10 +502,11 @@ Beware of nesting: var add24 = add(2)(4) echo add24(5) #OUT 11 + ``` This should produce roughly this code: -.. code-block:: nim + ```nim type EnvX = ref object x: int # data @@ -530,6 +534,7 @@ This should produce roughly this code: var tmp2 = tmp.fn(4, tmp.data) var add24 = tmp2.fn(4, tmp2.data) echo add24(5) + ``` We could get rid of nesting environments by always inlining inner anon procs. @@ -540,8 +545,7 @@ however. Accumulator ----------- -.. code-block:: nim - + ```nim proc getAccumulator(start: int): proc (): int {.closure} = var i = start return lambda: int = @@ -560,6 +564,7 @@ Accumulator var a = accumulator(3) var b = accumulator(4) echo a() + b() + ``` Internals @@ -614,36 +619,36 @@ keeps the full `int literal(321)` type. Here is an example where that difference matters. -.. code-block:: nim + ```nim + proc foo(arg: int8) = + echo "def" - proc foo(arg: int8) = - echo "def" + const tmp1 = 123 + foo(tmp1) # OK - const tmp1 = 123 - foo(tmp1) # OK - - let tmp2 = 123 - foo(tmp2) # Error + let tmp2 = 123 + foo(tmp2) # Error + ``` In a context with multiple overloads, the integer literal kind will 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 ambiguity. -.. code-block:: nim - - proc foo(arg: int) = - echo "abc" - proc foo(arg: int8) = - echo "def" - foo(123) # output: abc + ```nim + proc foo(arg: int) = + echo "abc" + proc foo(arg: int8) = + echo "def" + foo(123) # output: abc - proc bar(arg: int16) = - echo "abc" - proc bar(arg: int8) = - echo "def" + proc bar(arg: int16) = + echo "abc" + proc bar(arg: int8) = + echo "def" - bar(123) # Error ambiguous call + bar(123) # Error ambiguous call + ``` In the compiler these integer literal types are represented with the node kind `nkIntLit`, type kind `tyInt` and the member `n` of the type diff --git a/doc/koch.md b/doc/koch.md index 91dd5d570c60..2454ac2f49a8 100644 --- a/doc/koch.md +++ b/doc/koch.md @@ -8,10 +8,7 @@ .. include:: rstcommon.rst .. contents:: -.. raw:: html -

- "A great chef is an artist that I truly respect" -- Robert Stack. -

+> "A great chef is an artist that I truly respect" -- Robert Stack. Introduction diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 81d4cc51ecd0..f584c890565c 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -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 the procedure does not return a value: -.. code-block:: nim - + ```nim proc nothing(x, y: void): void = echo "ha" nothing() # writes "ha" to stdout + ``` The `void` type is particularly useful for generic code: -.. code-block:: nim - + ```nim proc callProc[T](p: proc (x: T), x: T) = when T is void: p() @@ -52,15 +51,16 @@ The `void` type is particularly useful for generic code: callProc[int](intProc, 12) callProc[void](emptyProc) + ``` However, a `void` type cannot be inferred in generic code: -.. code-block:: nim - + ```nim callProc(emptyProc) # Error: type mismatch: got (proc ()) # but expected one of: # callProc(p: proc (T), x: T) + ``` The `void` type is only valid for parameters and return types; other symbols 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 ambiguous, a static error will be produced. -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" {.experimental: "overloadableEnums".} type @@ -124,6 +122,7 @@ ambiguous, a static error will be produced. of value2: echo "B" p value2 + ``` Package level objects @@ -144,8 +143,7 @@ available. Example: -.. code-block:: nim - + ```nim # module A (in an arbitrary package) type Pack.SomeObject = object # declare as incomplete object of package 'Pack' @@ -154,15 +152,16 @@ Example: # Incomplete objects can be used as parameters: proc myproc(x: SomeObject) = discard + ``` -.. code-block:: nim - + ```nim # module B (in package "Pack") type SomeObject* {.package.} = object # Use 'package' to complete the object s, t: string x, y: int + ``` This feature will likely be superseded in the future by support for recursive module dependencies. @@ -223,8 +222,7 @@ preface definitions inside a module. Example: -.. code-block:: nim - + ```nim {.experimental: "codeReordering".} proc foo(x: int) = @@ -234,14 +232,14 @@ Example: echo(x) foo(10) + ``` Variables can also be reordered as well. Variables that are *initialized* (i.e. variables that have their declaration and assignment combined in a single statement) can have their entire initialization statement reordered. Be wary of what code is executed at the top level: -.. code-block:: nim - + ```nim {.experimental: "codeReordering".} proc a() = @@ -250,6 +248,7 @@ what code is executed at the top level: var foo = 5 a() # outputs: "5" + ``` .. 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 is the same as it would be with code reordering disabled. - .. code-block:: nim - + ```nim {.experimental: "codeReordering".} proc x() = @@ -270,12 +268,12 @@ what code is executed at the top level: var foo = 4 x() # "false" + ``` It is important to note that reordering *only* works for symbols at top level scope. Therefore, the following will *fail to compile:* -.. code-block:: nim - + ```nim {.experimental: "codeReordering".} proc a() = @@ -284,6 +282,7 @@ scope. Therefore, the following will *fail to compile:* echo("Hello!") a() + ``` This feature will likely be replaced with a better solution to remove the need for forward declarations. @@ -295,8 +294,7 @@ Automatic dereferencing Automatic dereferencing is performed for the first argument of a routine call. This feature has to be enabled via `{.experimental: "implicitDeref".}`: -.. code-block:: nim - + ```nim {.experimental: "implicitDeref".} type @@ -309,6 +307,7 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`: let n = Node() echo n.depth # no need to write n[].depth + ``` 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 an `untyped` parameter: -.. code-block:: nim - + ```nim a.b # becomes `.`(a, b) a.b(c, d) # becomes `.`(a, b, c, d) + ``` The matched dot operators can be symbols of any callable kind (procs, templates and macros), depending on the desired effect: -.. code-block:: nim - + ```nim template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)] var js = parseJson("{ x: 1, y: 2}") echo js.x # outputs 1 echo js.y # outputs 2 + ``` The following dot operators are available: @@ -366,9 +365,9 @@ operator `.=` ------------- This operator will be matched against assignments to missing fields. -.. code-block:: nim - + ```nim a.b = c # becomes `.=`(a, b, c) + ``` 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 to use this operator. -.. code-block:: nim - + ```nim {.experimental: "callOperator".} 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 (a.b)(c) == `()`(a.b, c) + ``` Extended macro pragmas @@ -412,9 +411,10 @@ can also be applied to type, variable and constant declarations. For types: -.. code-block:: nim + ```nim type MyObject {.schema: "schema.protobuf".} = object + ``` 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 @@ -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, and macros can return any expression. -.. code-block:: nim + ```nim var a = ... b {.importc, foo, nodecl.} = ... c = ... + ``` Assuming `foo` is a macro or a template, this is roughly equivalent to: -.. code-block:: nim + ```nim var a = ... foo: var b {.importc, nodecl.} = ... var c = ... + ``` 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 expressions that cannot conveniently be represented as runtime values. -.. code-block:: nim + ```nim type Foo = object bar: int @@ -468,6 +470,7 @@ expressions that cannot conveniently be represented as runtime values. assert bar == 10 bar = 15 assert bar == 15 + ``` 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 @@ -483,8 +486,7 @@ Not nil annotation All types for which `nil` is a valid value can be annotated with the `not nil` annotation to exclude `nil` as a valid value: -.. code-block:: nim - + ```nim {.experimental: "notnil".} type @@ -500,6 +502,7 @@ All types for which `nil` is a valid value can be annotated with the # and also this: var x: PObject p(x) + ``` The compiler ensures that every code path initializes variables which contain 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: -.. code-block:: nim - + ```nim {.experimental: "strictFuncs".} type @@ -566,6 +568,7 @@ For example: m.data = "yeah" # the mutation is here # Error: 'mut' can have side effects # an object reachable from 'n' is potentially mutated + ``` 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: -.. code-block:: nim - + ```nim type View1 = openArray[byte] View2 = lent string View3 = Table[openArray[char], int] + ``` Exceptions to this rule are types constructed via `ptr` or `proc`. For example, the following types are **not** view types: -.. code-block:: nim - + ```nim type NotView1 = proc (x: openArray[int]) NotView2 = ptr openArray[char] NotView3 = ptr array[4, lent int] + ``` 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: -.. code-block:: nim - + ```nim {.experimental: "views".} proc take(a: openArray[int]) = @@ -641,6 +643,7 @@ For example: main(@[11, 22, 33]) + ``` 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 location. The borrowed location is said to be *sealed* during the borrow. -.. code-block:: nim - + ```nim {.experimental: "views".} 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' s.setLen 0 # prevented at compile-time because 's' is sealed. echo v.field + ``` The scope of the view does not matter: -.. code-block:: nim - + ```nim proc valid(s: var seq[Obj]) = let v: lent Obj = s[0] # begin of borrow echo v.field # end of borrow s.setLen 0 # valid because 'v' isn't used afterwards + ``` 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: -.. code-block:: nim - + ```nim proc invalid(s: var seq[Obj]) = let v: lent Obj = s[0] if false: s.setLen 0 echo v.field + ``` 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 @@ -824,8 +827,7 @@ arbitrary set of requirements that the matched type must satisfy. Concepts are written in the following form: -.. code-block:: nim - + ```nim type Comparable = concept x, y (x < y) is bool @@ -838,6 +840,7 @@ Concepts are written in the following form: for value in s: value is T + ``` 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 the type itself: -.. code-block:: nim - + ```nim type 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 and parameters are expected. This provides a more convenient way to check for the presence of callable symbols with specific signatures: -.. code-block:: nim - + ```nim type OutputStream = concept var s s.write(string) + ``` In order to check for symbols accepting `type` params, you must prefix the type with the explicit `type` modifier. The named instance of the type, following the `concept` keyword is also considered to have the explicit modifier and will be matched only as a type. -.. code-block:: nim - + ```nim type # Let's imagine a user-defined casting framework with operators # 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 T x - y is T + ``` Please note that the `is` operator allows one to easily verify the precise 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 `explain` pragma to either the concept body or a particular call-site. -.. code-block:: nim - + ```nim type MyConcept {.explain.} = concept ... overloadedProc(x, y, z) {.explain.} + ``` This will provide Hints in the compiler output either every time the concept is 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: -.. code-block:: nim - + ```nim ### matrixalgo.nim import std/typetraits @@ -986,6 +988,7 @@ The concept types can be parametric just like the regular generic types: echo m.transposed.determinant setPerspectiveProjection projectionMatrix + ``` 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 @@ -999,11 +1002,11 @@ and `x.data is seq[T]`. Unbound static params will be inferred from expressions involving the `==` operator and also when types dependent on them are being matched: -.. code-block:: nim - + ```nim type MatrixReducer[M, N: static int; T] = concept x x.reduce(SquareMatrix[N, T]) is array[M, int] + ``` The Nim compiler includes a simple linear equation solver, allowing it to 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 to match several procs accepting the same wide class of types: -.. code-block:: nim - + ```nim type Enumerable[T] = concept 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 type Enum = distinct Enumerable o.baz is Enum + ``` 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, thus allowing you to encode implementation-defined types: -.. code-block:: nim - + ```nim type MyConcept = concept x type T1 = auto @@ -1049,6 +1051,7 @@ types, thus allowing you to encode implementation-defined types: x.alpha(T2) x.omega(T2) # both procs must accept the same type # and it must be a numeric sequence + ``` 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, @@ -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]` type is an instance of it: -.. code-block:: nim - :test: "nim c $1" - + ```nim test = "nim c $1" import std/[sugar, typetraits] type @@ -1089,6 +1090,7 @@ type is an instance of it: import std/options echo Option[int] is Functor # prints true + ``` 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 matched to a concrete type: -.. code-block:: nim - + ```nim type DateTime = concept t1, t2, type T const Min = T.MinDate @@ -1121,6 +1122,7 @@ matched to a concrete type: deviation: float ... + ``` 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 object inheritance syntax involving the `of` keyword: -.. code-block:: nim - + ```nim type Graph = concept g, type G of EquallyComparable, Copyable type @@ -1168,6 +1169,7 @@ object inheritance syntax involving the `of` keyword: proc f(g: IncidendeGraph) proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type # matching the BidirectionalGraph concept + ``` .. 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 the concept body: - .. code-block:: nim - + ```nim type Stringable = concept x $x is string @@ -1202,6 +1203,7 @@ object inheritance syntax involving the `of` keyword: # the same call at the cost of additional instantiations # the varargs param will be converted to a tuple 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 types to the corresponding VTable type. - .. code-block:: nim - + ```nim type IntEnumerable = vtref Enumerable[int] @@ -1243,6 +1244,7 @@ object inheritance syntax involving the `of` keyword: proc addStream(o: var MyObject, e: OutputStream.vtref) = o.streams.add e + ``` 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 @@ -1272,9 +1274,9 @@ object inheritance syntax involving the `of` keyword: The signature has to be: - .. code-block:: nim - + ```nim proc `=deepCopy`(x: T): T + ``` This mechanism will be used by most data structures that support shared memory, 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` to be computed dynamically. -.. code-block:: nim + ```nim {.experimental: "dynamicBindSym".} import macros @@ -1299,6 +1301,7 @@ to be computed dynamically. echo callOp("+", 1, 2) echo callOp("-", 5, 4) + ``` 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 compilation pipeline with user defined optimizations: -.. code-block:: nim - + ```nim template optMul{`*`(a, 2)}(a: int): int = a + a let x = 3 echo x * 2 + ``` The compiler now rewrites `x * 2` as `x + x`. The code inside the 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 is **wrong**: -.. code-block:: nim - + ```nim template optMul{`*`(a, 2)}(a: int): int = a + a proc f(): int = @@ -1341,12 +1343,12 @@ is **wrong**: result = 55 echo f() * 2 + ``` We cannot duplicate 'a' if it denotes an expression that has a side effect! Fortunately Nim supports side effect analysis: -.. code-block:: nim - + ```nim template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a + a proc f(): int = @@ -1354,6 +1356,7 @@ Fortunately Nim supports side effect analysis: result = 55 echo f() * 2 # not optimized ;-) + ``` You can make one overload matching with a constraint and one without, and the one with a constraint will have precedence, and so you can handle both cases @@ -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 blindly: -.. code-block:: nim - + ```nim template mulIsCommutative{`*`(a, b)}(a, b: int): int = b * a + ``` 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 + ``` The `int{lit}` parameter pattern matches against an expression of 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 the ordinary AST predicates: -.. code-block:: nim - + ```nim template ex{a = b + c}(a: int{noalias}, b, c: int) = # this transformation is only valid if 'b' and 'c' do not alias 'a': a = b inc a, c + ``` Another example: -.. code-block:: nim - + ```nim proc somefunc(s: string) = assert s == "variable" proc somefunc(s: string{nkStrLit}) = assert s == "literal" proc somefunc(s: string{nkRStrLit}) = assert s == r"raw" @@ -1454,6 +1456,7 @@ Another example: somefunc("literal") somefunc(r"raw") somefunc("""triple""") + ``` Pattern operators @@ -1467,21 +1470,21 @@ if they are written in infix notation. The `|` operator if used as infix operator creates an ordered choice: -.. code-block:: nim - + ```nim template t{0|1}(): untyped = 3 let a = 1 # outputs 3: echo a + ``` The matching is performed after the compiler performed some optimizations like constant folding, so the following does not work: -.. code-block:: nim - + ```nim template t{0|1}(): untyped = 3 # outputs 1: echo 1 + ``` 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 @@ -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}` notation: -.. code-block:: nim - + ```nim template t{(0|1|2){x}}(x: untyped): untyped = x + 1 let a = 1 # outputs 2: echo a + ``` ### The `~` operator The `~` operator is the 'not' operator in patterns: -.. code-block:: nim - + ```nim template t{x = (~x){y} and (~x){z}}(x, y, z: bool) = x = y if x: x = z @@ -1518,6 +1520,7 @@ The `~` operator is the 'not' operator in patterns: c = false a = b and c echo a + ``` ### 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` to `&(a, b, c)`: -.. code-block:: nim - + ```nim var calls = 0 @@ -1542,6 +1544,7 @@ to `&(a, b, c)`: # check that it's been optimized properly: doAssert calls == 1 + ``` 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` produces: -.. code-block:: nim - - `&&`("my", space & "awe", "some ", "concat") + ```nim + `&&`("my", space & "awe", "some ", "concat") + ``` ### The `**` operator @@ -1560,8 +1563,7 @@ produces: The `**` is much like the `*` operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation: -.. code-block:: nim - + ```nim import std/macros type @@ -1582,6 +1584,7 @@ all the arguments, but also the matched operators in reverse polish notation: var x, y, z: Matrix echo x + y * z - x + ``` This passes the expression `x + y * z - x` to the `optM` macro as 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 0 or more arguments in the AST to be matched against: -.. code-block:: nim - + ```nim template optWrite{ write(f, x) ((write|writeLine){w})(f, y) }(x, y: varargs[untyped], f: File, w: untyped) = w(f, x, y) + ``` 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, e.g. with given example `echo("ab")` will be rewritten just once: -.. code-block:: nim - + ```nim template pwnEcho{echo(x)}(x: untyped) = {.noRewrite.}: echo("pwned!") echo "ab" + ``` `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 implemented with term rewriting: -.. code-block:: nim - + ```nim proc p(x, y: int; cond: bool): int = result = if cond: x + y else: 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 + ``` Example: Hoisting @@ -1656,8 +1659,7 @@ Example: Hoisting The following example shows how some form of hoisting can be implemented: -.. code-block:: nim - + ```nim import std/pegs 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: echo match("(a b c)", peg"'(' @ ')'") echo match("W_HI_Le", peg"\y 'while'") + ``` 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 @@ -1680,8 +1683,7 @@ AST based overloading Parameter constraints can also be used for ordinary routine parameters; these constraints then affect ordinary overloading resolution: -.. code-block:: nim - + ```nim proc optLit(a: string{lit|`const`}) = echo "string literal" proc optLit(a: string) = @@ -1696,6 +1698,7 @@ constraints then affect ordinary overloading resolution: optLit("literal") optLit(constant) optLit(variable) + ``` However, the constraints `alias` and `noalias` are not available in ordinary routines. @@ -1735,8 +1738,7 @@ Spawn statement The `spawn`:idx: statement can be used to pass a task to the thread pool: -.. code-block:: nim - + ```nim import std/threadpool 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"): spawn processLine(x) sync() + ``` For reasons of type safety and implementation simplicity the expression 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 wait on multiple flow variables at the same time: -.. code-block:: nim - + ```nim import std/threadpool, ... # 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 responses.del(index) discard blockUntilAny(responses) + ``` Data flow variables ensure that no data races are possible. Due to technical limitations, not every type `T` can be used in @@ -1795,9 +1798,7 @@ Parallel statement Example: -.. code-block:: nim - :test: "nim c --threads:on $1" - + ```nim test = "nim c --threads:on $1" # Compute pi in an inefficient way import std/[strutils, math, threadpool] {.experimental: "parallel".} @@ -1813,6 +1814,7 @@ Example: result += ch[k] echo formatFloat(pi(5000)) + ``` 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 single `locks` section: -.. code-block:: nim - + ```nim var a, b: TLock[2] var x: TLock[1] # 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: {.locks: [a, b].}: ... + ``` 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` and `b` of the same lock level: -.. code-block:: nim - + ```nim template multilock(a, b: ptr TLock; body: untyped) = if cast[ByteAddress](a) < cast[ByteAddress](b): pthread_mutex_lock(a) @@ -1895,20 +1896,21 @@ and `b` of the same lock level: finally: pthread_mutex_unlock(a) pthread_mutex_unlock(b) + ``` 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. This is essential so that procs can be called within a `locks` section: -.. code-block:: nim - + ```nim proc p() {.locks: 3.} = discard var a: TLock[4] {.locks: [a].}: # p's locklevel (3) is strictly less than a's (4) so the call is allowed: p() + ``` 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 having unknown lock level as well: -.. code-block:: nim - + ```nim type SomeBase* = ref object of RootObj type SomeDerived* = ref object of SomeBase memberProc*: proc () @@ -1934,5 +1935,6 @@ having unknown lock level as well: method testMethod(g: SomeDerived) = if g.memberProc != nil: g.memberProc() + ``` This feature may be removed in the future due to its practical difficulties.