Markdown code blocks part 5 (#20236)
No logic was added, just a few more `*.md` files have been migrated.
This commit is contained in:
parent
60f6724b70
commit
1c31de361d
21 changed files with 486 additions and 413 deletions
|
|
@ -198,8 +198,7 @@ static C library.
|
||||||
|
|
||||||
Create a ``host.html`` file with the following content:
|
Create a ``host.html`` file with the following content:
|
||||||
|
|
||||||
.. code-block::
|
```
|
||||||
|
|
||||||
<html><body>
|
<html><body>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function addTwoIntegers(a, b)
|
function addTwoIntegers(a, b)
|
||||||
|
|
@ -209,6 +208,7 @@ Create a ``host.html`` file with the following content:
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="calculator.js"></script>
|
<script type="text/javascript" src="calculator.js"></script>
|
||||||
</body></html>
|
</body></html>
|
||||||
|
```
|
||||||
|
|
||||||
Create a ``calculator.nim`` file with the following content (or reuse the one
|
Create a ``calculator.nim`` file with the following content (or reuse the one
|
||||||
from the previous section):
|
from the previous section):
|
||||||
|
|
|
||||||
|
|
@ -67,11 +67,12 @@ Basic Markdown syntax is also supported inside the doc comments.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type Person* = object
|
type Person* = object
|
||||||
## This type contains a description of a person
|
## This type contains a description of a person
|
||||||
name: string
|
name: string
|
||||||
age: int
|
age: int
|
||||||
|
```
|
||||||
|
|
||||||
Outputs::
|
Outputs::
|
||||||
Person* = object
|
Person* = object
|
||||||
|
|
@ -82,9 +83,10 @@ Outputs::
|
||||||
|
|
||||||
Field documentation comments can be added to fields like so:
|
Field documentation comments can be added to fields like so:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var numValues: int ## \
|
var numValues: int ## \
|
||||||
## `numValues` stores the number of values
|
## `numValues` stores the number of values
|
||||||
|
```
|
||||||
|
|
||||||
Note that without the `*` following the name of the type, the documentation for
|
Note that without the `*` following the name of the type, the documentation for
|
||||||
this type would not be generated. Documentation will only be generated for
|
this type would not be generated. Documentation will only be generated for
|
||||||
|
|
@ -102,12 +104,13 @@ won't influence RST formatting.
|
||||||
If you still need to add an additional indentation at the very beginning
|
If you still need to add an additional indentation at the very beginning
|
||||||
(for RST block quote syntax) use backslash \\ before it:
|
(for RST block quote syntax) use backslash \\ before it:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
## \
|
## \
|
||||||
##
|
##
|
||||||
## Block quote at the first line.
|
## Block quote at the first line.
|
||||||
##
|
##
|
||||||
## Paragraph.
|
## Paragraph.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Document Types
|
Document Types
|
||||||
|
|
@ -248,9 +251,9 @@ the anchor [*]_ of Nim symbol that corresponds to link text.
|
||||||
|
|
||||||
If you have a constant:
|
If you have a constant:
|
||||||
|
|
||||||
```Nim
|
```Nim
|
||||||
const pi* = 3.14
|
const pi* = 3.14
|
||||||
```
|
```
|
||||||
|
|
||||||
then it should be referenced in one of the 2 forms:
|
then it should be referenced in one of the 2 forms:
|
||||||
|
|
||||||
|
|
@ -261,9 +264,9 @@ B. qualified (with symbol kind specification)::
|
||||||
|
|
||||||
For routine kinds there are more options. Consider this definition:
|
For routine kinds there are more options. Consider this definition:
|
||||||
|
|
||||||
```Nim
|
```Nim
|
||||||
proc foo*(a: int, b: float): string
|
proc foo*(a: int, b: float): string
|
||||||
```
|
```
|
||||||
|
|
||||||
Generally following syntax is allowed for referencing `foo`:
|
Generally following syntax is allowed for referencing `foo`:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,12 @@ Whenever an example of usage would be helpful to the user, you should include on
|
||||||
## truncating the result.
|
## truncating the result.
|
||||||
##
|
##
|
||||||
## ```
|
## ```
|
||||||
## # 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 blocks, when possible.
|
||||||
doAssert addThree(3, 125, 6) == -122
|
doAssert addThree(3, 125, 6) == -122
|
||||||
result = x +% y +% z
|
result = x +% y +% z
|
||||||
````
|
````
|
||||||
|
|
|
||||||
|
|
@ -5083,10 +5083,7 @@ exception tracking.
|
||||||
|
|
||||||
There is also a way which can be used to forbid certain effects:
|
There is also a way which can be used to forbid certain effects:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c --warningAsError:Effect:on $1" status = 1
|
||||||
:test: "nim c --warningAsError:Effect:on $1"
|
|
||||||
:status: 1
|
|
||||||
|
|
||||||
type IO = object ## input/output effect
|
type IO = object ## input/output effect
|
||||||
proc readLine(): string {.tags: [IO].} = discard
|
proc readLine(): string {.tags: [IO].} = discard
|
||||||
proc echoLine(): void = discard
|
proc echoLine(): void = discard
|
||||||
|
|
@ -5096,13 +5093,14 @@ There is also a way which can be used to forbid certain effects:
|
||||||
echoLine()
|
echoLine()
|
||||||
# the compiler prevents this:
|
# the compiler prevents this:
|
||||||
let y = readLine()
|
let y = readLine()
|
||||||
|
```
|
||||||
|
|
||||||
The `forbids` pragma defines a list of illegal effects - if any statement
|
The `forbids` pragma defines a list of illegal effects - if any statement
|
||||||
invokes any of those effects, the compilation will fail.
|
invokes any of those effects, the compilation will fail.
|
||||||
Procedure types with any disallowed effect are the subtypes of equal
|
Procedure types with any disallowed effect are the subtypes of equal
|
||||||
procedure types without such lists:
|
procedure types without such lists:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type MyEffect = object
|
type MyEffect = object
|
||||||
type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
|
type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
|
||||||
type ProcType2 = proc (i: int): void
|
type ProcType2 = proc (i: int): void
|
||||||
|
|
@ -5123,6 +5121,7 @@ procedure types without such lists:
|
||||||
## these are OK because ProcType2 doesn't have any effect requirement:
|
## these are OK because ProcType2 doesn't have any effect requirement:
|
||||||
caller2(toBeCalled1)
|
caller2(toBeCalled1)
|
||||||
caller2(toBeCalled2)
|
caller2(toBeCalled2)
|
||||||
|
```
|
||||||
|
|
||||||
`ProcType2` is a subtype of `ProcType1`. Unlike with tags, the parent context - the function which calls other functions with forbidden effects - doesn't inherit the forbidden list of effects.
|
`ProcType2` is a subtype of `ProcType1`. Unlike with tags, the parent context - the function which calls other functions with forbidden effects - doesn't inherit the forbidden list of effects.
|
||||||
|
|
||||||
|
|
@ -8079,18 +8078,20 @@ from C. The optional argument is a string containing the C identifier. If
|
||||||
the argument is missing, the C name is the Nim identifier *exactly as
|
the argument is missing, the C name is the Nim identifier *exactly as
|
||||||
spelled*:
|
spelled*:
|
||||||
|
|
||||||
.. code-block::
|
```nim
|
||||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||||
|
```
|
||||||
|
|
||||||
When `importc` is applied to a `let` statement it can omit its value which
|
When `importc` is applied to a `let` statement it can omit its value which
|
||||||
will then be expected to come from C. This can be used to import a C `const`:c:\:
|
will then be expected to come from C. This can be used to import a C `const`:c:\:
|
||||||
|
|
||||||
.. code-block::
|
```nim
|
||||||
{.emit: "const int cconst = 42;".}
|
{.emit: "const int cconst = 42;".}
|
||||||
|
|
||||||
let cconst {.importc, nodecl.}: cint
|
let cconst {.importc, nodecl.}: cint
|
||||||
|
|
||||||
assert cconst == 42
|
assert cconst == 42
|
||||||
|
```
|
||||||
|
|
||||||
Note that this pragma has been abused in the past to also work in the
|
Note that this pragma has been abused in the past to also work in the
|
||||||
JS backend for JS objects and functions. Other backends do provide
|
JS backend for JS objects and functions. Other backends do provide
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ rule: If `result` does not refer to a location pointing to the heap
|
||||||
(that is in `result = X` the `X` involves a `ptr` or `ref` access)
|
(that is in `result = X` the `X` involves a `ptr` or `ref` access)
|
||||||
then it has to be derived from the routine's first parameter:
|
then it has to be derived from the routine's first parameter:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc forward[T](x: var T): var T =
|
proc forward[T](x: var T): var T =
|
||||||
result = x # ok, derived from the first parameter.
|
result = x # ok, derived from the first parameter.
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ then it has to be derived from the routine's first parameter:
|
||||||
result = forward(x) # Error: location is derived from `x`
|
result = forward(x) # Error: location is derived from `x`
|
||||||
# which is not p's first parameter and lives
|
# which is not p's first parameter and lives
|
||||||
# on the stack.
|
# on the stack.
|
||||||
|
```
|
||||||
|
|
||||||
In other words, the lifetime of what `result` points to is attached to the
|
In other words, the lifetime of what `result` points to is attached to the
|
||||||
lifetime of the first parameter and that is enough knowledge to verify
|
lifetime of the first parameter and that is enough knowledge to verify
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,15 @@ Strict not nil checking
|
||||||
|
|
||||||
**Note:** This feature is experimental, you need to enable it with
|
**Note:** This feature is experimental, you need to enable it with
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
{.experimental: "strictNotNil".}
|
{.experimental: "strictNotNil".}
|
||||||
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
.. code-block:: cmd
|
```cmd
|
||||||
nim c --experimental:strictNotNil <program>
|
nim c --experimental:strictNotNil <program>
|
||||||
|
```
|
||||||
|
|
||||||
In the second case it would check builtin and imported modules as well.
|
In the second case it would check builtin and imported modules as well.
|
||||||
|
|
||||||
|
|
@ -39,7 +41,7 @@ not nil
|
||||||
|
|
||||||
You can annotate a type where nil isn't a valid value with `not nil`.
|
You can annotate a type where nil isn't a valid value with `not nil`.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
NilableObject = ref object
|
NilableObject = ref object
|
||||||
a: int
|
a: int
|
||||||
|
|
@ -57,6 +59,7 @@ You can annotate a type where nil isn't a valid value with `not nil`.
|
||||||
p(x)
|
p(x)
|
||||||
else:
|
else:
|
||||||
p(x) # ok
|
p(x) # ok
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -118,14 +121,16 @@ call args rules
|
||||||
|
|
||||||
When we call with arguments, we have two cases when we might change the nilability.
|
When we call with arguments, we have two cases when we might change the nilability.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
callByVar(a)
|
callByVar(a)
|
||||||
|
```
|
||||||
|
|
||||||
Here `callByVar` can re-assign `a`, so this might change `a`'s nilability, so we change it to `MaybeNil`.
|
Here `callByVar` can re-assign `a`, so this might change `a`'s nilability, so we change it to `MaybeNil`.
|
||||||
This is also a possible aliasing `move out` (moving out of a current alias set).
|
This is also a possible aliasing `move out` (moving out of a current alias set).
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
call(a)
|
call(a)
|
||||||
|
```
|
||||||
|
|
||||||
Here `call` can change a field or element of `a`, so if we have a dependant expression of `a` : e.g. `a.field`. Dependants become `MaybeNil`.
|
Here `call` can change a field or element of `a`, so if we have a dependant expression of `a` : e.g. `a.field`. Dependants become `MaybeNil`.
|
||||||
|
|
||||||
|
|
@ -141,13 +146,14 @@ When branches "join" we usually unify their expression maps or/and nilabilities.
|
||||||
|
|
||||||
Merging usually merges maps and alias sets: nilabilities are merged like this:
|
Merging usually merges maps and alias sets: nilabilities are merged like this:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
template union(l: Nilability, r: Nilability): Nilability =
|
template union(l: Nilability, r: Nilability): Nilability =
|
||||||
## unify two states
|
## unify two states
|
||||||
if l == r:
|
if l == r:
|
||||||
l
|
l
|
||||||
else:
|
else:
|
||||||
MaybeNil
|
MaybeNil
|
||||||
|
```
|
||||||
|
|
||||||
Special handling is for `.isNil` and `== nil`, also for `not`, `and` and `or`.
|
Special handling is for `.isNil` and `== nil`, also for `not`, `and` and `or`.
|
||||||
|
|
||||||
|
|
@ -183,8 +189,9 @@ element tracking
|
||||||
When we assign an object construction, we should track the fields as well:
|
When we assign an object construction, we should track the fields as well:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var a = Nilable(field: Nilable()) # a : Safe, a.field: Safe
|
var a = Nilable(field: Nilable()) # a : Safe, a.field: Safe
|
||||||
|
```
|
||||||
|
|
||||||
Usually we just track the result of an expression: probably this should apply for elements in other cases as well.
|
Usually we just track the result of an expression: probably this should apply for elements in other cases as well.
|
||||||
Also related to tracking initialization of expressions/fields.
|
Also related to tracking initialization of expressions/fields.
|
||||||
|
|
@ -195,12 +202,13 @@ unstructured control flow rules
|
||||||
Unstructured control flow keywords as `return`, `break`, `continue`, `raise` mean that we jump from a branch out.
|
Unstructured control flow keywords as `return`, `break`, `continue`, `raise` mean that we jump from a branch out.
|
||||||
This means that if there is code after the finishing of the branch, it would be run if one hasn't hit the direct parent branch of those: so it is similar to an `else`. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g.
|
This means that if there is code after the finishing of the branch, it would be run if one hasn't hit the direct parent branch of those: so it is similar to an `else`. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
for a in c:
|
for a in c:
|
||||||
if not a.isNil:
|
if not a.isNil:
|
||||||
b()
|
b()
|
||||||
break
|
break
|
||||||
code # here a: Nil , because if not, we would have breaked
|
code # here a: Nil , because if not, we would have breaked
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
aliasing
|
aliasing
|
||||||
|
|
@ -214,17 +222,19 @@ Assignments and other changes to nilability can move / move out expressions of s
|
||||||
`move`: Moving `left` to `right` means we remove `left` from its current set and unify it with the `right`'s set.
|
`move`: Moving `left` to `right` means we remove `left` from its current set and unify it with the `right`'s set.
|
||||||
This means it stops being aliased with its previous aliases.
|
This means it stops being aliased with its previous aliases.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var left = b
|
var left = b
|
||||||
left = right # moving left to right
|
left = right # moving left to right
|
||||||
|
```
|
||||||
|
|
||||||
`move out`: Moving out `left` might remove it from the current set and ensure that it's in its own set as a single element.
|
`move out`: Moving out `left` might remove it from the current set and ensure that it's in its own set as a single element.
|
||||||
e.g.
|
e.g.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var left = b
|
var left = b
|
||||||
left = nil # moving out
|
left = nil # moving out
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
initialization of non nilable and nilable values
|
initialization of non nilable and nilable values
|
||||||
|
|
|
||||||
36
doc/nep1.md
36
doc/nep1.md
|
|
@ -49,7 +49,7 @@ Spacing and Whitespace Conventions
|
||||||
Not all editors support automatic alignment of code sections, and re-aligning
|
Not all editors support automatic alignment of code sections, and re-aligning
|
||||||
long sections of code by hand can quickly become tedious.
|
long sections of code by hand can quickly become tedious.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
# This is bad, as the next time someone comes
|
# This is bad, as the next time someone comes
|
||||||
# to edit this code block, they
|
# to edit this code block, they
|
||||||
# must re-align all the assignments again:
|
# must re-align all the assignments again:
|
||||||
|
|
@ -60,6 +60,7 @@ Spacing and Whitespace Conventions
|
||||||
CalId* = int
|
CalId* = int
|
||||||
LongLong* = int64
|
LongLong* = int64
|
||||||
LongLongPtr* = ptr LongLong
|
LongLongPtr* = ptr LongLong
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Naming Conventions
|
Naming Conventions
|
||||||
|
|
@ -69,7 +70,7 @@ Naming Conventions
|
||||||
camelCase with the exception of constants which **may** use PascalCase but
|
camelCase with the exception of constants which **may** use PascalCase but
|
||||||
are not required to.
|
are not required to.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
# Constants can start with either a lower case or upper case letter.
|
# Constants can start with either a lower case or upper case letter.
|
||||||
const aConstant = 42
|
const aConstant = 42
|
||||||
const FooBar = 4.2
|
const FooBar = 4.2
|
||||||
|
|
@ -79,6 +80,7 @@ Naming Conventions
|
||||||
# Types must start with an uppercase letter.
|
# Types must start with an uppercase letter.
|
||||||
type
|
type
|
||||||
FooBar = object
|
FooBar = object
|
||||||
|
```
|
||||||
|
|
||||||
For constants coming from a C/C++ wrapper, ALL_UPPERCASE are allowed, but ugly.
|
For constants coming from a C/C++ wrapper, ALL_UPPERCASE are allowed, but ugly.
|
||||||
(Why shout CONSTANT? Constants do no harm, variables do!)
|
(Why shout CONSTANT? Constants do no harm, variables do!)
|
||||||
|
|
@ -89,41 +91,45 @@ Naming Conventions
|
||||||
that will be used the most, add the suffixes to the pointer variants only. The
|
that will be used the most, add the suffixes to the pointer variants only. The
|
||||||
same applies to C/C++ wrappers.
|
same applies to C/C++ wrappers.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
Handle = object # Will be used most often
|
Handle = object # Will be used most often
|
||||||
fd: int64
|
fd: int64
|
||||||
HandleRef = ref Handle # Will be used less often
|
HandleRef = ref Handle # Will be used less often
|
||||||
|
```
|
||||||
|
|
||||||
- Exception and Error types should have the "Error" or "Defect" suffix.
|
- Exception and Error types should have the "Error" or "Defect" suffix.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
ValueError = object of CatchableError
|
ValueError = object of CatchableError
|
||||||
AssertionDefect = object of Defect
|
AssertionDefect = object of Defect
|
||||||
Foo = object of Exception # bad style, try to inherit CatchableError or Defect
|
Foo = object of Exception # bad style, try to inherit CatchableError or Defect
|
||||||
|
```
|
||||||
|
|
||||||
- Unless marked with the `{.pure.}` pragma, members of enums should have an
|
- Unless marked with the `{.pure.}` pragma, members of enums should have an
|
||||||
identifying prefix, such as an abbreviation of the enum's name.
|
identifying prefix, such as an abbreviation of the enum's name.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
PathComponent = enum
|
PathComponent = enum
|
||||||
pcDir
|
pcDir
|
||||||
pcLinkToDir
|
pcLinkToDir
|
||||||
pcFile
|
pcFile
|
||||||
pcLinkToFile
|
pcLinkToFile
|
||||||
|
```
|
||||||
|
|
||||||
- Non-pure enum values should use camelCase whereas pure enum values should use
|
- Non-pure enum values should use camelCase whereas pure enum values should use
|
||||||
PascalCase.
|
PascalCase.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
PathComponent {.pure.} = enum
|
PathComponent {.pure.} = enum
|
||||||
Dir
|
Dir
|
||||||
LinkToDir
|
LinkToDir
|
||||||
File
|
File
|
||||||
LinkToFile
|
LinkToFile
|
||||||
|
```
|
||||||
|
|
||||||
- In the age of HTTP, HTML, FTP, TCP, IP, UTF, WWW it is foolish to pretend
|
- In the age of HTTP, HTML, FTP, TCP, IP, UTF, WWW it is foolish to pretend
|
||||||
these are somewhat special words requiring all uppercase. Instead treat them
|
these are somewhat special words requiring all uppercase. Instead treat them
|
||||||
|
|
@ -230,12 +236,13 @@ Coding Conventions
|
||||||
are required. Use a procedure's implicit `result` variable whenever possible.
|
are required. Use a procedure's implicit `result` variable whenever possible.
|
||||||
This improves readability.
|
This improves readability.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc repeat(text: string, x: int): string =
|
proc repeat(text: string, x: int): string =
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
for i in 0..x:
|
for i in 0..x:
|
||||||
result.add($i)
|
result.add($i)
|
||||||
|
```
|
||||||
|
|
||||||
- Use a proc when possible, only using the more powerful facilities of macros,
|
- Use a proc when possible, only using the more powerful facilities of macros,
|
||||||
templates, iterators, and converters when necessary.
|
templates, iterators, and converters when necessary.
|
||||||
|
|
@ -252,15 +259,16 @@ Conventions for multi-line statements and expressions
|
||||||
- Tuples which are longer than one line should indent their parameters to
|
- Tuples which are longer than one line should indent their parameters to
|
||||||
align with the parameters above it.
|
align with the parameters above it.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
LongTupleA = tuple[wordyTupleMemberOne: int, wordyTupleMemberTwo: string,
|
LongTupleA = tuple[wordyTupleMemberOne: int, wordyTupleMemberTwo: string,
|
||||||
wordyTupleMemberThree: float]
|
wordyTupleMemberThree: float]
|
||||||
|
```
|
||||||
|
|
||||||
- Similarly, any procedure and procedure type declarations that are longer
|
- Similarly, any procedure and procedure type declarations that are longer
|
||||||
than one line should do the same thing.
|
than one line should do the same thing.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
EventCallback = proc (timeReceived: Time, errorCode: int, event: Event,
|
EventCallback = proc (timeReceived: Time, errorCode: int, event: Event,
|
||||||
output: var string)
|
output: var string)
|
||||||
|
|
@ -268,13 +276,15 @@ Conventions for multi-line statements and expressions
|
||||||
proc lotsOfArguments(argOne: string, argTwo: int, argThree: float,
|
proc lotsOfArguments(argOne: string, argTwo: int, argThree: float,
|
||||||
argFour: proc(), argFive: bool): int
|
argFour: proc(), argFive: bool): int
|
||||||
{.heyLookALongPragma.} =
|
{.heyLookALongPragma.} =
|
||||||
|
```
|
||||||
|
|
||||||
- Multi-line procedure calls should continue on the same column as the opening
|
- Multi-line procedure calls should continue on the same column as the opening
|
||||||
parenthesis (like multi-line procedure declarations).
|
parenthesis (like multi-line procedure declarations).
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
startProcess(nimExecutable, currentDirectory, compilerArguments
|
startProcess(nimExecutable, currentDirectory, compilerArguments
|
||||||
environment, processOptions)
|
environment, processOptions)
|
||||||
|
```
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -290,18 +300,20 @@ Miscellaneous
|
||||||
|
|
||||||
use this:
|
use this:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
let a = """
|
let a = """
|
||||||
foo
|
foo
|
||||||
bar
|
bar
|
||||||
"""
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
instead of:
|
instead of:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
let a = """foo
|
let a = """foo
|
||||||
bar
|
bar
|
||||||
"""
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
- A getter API for a private field `foo` should preferably be named `foo`, not `getFoo`.
|
- A getter API for a private field `foo` should preferably be named `foo`, not `getFoo`.
|
||||||
A getter-like API should preferably be named `getFoo`, not `foo` if:
|
A getter-like API should preferably be named `getFoo`, not `foo` if:
|
||||||
|
|
|
||||||
76
doc/nimc.md
76
doc/nimc.md
|
|
@ -219,15 +219,15 @@ Command-line settings have priority over configuration file settings.
|
||||||
The default build of a project is a `debug build`:idx:. To compile a
|
The default build of a project is a `debug build`:idx:. To compile a
|
||||||
`release build`:idx: define the `release` symbol:
|
`release build`:idx: define the `release` symbol:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c -d:release myproject.nim
|
nim c -d:release myproject.nim
|
||||||
|
```
|
||||||
|
|
||||||
To compile a `dangerous release build`:idx: define the `danger` symbol:
|
To compile a `dangerous release build`:idx: define the `danger` symbol:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c -d:danger myproject.nim
|
nim c -d:danger myproject.nim
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Search path handling
|
Search path handling
|
||||||
|
|
@ -281,9 +281,9 @@ Compiler Selection
|
||||||
|
|
||||||
To change the compiler from the default compiler (at the command line):
|
To change the compiler from the default compiler (at the command line):
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --cc:llvm_gcc --compile_only myfile.nim
|
nim c --cc:llvm_gcc --compile_only myfile.nim
|
||||||
|
```
|
||||||
|
|
||||||
This uses the configuration defined in ``config\nim.cfg`` for `llvm_gcc`:cmd:.
|
This uses the configuration defined in ``config\nim.cfg`` for `llvm_gcc`:cmd:.
|
||||||
|
|
||||||
|
|
@ -303,18 +303,18 @@ Cross-compilation
|
||||||
|
|
||||||
To cross compile, use for example:
|
To cross compile, use for example:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --cpu:i386 --os:linux --compileOnly --genScript myproject.nim
|
nim c --cpu:i386 --os:linux --compileOnly --genScript myproject.nim
|
||||||
|
```
|
||||||
|
|
||||||
Then move the C code and the compile script `compile_myproject.sh`:cmd: to your
|
Then move the C code and the compile script `compile_myproject.sh`:cmd: to your
|
||||||
Linux i386 machine and run the script.
|
Linux i386 machine and run the script.
|
||||||
|
|
||||||
Another way is to make Nim invoke a cross compiler toolchain:
|
Another way is to make Nim invoke a cross compiler toolchain:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --cpu:arm --os:linux myproject.nim
|
nim c --cpu:arm --os:linux myproject.nim
|
||||||
|
```
|
||||||
|
|
||||||
For cross compilation, the compiler invokes a C compiler named
|
For cross compilation, the compiler invokes a C compiler named
|
||||||
like `$cpu.$os.$cc` (for example arm.linux.gcc) and the configuration
|
like `$cpu.$os.$cc` (for example arm.linux.gcc) and the configuration
|
||||||
|
|
@ -330,22 +330,22 @@ Cross-compilation for Windows
|
||||||
|
|
||||||
To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:
|
To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c -d:mingw myproject.nim
|
nim c -d:mingw myproject.nim
|
||||||
# `nim r` also works, running the binary via `wine` or `wine64`:
|
# `nim r` also works, running the binary via `wine` or `wine64`:
|
||||||
nim r -d:mingw --eval:'import os; echo "a" / "b"'
|
nim r -d:mingw --eval:'import os; echo "a" / "b"'
|
||||||
|
```
|
||||||
|
|
||||||
Use `--cpu:i386`:option: or `--cpu:amd64`:option: to switch the CPU architecture.
|
Use `--cpu:i386`:option: or `--cpu:amd64`:option: to switch the CPU architecture.
|
||||||
|
|
||||||
The MinGW-w64 toolchain can be installed as follows:
|
The MinGW-w64 toolchain can be installed as follows:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
apt install mingw-w64 # Ubuntu
|
apt install mingw-w64 # Ubuntu
|
||||||
yum install mingw32-gcc
|
yum install mingw32-gcc
|
||||||
yum install mingw64-gcc # CentOS - requires EPEL
|
yum install mingw64-gcc # CentOS - requires EPEL
|
||||||
brew install mingw-w64 # OSX
|
brew install mingw-w64 # OSX
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Cross-compilation for Android
|
Cross-compilation for Android
|
||||||
|
|
@ -380,11 +380,11 @@ stuff is done, it's very important to call `NimMain()`:c: in order to
|
||||||
initialize Nim's garbage collector and to run the top level statements
|
initialize Nim's garbage collector and to run the top level statements
|
||||||
of your program.
|
of your program.
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
|
|
||||||
proc NimMain() {.importc.}
|
proc NimMain() {.importc.}
|
||||||
proc glfmMain*(display: ptr GLFMDisplay) {.exportc.} =
|
proc glfmMain*(display: ptr GLFMDisplay) {.exportc.} =
|
||||||
NimMain() # initialize garbage collector memory, types and stack
|
NimMain() # initialize garbage collector memory, types and stack
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||||
|
|
@ -410,11 +410,11 @@ the iOS setup is done, it's very important to call `NimMain()`:c: to
|
||||||
initialize Nim's garbage collector and to run the top-level statements
|
initialize Nim's garbage collector and to run the top-level statements
|
||||||
of your program.
|
of your program.
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
|
|
||||||
proc NimMain() {.importc.}
|
proc NimMain() {.importc.}
|
||||||
proc glfmMain*(display: ptr GLFMDisplay) {.exportc.} =
|
proc glfmMain*(display: ptr GLFMDisplay) {.exportc.} =
|
||||||
NimMain() # initialize garbage collector memory, types and stack
|
NimMain() # initialize garbage collector memory, types and stack
|
||||||
|
```
|
||||||
|
|
||||||
Note: XCode's "make clean" gets confused about the generated nim.c files,
|
Note: XCode's "make clean" gets confused about the generated nim.c files,
|
||||||
so you need to clean those files manually to do a clean build.
|
so you need to clean those files manually to do a clean build.
|
||||||
|
|
@ -430,9 +430,10 @@ Simply add `--os:nintendoswitch`:option:
|
||||||
to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option:
|
to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option:
|
||||||
and `passL`:option: command line switches to something like:
|
and `passL`:option: command line switches to something like:
|
||||||
|
|
||||||
.. code-block:: cmd
|
```cmd
|
||||||
nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
||||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||||
|
```
|
||||||
|
|
||||||
or setup a ``nim.cfg`` file like so::
|
or setup a ``nim.cfg`` file like so::
|
||||||
|
|
||||||
|
|
@ -448,9 +449,9 @@ The devkitPro setup must be the same as the default with their new installer
|
||||||
|
|
||||||
For example, with the above-mentioned config:
|
For example, with the above-mentioned config:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --os:nintendoswitch switchhomebrew.nim
|
nim c --os:nintendoswitch switchhomebrew.nim
|
||||||
|
```
|
||||||
|
|
||||||
This will generate a file called ``switchhomebrew.elf`` which can then be turned into
|
This will generate a file called ``switchhomebrew.elf`` which can then be turned into
|
||||||
an nro file with the `elf2nro`:cmd: tool in the devkitPro release. Examples can be found at
|
an nro file with the `elf2nro`:cmd: tool in the devkitPro release. Examples can be found at
|
||||||
|
|
@ -475,15 +476,15 @@ instance of the GC per process/address space. This instance is contained in
|
||||||
``nimrtl.dll``. This means that every generated Nim DLL depends
|
``nimrtl.dll``. This means that every generated Nim DLL depends
|
||||||
on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:
|
on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c -d:release lib/nimrtl.nim
|
nim c -d:release lib/nimrtl.nim
|
||||||
|
```
|
||||||
|
|
||||||
To link against ``nimrtl.dll`` use the command:
|
To link against ``nimrtl.dll`` use the command:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c -d:useNimRtl myprog.nim
|
nim c -d:useNimRtl myprog.nim
|
||||||
|
```
|
||||||
|
|
||||||
**Note**: Currently the creation of ``nimrtl.dll`` with thread support has
|
**Note**: Currently the creation of ``nimrtl.dll`` with thread support has
|
||||||
never been tested and is unlikely to work!
|
never been tested and is unlikely to work!
|
||||||
|
|
@ -578,9 +579,9 @@ can be prevented and then via `--passL`:option: the static library can be linked
|
||||||
against. For instance, to link statically against Lua this command might work
|
against. For instance, to link statically against Lua this command might work
|
||||||
on Linux:
|
on Linux:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --dynlibOverride:lua --passL:liblua.lib program.nim
|
nim c --dynlibOverride:lua --passL:liblua.lib program.nim
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Backend language options
|
Backend language options
|
||||||
|
|
@ -635,9 +636,9 @@ embedded microprocessors with only a few kilobytes of memory.
|
||||||
A good start is to use the `any` operating target together with the
|
A good start is to use the `any` operating target together with the
|
||||||
`malloc` memory allocator and the `arc` garbage collector. For example:
|
`malloc` memory allocator and the `arc` garbage collector. For example:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
nim c --os:any --mm:arc -d:useMalloc [...] x.nim
|
||||||
nim c --os:any --mm:arc -d:useMalloc [...] x.nim
|
```
|
||||||
|
|
||||||
- `--mm:arc`:option: will enable the reference counting memory management instead
|
- `--mm:arc`:option: will enable the reference counting memory management instead
|
||||||
of the default garbage collector. This enables Nim to use heap memory which
|
of the default garbage collector. This enables Nim to use heap memory which
|
||||||
|
|
@ -760,28 +761,32 @@ passed to subroutines. The compiler does not copy strings that are a result of
|
||||||
a procedure call, because the callee returns a new string anyway.
|
a procedure call, because the callee returns a new string anyway.
|
||||||
Thus it is efficient to do:
|
Thus it is efficient to do:
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
var s = procA() # assignment will not copy the string; procA allocates a new
|
var s = procA() # assignment will not copy the string; procA allocates a new
|
||||||
# string already
|
# string already
|
||||||
|
```
|
||||||
|
|
||||||
However, it is not efficient to do:
|
However, it is not efficient to do:
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
var s = varA # assignment has to copy the whole string into a new buffer!
|
var s = varA # assignment has to copy the whole string into a new buffer!
|
||||||
|
```
|
||||||
|
|
||||||
For `let` symbols a copy is not always necessary:
|
For `let` symbols a copy is not always necessary:
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
let s = varA # may only copy a pointer if it safe to do so
|
let s = varA # may only copy a pointer if it safe to do so
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
If you know what you're doing, you can also mark single-string (or sequence)
|
If you know what you're doing, you can also mark single-string (or sequence)
|
||||||
objects as `shallow`:idx:\:
|
objects as `shallow`:idx:\:
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
var s = "abc"
|
var s = "abc"
|
||||||
shallow(s) # mark 's' as a shallow string
|
shallow(s) # mark 's' as a shallow string
|
||||||
var x = s # now might not copy the string!
|
var x = s # now might not copy the string!
|
||||||
|
```
|
||||||
|
|
||||||
Usage of `shallow` is always safe once you know the string won't be modified
|
Usage of `shallow` is always safe once you know the string won't be modified
|
||||||
anymore, similar to Ruby's `freeze`:idx:.
|
anymore, similar to Ruby's `freeze`:idx:.
|
||||||
|
|
@ -791,7 +796,7 @@ The compiler optimizes string case statements: A hashing scheme is used for them
|
||||||
if several different string constants are used. So code like this is reasonably
|
if several different string constants are used. So code like this is reasonably
|
||||||
efficient:
|
efficient:
|
||||||
|
|
||||||
.. code-block:: Nim
|
```Nim
|
||||||
case normalize(k.key)
|
case normalize(k.key)
|
||||||
of "name": c.name = v
|
of "name": c.name = v
|
||||||
of "displayname": c.displayName = v
|
of "displayname": c.displayName = v
|
||||||
|
|
@ -807,3 +812,4 @@ efficient:
|
||||||
else: quit(errorStr(p, "expected: console or gui"))
|
else: quit(errorStr(p, "expected: console or gui"))
|
||||||
of "license": c.license = UnixToNativePath(k.value)
|
of "license": c.license = UnixToNativePath(k.value)
|
||||||
else: quit(errorStr(p, "unknown variable: " & k.key))
|
else: quit(errorStr(p, "unknown variable: " & k.key))
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ Installation
|
||||||
|
|
||||||
Compile nimgrep with the command:
|
Compile nimgrep with the command:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
nim c -d:release tools/nimgrep.nim
|
nim c -d:release tools/nimgrep.nim
|
||||||
|
```
|
||||||
|
|
||||||
And copy the executable somewhere in your ``$PATH``.
|
And copy the executable somewhere in your ``$PATH``.
|
||||||
|
|
||||||
|
|
@ -40,9 +41,10 @@ All examples below use default PCRE Regex patterns:
|
||||||
|
|
||||||
+ To search recursively in Nim files using style-insensitive identifiers:
|
+ To search recursively in Nim files using style-insensitive identifiers:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
nimgrep --recursive --ext:'nim|nims' --ignoreStyle
|
nimgrep --recursive --ext:'nim|nims' --ignoreStyle
|
||||||
# short: -r --ext:'nim|nims' -y
|
# short: -r --ext:'nim|nims' -y
|
||||||
|
```
|
||||||
|
|
||||||
.. Note:: we used `'` quotes to avoid special treatment of `|` symbol
|
.. Note:: we used `'` quotes to avoid special treatment of `|` symbol
|
||||||
for shells like Bash
|
for shells like Bash
|
||||||
|
|
@ -50,15 +52,17 @@ All examples below use default PCRE Regex patterns:
|
||||||
+ To exclude version control directories (Git, Mercurial=hg, Subversion=svn)
|
+ To exclude version control directories (Git, Mercurial=hg, Subversion=svn)
|
||||||
from the search:
|
from the search:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
nimgrep --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$'
|
nimgrep --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$'
|
||||||
# short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$'
|
# short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$'
|
||||||
|
```
|
||||||
|
|
||||||
+ To search only in paths containing the `tests` sub-directory recursively:
|
+ To search only in paths containing the `tests` sub-directory recursively:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
nimgrep --recursive --includeDir:'(^|/)tests($|/)'
|
nimgrep --recursive --includeDir:'(^|/)tests($|/)'
|
||||||
# short: -r --id:'(^|/)tests($|/)'
|
# short: -r --id:'(^|/)tests($|/)'
|
||||||
|
```
|
||||||
|
|
||||||
.. Attention:: note the subtle difference between `--excludeDir`:option: and
|
.. Attention:: note the subtle difference between `--excludeDir`:option: and
|
||||||
`--includeDir`:option:\: the former is applied to relative directory entries
|
`--includeDir`:option:\: the former is applied to relative directory entries
|
||||||
|
|
|
||||||
33
doc/nims.md
33
doc/nims.md
|
|
@ -118,22 +118,24 @@ NimScript. Similarly, command-line `--FOO:VAL`:option: translates to
|
||||||
|
|
||||||
Here are few examples of using the `switch` proc:
|
Here are few examples of using the `switch` proc:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
# command-line: --opt:size
|
# command-line: --opt:size
|
||||||
switch("opt", "size")
|
switch("opt", "size")
|
||||||
# command-line: --define:release or -d:release
|
# command-line: --define:release or -d:release
|
||||||
switch("define", "release")
|
switch("define", "release")
|
||||||
# command-line: --forceBuild
|
# command-line: --forceBuild
|
||||||
switch("forceBuild")
|
switch("forceBuild")
|
||||||
|
```
|
||||||
|
|
||||||
NimScripts also support `--`:option: templates for convenience, which look
|
NimScripts also support `--`:option: templates for convenience, which look
|
||||||
like command-line switches written as-is in the NimScript file. So the
|
like command-line switches written as-is in the NimScript file. So the
|
||||||
above example can be rewritten as:
|
above example can be rewritten as:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
--opt:size
|
--opt:size
|
||||||
--define:release
|
--define:release
|
||||||
--forceBuild
|
--forceBuild
|
||||||
|
```
|
||||||
|
|
||||||
**Note**: In general, the *define* switches can also be set in
|
**Note**: In general, the *define* switches can also be set in
|
||||||
NimScripts using `switch` or `--`, as shown in above examples. Few
|
NimScripts using `switch` or `--`, as shown in above examples. Few
|
||||||
|
|
@ -148,9 +150,10 @@ The `task` template that the `system` module defines allows a NimScript
|
||||||
file to be used as a build tool. The following example defines a
|
file to be used as a build tool. The following example defines a
|
||||||
task `build` that is an alias for the `c`:option: command:
|
task `build` that is an alias for the `c`:option: command:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
task build, "builds an example":
|
task build, "builds an example":
|
||||||
setCommand "c"
|
setCommand "c"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
In fact, as a convention the following tasks should be available:
|
In fact, as a convention the following tasks should be available:
|
||||||
|
|
@ -184,8 +187,7 @@ NimScript can also be used directly as a portable replacement for Bash and
|
||||||
Batch files. Use `nim myscript.nims`:cmd: to run ``myscript.nims``. For example,
|
Batch files. Use `nim myscript.nims`:cmd: to run ``myscript.nims``. For example,
|
||||||
installation of Nimble could be accomplished with this simple script:
|
installation of Nimble could be accomplished with this simple script:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
mode = ScriptMode.Verbose
|
mode = ScriptMode.Verbose
|
||||||
|
|
||||||
var id = 0
|
var id = 0
|
||||||
|
|
@ -198,16 +200,17 @@ installation of Nimble could be accomplished with this simple script:
|
||||||
exec "nim c nimble"
|
exec "nim c nimble"
|
||||||
|
|
||||||
mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
|
mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
|
||||||
|
```
|
||||||
|
|
||||||
On Unix, you can also use the shebang `#!/usr/bin/env nim`, as long as your filename
|
On Unix, you can also use the shebang `#!/usr/bin/env nim`, as long as your filename
|
||||||
ends with ``.nims``:
|
ends with ``.nims``:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
#!/usr/bin/env nim
|
#!/usr/bin/env nim
|
||||||
mode = ScriptMode.Silent
|
mode = ScriptMode.Silent
|
||||||
|
|
||||||
echo "hello world"
|
echo "hello world"
|
||||||
|
```
|
||||||
|
|
||||||
Use `#!/usr/bin/env -S nim --hints:off` to disable hints.
|
Use `#!/usr/bin/env -S nim --hints:off` to disable hints.
|
||||||
|
|
||||||
|
|
@ -229,8 +232,7 @@ allowing the same script to support a lot of systems.
|
||||||
|
|
||||||
See the following (incomplete) example:
|
See the following (incomplete) example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
import std/distros
|
import std/distros
|
||||||
|
|
||||||
# Architectures.
|
# Architectures.
|
||||||
|
|
@ -256,6 +258,7 @@ See the following (incomplete) example:
|
||||||
echo "Distro is ArchLinux"
|
echo "Distro is ArchLinux"
|
||||||
elif detectOs(Debian):
|
elif detectOs(Debian):
|
||||||
echo "Distro is Debian"
|
echo "Distro is Debian"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Uniform Syntax
|
Uniform Syntax
|
||||||
|
|
@ -277,21 +280,21 @@ making it ideal for functional scripting metaprogramming.
|
||||||
This is an example of a third party module that uses macros and templates to
|
This is an example of a third party module that uses macros and templates to
|
||||||
translate text strings on unmodified NimScript:
|
translate text strings on unmodified NimScript:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
import nimterlingua
|
import nimterlingua
|
||||||
nimterlingua("translations.cfg")
|
nimterlingua("translations.cfg")
|
||||||
echo "cat" # Run with -d:RU becomes "kot", -d:ES becomes "gato", ...
|
echo "cat" # Run with -d:RU becomes "kot", -d:ES becomes "gato", ...
|
||||||
|
```
|
||||||
|
|
||||||
translations.cfg
|
translations.cfg
|
||||||
|
|
||||||
.. code-block:: none
|
```none
|
||||||
|
|
||||||
[cat]
|
[cat]
|
||||||
ES = gato
|
ES = gato
|
||||||
IT = gatto
|
IT = gatto
|
||||||
RU = kot
|
RU = kot
|
||||||
FR = chat
|
FR = chat
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
* `Nimterlingua <https://nimble.directory/pkg/nimterlingua>`_
|
* `Nimterlingua <https://nimble.directory/pkg/nimterlingua>`_
|
||||||
|
|
@ -305,8 +308,7 @@ but often a graceful and seamless fallback degradation is used.
|
||||||
|
|
||||||
See the following NimScript:
|
See the following NimScript:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
if likely(true):
|
if likely(true):
|
||||||
discard
|
discard
|
||||||
elif unlikely(false):
|
elif unlikely(false):
|
||||||
|
|
@ -316,6 +318,7 @@ See the following NimScript:
|
||||||
|
|
||||||
static:
|
static:
|
||||||
echo CompileDate
|
echo CompileDate
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
`likely()`, `unlikely()`, `static:` and `{.compiletime.}`
|
`likely()`, `unlikely()`, `static:` and `{.compiletime.}`
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,9 @@ Installation
|
||||||
|
|
||||||
Nimsuggest is part of Nim's core. Build it via:
|
Nimsuggest is part of Nim's core. Build it via:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
koch nimsuggest
|
koch nimsuggest
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Nimsuggest invocation
|
Nimsuggest invocation
|
||||||
|
|
|
||||||
|
|
@ -48,24 +48,24 @@ The Debian package ships bash and ksh completion and manpages that can be reused
|
||||||
|
|
||||||
Hints on the build process:
|
Hints on the build process:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
# build from C sources and then using koch
|
||||||
|
make -j # supports parallel build
|
||||||
|
# alternatively: ./build.sh --os $os_type --cpu $cpu_arch
|
||||||
|
./bin/nim c -d:release koch
|
||||||
|
./koch boot -d:release
|
||||||
|
|
||||||
# build from C sources and then using koch
|
# optionally generate docs into doc/html
|
||||||
make -j # supports parallel build
|
./koch docs
|
||||||
# alternatively: ./build.sh --os $os_type --cpu $cpu_arch
|
|
||||||
./bin/nim c -d:release koch
|
|
||||||
./koch boot -d:release
|
|
||||||
|
|
||||||
# optionally generate docs into doc/html
|
./koch tools
|
||||||
./koch docs
|
|
||||||
|
|
||||||
./koch tools
|
# extract files to be really installed
|
||||||
|
./install.sh <tempdir>
|
||||||
|
|
||||||
# extract files to be really installed
|
# also include the tools
|
||||||
./install.sh <tempdir>
|
for fn in nimble nimsuggest nimgrep; do cp ./bin/$fn <tempdir>/nim/bin/; done
|
||||||
|
```
|
||||||
# also include the tools
|
|
||||||
for fn in nimble nimsuggest nimgrep; do cp ./bin/$fn <tempdir>/nim/bin/; done
|
|
||||||
|
|
||||||
What to install:
|
What to install:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,8 +175,9 @@ The PEG parser implements this grammar (written in PEG syntax)::
|
||||||
expression, identifiers are not interpreted as non-terminals, but are
|
expression, identifiers are not interpreted as non-terminals, but are
|
||||||
interpreted as verbatim string:
|
interpreted as verbatim string:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
abc =~ peg"abc" # is true
|
abc =~ peg"abc" # is true
|
||||||
|
```
|
||||||
|
|
||||||
So it is not necessary to write ``peg" 'abc' "`` in the above example.
|
So it is not necessary to write ``peg" 'abc' "`` in the above example.
|
||||||
|
|
||||||
|
|
@ -186,22 +187,25 @@ Examples
|
||||||
|
|
||||||
Check if `s` matches Nim's "while" keyword:
|
Check if `s` matches Nim's "while" keyword:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
s =~ peg" y'while'"
|
s =~ peg" y'while'"
|
||||||
|
```
|
||||||
|
|
||||||
Exchange (key, val)-pairs:
|
Exchange (key, val)-pairs:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
"key: val; key2: val2".replacef(peg"{\ident} \s* ':' \s* {\ident}", "$2: $1")
|
"key: val; key2: val2".replacef(peg"{\ident} \s* ':' \s* {\ident}", "$2: $1")
|
||||||
|
```
|
||||||
|
|
||||||
Determine the ``#include``'ed files of a C file:
|
Determine the ``#include``'ed files of a C file:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
for line in lines("myfile.c"):
|
for line in lines("myfile.c"):
|
||||||
if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws
|
if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws
|
||||||
comment <- '/*' @ '*/' / '//' .*
|
comment <- '/*' @ '*/' / '//' .*
|
||||||
ws <- (comment / \s+)* """:
|
ws <- (comment / \s+)* """:
|
||||||
echo matches[0]
|
echo matches[0]
|
||||||
|
```
|
||||||
|
|
||||||
PEG vs regular expression
|
PEG vs regular expression
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
|
||||||
12
doc/refc.md
12
doc/refc.md
|
|
@ -16,9 +16,10 @@ defined via `--define:useRealtimeGC`:option: (you can put this into your config
|
||||||
file as well).
|
file as well).
|
||||||
With this switch the garbage collector supports the following operations:
|
With this switch the garbage collector supports the following operations:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc GC_setMaxPause*(maxPauseInUs: int)
|
proc GC_setMaxPause*(maxPauseInUs: int)
|
||||||
proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
|
proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
|
||||||
|
```
|
||||||
|
|
||||||
The unit of the parameters `maxPauseInUs` and `us` is microseconds.
|
The unit of the parameters `maxPauseInUs` and `us` is microseconds.
|
||||||
|
|
||||||
|
|
@ -98,9 +99,9 @@ As long as you don't use the threadvar emulation Nim uses native thread
|
||||||
variables, of which you get a fresh version whenever you create a thread. You
|
variables, of which you get a fresh version whenever you create a thread. You
|
||||||
can then attach a GC to this thread via
|
can then attach a GC to this thread via
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
system.setupForeignThreadGc()
|
system.setupForeignThreadGc()
|
||||||
|
```
|
||||||
|
|
||||||
It is **not** safe to disable the garbage collector and enable it after the
|
It is **not** safe to disable the garbage collector and enable it after the
|
||||||
call from your background thread even if the code you are calling is short
|
call from your background thread even if the code you are calling is short
|
||||||
|
|
@ -109,10 +110,9 @@ lived.
|
||||||
Before the thread exits, you should tear down the thread's GC to prevent memory
|
Before the thread exits, you should tear down the thread's GC to prevent memory
|
||||||
leaks by calling
|
leaks by calling
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
system.tearDownForeignThreadGc()
|
system.tearDownForeignThreadGc()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Keeping track of memory
|
Keeping track of memory
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ range `0 .. MaxSetElements-1` where `MaxSetElements` is currently always
|
||||||
The reason is that sets are implemented as high performance bit vectors.
|
The reason is that sets are implemented as high performance bit vectors.
|
||||||
Attempting to declare a set with a larger type will result in an error:
|
Attempting to declare a set with a larger type will result in an error:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
var s: set[int64] # Error: set is too large
|
var s: set[int64] # Error: set is too large
|
||||||
|
```
|
||||||
|
|
||||||
**Note:** Nim also offers `hash sets <sets.html>`_ (which you need to import
|
**Note:** Nim also offers `hash sets <sets.html>`_ (which you need to import
|
||||||
with `import sets`), which have no such restrictions.
|
with `import sets`), which have no such restrictions.
|
||||||
|
|
@ -24,7 +24,7 @@ Sets can be constructed via the set constructor: `{}` is the empty set. The
|
||||||
empty set is type compatible with any concrete set type. The constructor
|
empty set is type compatible with any concrete set type. The constructor
|
||||||
can also be used to include elements (and ranges of elements):
|
can also be used to include elements (and ranges of elements):
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
type
|
type
|
||||||
CharSet = set[char]
|
CharSet = set[char]
|
||||||
var
|
var
|
||||||
|
|
@ -32,6 +32,7 @@ can also be used to include elements (and ranges of elements):
|
||||||
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
|
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
|
||||||
# letters from 'a' to 'z' and the digits
|
# letters from 'a' to 'z' and the digits
|
||||||
# from '0' to '9'
|
# from '0' to '9'
|
||||||
|
```
|
||||||
|
|
||||||
These operations are supported by sets:
|
These operations are supported by sets:
|
||||||
|
|
||||||
|
|
@ -60,8 +61,7 @@ constants that have to be `or`'ed together.
|
||||||
|
|
||||||
Enum, sets and casting can be used together as in:
|
Enum, sets and casting can be used together as in:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
MyFlag* {.size: sizeof(cint).} = enum
|
MyFlag* {.size: sizeof(cint).} = enum
|
||||||
A
|
A
|
||||||
|
|
@ -79,6 +79,7 @@ Enum, sets and casting can be used together as in:
|
||||||
assert toNum({A, C}) == 5
|
assert toNum({A, C}) == 5
|
||||||
assert toFlags(0) == {}
|
assert toFlags(0) == {}
|
||||||
assert toFlags(7) == {A, B, C}
|
assert toFlags(7) == {A, B, C}
|
||||||
|
```
|
||||||
|
|
||||||
Note how the set turns enum values into powers of 2.
|
Note how the set turns enum values into powers of 2.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ the passed expression on the thread pool and returns a `data flow variable`:idx:
|
||||||
**blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow
|
**blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow
|
||||||
variables at the same time:
|
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:
|
||||||
|
|
@ -40,6 +40,7 @@ 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
|
Data flow variables ensure that no data races
|
||||||
are possible. Due to technical limitations not every type ``T`` is possible in
|
are possible. Due to technical limitations not every type ``T`` is possible in
|
||||||
|
|
@ -54,7 +55,7 @@ Parallel statement
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
# Compute PI in an inefficient way
|
# Compute PI in an inefficient way
|
||||||
import std/[strutils, math, threadpool]
|
import std/[strutils, math, threadpool]
|
||||||
|
|
||||||
|
|
@ -69,6 +70,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
|
The parallel statement is the preferred mechanism to introduce parallelism
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,7 @@ Notation meaning
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
|
subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
|
||||||
|
|
||||||
subex"$1 $[files|file|files]{1} copied" % ["1"] == "1 file copied"
|
subex"$1 $[files|file|files]{1} copied" % ["1"] == "1 file copied"
|
||||||
|
|
@ -57,5 +56,5 @@ Examples
|
||||||
|
|
||||||
subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
|
subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
|
||||||
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
|
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,29 +53,29 @@ Running a single test
|
||||||
This is a minimal example to understand the basics,
|
This is a minimal example to understand the basics,
|
||||||
not very useful for production, but easy to understand:
|
not very useful for production, but easy to understand:
|
||||||
|
|
||||||
.. code:: console
|
```console
|
||||||
|
|
||||||
$ mkdir tests
|
$ mkdir tests
|
||||||
$ echo "assert 42 == 42" > tests/test0.nim
|
$ echo "assert 42 == 42" > tests/test0.nim
|
||||||
$ testament run test0.nim
|
$ testament run test0.nim
|
||||||
PASS: tests/test0.nim C ( 0.2 sec)
|
PASS: tests/test0.nim C ( 0.2 sec)
|
||||||
$ testament r test0
|
$ testament r test0
|
||||||
PASS: tests/test0.nim C ( 0.2 sec)
|
PASS: tests/test0.nim C ( 0.2 sec)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Running all tests from a directory
|
Running all tests from a directory
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
.. code:: console
|
```console
|
||||||
|
|
||||||
$ testament pattern "tests/*.nim"
|
$ testament pattern "tests/*.nim"
|
||||||
|
```
|
||||||
|
|
||||||
To search for tests deeper in a directory, use
|
To search for tests deeper in a directory, use
|
||||||
|
|
||||||
.. code:: console
|
```console
|
||||||
|
|
||||||
$ testament pattern "tests/**/*.nim" # one level deeper
|
$ testament pattern "tests/**/*.nim" # one level deeper
|
||||||
$ testament pattern "tests/**/**/*.nim" # two levels deeper
|
$ testament pattern "tests/**/**/*.nim" # two levels deeper
|
||||||
|
```
|
||||||
|
|
||||||
HTML Reports
|
HTML Reports
|
||||||
============
|
============
|
||||||
|
|
@ -83,9 +83,9 @@ HTML Reports
|
||||||
Generate HTML Reports ``testresults.html`` from unittests,
|
Generate HTML Reports ``testresults.html`` from unittests,
|
||||||
you have to run at least 1 test *before* generating a report:
|
you have to run at least 1 test *before* generating a report:
|
||||||
|
|
||||||
.. code:: console
|
```console
|
||||||
|
|
||||||
$ testament html
|
$ testament html
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Writing Unit tests
|
Writing Unit tests
|
||||||
|
|
@ -93,8 +93,7 @@ Writing Unit tests
|
||||||
|
|
||||||
Example "template" **to edit** and write a Testament unittest:
|
Example "template" **to edit** and write a Testament unittest:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
|
|
||||||
# What actions to expect completion on.
|
# What actions to expect completion on.
|
||||||
|
|
@ -182,6 +181,7 @@ Example "template" **to edit** and write a Testament unittest:
|
||||||
"""
|
"""
|
||||||
assert true
|
assert true
|
||||||
assert 42 == 42, "Assert error message"
|
assert 42 == 42, "Assert error message"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
* As you can see the "Spec" is just a `discard """ """`.
|
* As you can see the "Spec" is just a `discard """ """`.
|
||||||
|
|
@ -197,26 +197,25 @@ Unit test Examples
|
||||||
|
|
||||||
Expected to fail:
|
Expected to fail:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
errormsg: "undeclared identifier: 'not_defined'"
|
errormsg: "undeclared identifier: 'not_defined'"
|
||||||
"""
|
"""
|
||||||
assert not_defined == "not_defined", "not_defined is not defined"
|
assert not_defined == "not_defined", "not_defined is not defined"
|
||||||
|
```
|
||||||
|
|
||||||
Non-Zero exit code:
|
Non-Zero exit code:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
exitcode: 1
|
exitcode: 1
|
||||||
"""
|
"""
|
||||||
quit "Non-Zero exit code", 1
|
quit "Non-Zero exit code", 1
|
||||||
|
```
|
||||||
|
|
||||||
Standard output checking:
|
Standard output checking:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
|
|
||||||
output: '''
|
output: '''
|
||||||
|
|
@ -230,32 +229,33 @@ Standard output checking:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for i in 0..5: echo i
|
for i in 0..5: echo i
|
||||||
|
```
|
||||||
|
|
||||||
JavaScript tests:
|
JavaScript tests:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
targets: "js"
|
targets: "js"
|
||||||
"""
|
"""
|
||||||
when defined(js):
|
when defined(js):
|
||||||
import std/jsconsole
|
import std/jsconsole
|
||||||
console.log("My Frontend Project")
|
console.log("My Frontend Project")
|
||||||
|
```
|
||||||
|
|
||||||
Compile-time tests:
|
Compile-time tests:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
action: "compile"
|
action: "compile"
|
||||||
"""
|
"""
|
||||||
static: assert 9 == 9, "Compile time assert"
|
static: assert 9 == 9, "Compile time assert"
|
||||||
|
```
|
||||||
|
|
||||||
Tests without Spec:
|
Tests without Spec:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
assert 1 == 1
|
assert 1 == 1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
See also:
|
See also:
|
||||||
|
|
|
||||||
357
doc/tut1.md
357
doc/tut1.md
File diff suppressed because it is too large
Load diff
94
doc/tut2.md
94
doc/tut2.md
|
|
@ -53,8 +53,7 @@ types with inheritance are also marked as `ref` types even though
|
||||||
this isn't strictly enforced. To check at runtime if an object is of a certain
|
this isn't strictly enforced. To check at runtime if an object is of a certain
|
||||||
type, the `of` operator can be used.
|
type, the `of` operator can be used.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
type
|
type
|
||||||
Person = ref object of RootObj
|
Person = ref object of RootObj
|
||||||
name*: string # the * means that `name` is accessible from other modules
|
name*: string # the * means that `name` is accessible from other modules
|
||||||
|
|
@ -70,6 +69,7 @@ type, the `of` operator can be used.
|
||||||
# object construction:
|
# object construction:
|
||||||
student = Student(name: "Anton", age: 5, id: 2)
|
student = Student(name: "Anton", age: 5, id: 2)
|
||||||
echo student[]
|
echo student[]
|
||||||
|
```
|
||||||
|
|
||||||
Inheritance is done with the `object of` syntax. Multiple inheritance is
|
Inheritance is done with the `object of` syntax. Multiple inheritance is
|
||||||
currently not supported. If an object type has no suitable ancestor, `RootObj`
|
currently not supported. If an object type has no suitable ancestor, `RootObj`
|
||||||
|
|
@ -97,8 +97,7 @@ would require arbitrary symbol lookahead which slows down compilation.)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
type
|
type
|
||||||
Node = ref object # a reference to an object with the following field:
|
Node = ref object # a reference to an object with the following field:
|
||||||
le, ri: Node # left and right subtrees
|
le, ri: Node # left and right subtrees
|
||||||
|
|
@ -108,6 +107,7 @@ Example:
|
||||||
name: string # the symbol's name
|
name: string # the symbol's name
|
||||||
line: int # the line the symbol was declared in
|
line: int # the line the symbol was declared in
|
||||||
code: Node # the symbol's abstract syntax tree
|
code: Node # the symbol's abstract syntax tree
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Type conversions
|
Type conversions
|
||||||
|
|
@ -124,9 +124,10 @@ raised.
|
||||||
The syntax for type conversions is `destination_type(expression_to_convert)`
|
The syntax for type conversions is `destination_type(expression_to_convert)`
|
||||||
(like an ordinary call):
|
(like an ordinary call):
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc getID(x: Person): int =
|
proc getID(x: Person): int =
|
||||||
Student(x).id
|
Student(x).id
|
||||||
|
```
|
||||||
|
|
||||||
The `InvalidObjectConversionDefect` exception is raised if `x` is not a
|
The `InvalidObjectConversionDefect` exception is raised if `x` is not a
|
||||||
`Student`.
|
`Student`.
|
||||||
|
|
@ -139,9 +140,7 @@ variant types are needed.
|
||||||
|
|
||||||
An example:
|
An example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
# This is an example how an abstract syntax tree could be modelled in Nim
|
# This is an example how an abstract syntax tree could be modelled in Nim
|
||||||
type
|
type
|
||||||
NodeKind = enum # the different node types
|
NodeKind = enum # the different node types
|
||||||
|
|
@ -165,6 +164,7 @@ An example:
|
||||||
# the following statement raises an `FieldDefect` exception, because
|
# the following statement raises an `FieldDefect` exception, because
|
||||||
# n.kind's value does not fit:
|
# n.kind's value does not fit:
|
||||||
n.strVal = ""
|
n.strVal = ""
|
||||||
|
```
|
||||||
|
|
||||||
As can been seen from the example, an advantage to an object hierarchy is that
|
As can been seen from the example, an advantage to an object hierarchy is that
|
||||||
no conversion between different object types is needed. Yet, access to invalid
|
no conversion between different object types is needed. Yet, access to invalid
|
||||||
|
|
@ -183,27 +183,27 @@ If there are no remaining arguments, the parentheses can be omitted:
|
||||||
This method call syntax is not restricted to objects, it can be used
|
This method call syntax is not restricted to objects, it can be used
|
||||||
for any type:
|
for any type:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
import std/strutils
|
import std/strutils
|
||||||
|
|
||||||
echo "abc".len # is the same as echo len("abc")
|
echo "abc".len # is the same as echo len("abc")
|
||||||
echo "abc".toUpperAscii()
|
echo "abc".toUpperAscii()
|
||||||
echo({'a', 'b', 'c'}.card)
|
echo({'a', 'b', 'c'}.card)
|
||||||
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
||||||
|
```
|
||||||
|
|
||||||
(Another way to look at the method call syntax is that it provides the missing
|
(Another way to look at the method call syntax is that it provides the missing
|
||||||
postfix notation.)
|
postfix notation.)
|
||||||
|
|
||||||
So "pure object oriented" code is easy to write:
|
So "pure object oriented" code is easy to write:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
import std/[strutils, sequtils]
|
import std/[strutils, sequtils]
|
||||||
|
|
||||||
stdout.writeLine("Give a list of numbers (separated by spaces): ")
|
stdout.writeLine("Give a list of numbers (separated by spaces): ")
|
||||||
stdout.write(stdin.readLine.splitWhitespace.map(parseInt).max.`$`)
|
stdout.write(stdin.readLine.splitWhitespace.map(parseInt).max.`$`)
|
||||||
stdout.writeLine(" is the maximum!")
|
stdout.writeLine(" is the maximum!")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Properties
|
Properties
|
||||||
|
|
@ -213,9 +213,7 @@ Ordinary get-procedures that are called with the *method call syntax* achieve
|
||||||
the same. But setting a value is different; for this a special setter syntax
|
the same. But setting a value is different; for this a special setter syntax
|
||||||
is needed:
|
is needed:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Socket* = ref object of RootObj
|
Socket* = ref object of RootObj
|
||||||
h: int # cannot be accessed from the outside of the module due to missing star
|
h: int # cannot be accessed from the outside of the module due to missing star
|
||||||
|
|
@ -231,6 +229,7 @@ is needed:
|
||||||
var s: Socket
|
var s: Socket
|
||||||
new s
|
new s
|
||||||
s.host = 34 # same as `host=`(s, 34)
|
s.host = 34 # same as `host=`(s, 34)
|
||||||
|
```
|
||||||
|
|
||||||
(The example also shows `inline` procedures.)
|
(The example also shows `inline` procedures.)
|
||||||
|
|
||||||
|
|
@ -238,8 +237,7 @@ is needed:
|
||||||
The `[]` array access operator can be overloaded to provide
|
The `[]` array access operator can be overloaded to provide
|
||||||
`array properties`:idx:\ :
|
`array properties`:idx:\ :
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
type
|
type
|
||||||
Vector* = object
|
Vector* = object
|
||||||
x, y, z: float
|
x, y, z: float
|
||||||
|
|
@ -259,6 +257,7 @@ The `[]` array access operator can be overloaded to provide
|
||||||
of 1: result = v.y
|
of 1: result = v.y
|
||||||
of 2: result = v.z
|
of 2: result = v.z
|
||||||
else: assert(false)
|
else: assert(false)
|
||||||
|
```
|
||||||
|
|
||||||
The example is silly, since a vector is better modelled by a tuple which
|
The example is silly, since a vector is better modelled by a tuple which
|
||||||
already provides `v[]` access.
|
already provides `v[]` access.
|
||||||
|
|
@ -270,8 +269,7 @@ Dynamic dispatch
|
||||||
Procedures always use static dispatch. For dynamic dispatch replace the
|
Procedures always use static dispatch. For dynamic dispatch replace the
|
||||||
`proc` keyword by `method`:
|
`proc` keyword by `method`:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
type
|
type
|
||||||
Expression = ref object of RootObj ## abstract base class for an expression
|
Expression = ref object of RootObj ## abstract base class for an expression
|
||||||
Literal = ref object of Expression
|
Literal = ref object of Expression
|
||||||
|
|
@ -291,6 +289,7 @@ Procedures always use static dispatch. For dynamic dispatch replace the
|
||||||
proc newPlus(a, b: Expression): PlusExpr = PlusExpr(a: a, b: b)
|
proc newPlus(a, b: Expression): PlusExpr = PlusExpr(a: a, b: b)
|
||||||
|
|
||||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
||||||
|
```
|
||||||
|
|
||||||
Note that in the example the constructors `newLit` and `newPlus` are procs
|
Note that in the example the constructors `newLit` and `newPlus` are procs
|
||||||
because it makes more sense for them to use static binding, but `eval` is a
|
because it makes more sense for them to use static binding, but `eval` is a
|
||||||
|
|
@ -302,9 +301,7 @@ method because it requires dynamic binding.
|
||||||
In a multi-method all parameters that have an object type are used for the
|
In a multi-method all parameters that have an object type are used for the
|
||||||
dispatching:
|
dispatching:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c --multiMethods:on $1"
|
||||||
:test: "nim c --multiMethods:on $1"
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Thing = ref object of RootObj
|
Thing = ref object of RootObj
|
||||||
Unit = ref object of Thing
|
Unit = ref object of Thing
|
||||||
|
|
@ -323,6 +320,7 @@ dispatching:
|
||||||
new a
|
new a
|
||||||
new b
|
new b
|
||||||
collide(a, b) # output: 2
|
collide(a, b) # output: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
||||||
|
|
@ -355,20 +353,21 @@ Raise statement
|
||||||
---------------
|
---------------
|
||||||
Raising an exception is done with the `raise` statement:
|
Raising an exception is done with the `raise` statement:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
var
|
var
|
||||||
e: ref OSError
|
e: ref OSError
|
||||||
new(e)
|
new(e)
|
||||||
e.msg = "the request to the OS failed"
|
e.msg = "the request to the OS failed"
|
||||||
raise e
|
raise e
|
||||||
|
```
|
||||||
|
|
||||||
If the `raise` keyword is not followed by an expression, the last exception
|
If the `raise` keyword is not followed by an expression, the last exception
|
||||||
is *re-raised*. For the purpose of avoiding repeating this common code pattern,
|
is *re-raised*. For the purpose of avoiding repeating this common code pattern,
|
||||||
the template `newException` in the `system` module can be used:
|
the template `newException` in the `system` module can be used:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
raise newException(OSError, "the request to the OS failed")
|
raise newException(OSError, "the request to the OS failed")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Try statement
|
Try statement
|
||||||
|
|
@ -376,8 +375,7 @@ Try statement
|
||||||
|
|
||||||
The `try` statement handles exceptions:
|
The `try` statement handles exceptions:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
from std/strutils import parseInt
|
from std/strutils import parseInt
|
||||||
|
|
||||||
# read the first two lines of a text file that should contain numbers
|
# read the first two lines of a text file that should contain numbers
|
||||||
|
|
@ -401,6 +399,7 @@ The `try` statement handles exceptions:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
close(f)
|
close(f)
|
||||||
|
```
|
||||||
|
|
||||||
The statements after the `try` are executed unless an exception is
|
The statements after the `try` are executed unless an exception is
|
||||||
raised. Then the appropriate `except` part is executed.
|
raised. Then the appropriate `except` part is executed.
|
||||||
|
|
@ -423,7 +422,7 @@ If you need to *access* the actual exception object or message inside an
|
||||||
<system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_
|
<system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_
|
||||||
module. Example:
|
module. Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
try:
|
try:
|
||||||
doSomethingHere()
|
doSomethingHere()
|
||||||
except:
|
except:
|
||||||
|
|
@ -431,6 +430,7 @@ module. Example:
|
||||||
e = getCurrentException()
|
e = getCurrentException()
|
||||||
msg = getCurrentExceptionMsg()
|
msg = getCurrentExceptionMsg()
|
||||||
echo "Got exception ", repr(e), " with message ", msg
|
echo "Got exception ", repr(e), " with message ", msg
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Annotating procs with raised exceptions
|
Annotating procs with raised exceptions
|
||||||
|
|
@ -443,12 +443,13 @@ instance, if you specify that a proc raises `IOError`, and at some point it
|
||||||
(or one of the procs it calls) starts raising a new exception the compiler will
|
(or one of the procs it calls) starts raising a new exception the compiler will
|
||||||
prevent that proc from compiling. Usage example:
|
prevent that proc from compiling. Usage example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc complexProc() {.raises: [IOError, ArithmeticDefect].} =
|
proc complexProc() {.raises: [IOError, ArithmeticDefect].} =
|
||||||
...
|
...
|
||||||
|
|
||||||
proc simpleProc() {.raises: [].} =
|
proc simpleProc() {.raises: [].} =
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Once you have code like this in place, if the list of raised exception changes
|
Once you have code like this in place, if the list of raised exception changes
|
||||||
the compiler will stop with an error specifying the line of the proc which
|
the compiler will stop with an error specifying the line of the proc which
|
||||||
|
|
@ -474,8 +475,7 @@ with `type parameters`:idx:. Generic parameters are written within square
|
||||||
brackets, for example `Foo[T]`. They are most useful for efficient type safe
|
brackets, for example `Foo[T]`. They are most useful for efficient type safe
|
||||||
containers:
|
containers:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
type
|
type
|
||||||
BinaryTree*[T] = ref object # BinaryTree is a generic type with
|
BinaryTree*[T] = ref object # BinaryTree is a generic type with
|
||||||
# generic param `T`
|
# generic param `T`
|
||||||
|
|
@ -530,6 +530,7 @@ containers:
|
||||||
add(root, "world") # instantiates the second `add` proc
|
add(root, "world") # instantiates the second `add` proc
|
||||||
for str in preorder(root):
|
for str in preorder(root):
|
||||||
stdout.writeLine(str)
|
stdout.writeLine(str)
|
||||||
|
```
|
||||||
|
|
||||||
The example shows a generic binary tree. Depending on context, the brackets are
|
The example shows a generic binary tree. Depending on context, the brackets are
|
||||||
used either to introduce type parameters or to instantiate a generic proc,
|
used either to introduce type parameters or to instantiate a generic proc,
|
||||||
|
|
@ -539,8 +540,7 @@ is not hidden and is used in the `preorder` iterator.
|
||||||
|
|
||||||
There is a special `[:T]` syntax when using generics with the method call syntax:
|
There is a special `[:T]` syntax when using generics with the method call syntax:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
proc foo[T](i: T) =
|
proc foo[T](i: T) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
@ -549,6 +549,7 @@ There is a special `[:T]` syntax when using generics with the method call syntax
|
||||||
# i.foo[int]() # Error: expression 'foo(i)' has no type (or is ambiguous)
|
# i.foo[int]() # Error: expression 'foo(i)' has no type (or is ambiguous)
|
||||||
|
|
||||||
i.foo[:int]() # Success
|
i.foo[:int]() # Success
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Templates
|
Templates
|
||||||
|
|
@ -563,12 +564,13 @@ To *invoke* a template, call it like a procedure.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
template `!=` (a, b: untyped): untyped =
|
template `!=` (a, b: untyped): untyped =
|
||||||
# this definition exists in the System module
|
# this definition exists in the System module
|
||||||
not (a == b)
|
not (a == b)
|
||||||
|
|
||||||
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
||||||
|
```
|
||||||
|
|
||||||
The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact
|
The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact
|
||||||
templates: this has the benefit that if you overload the `==` operator,
|
templates: this has the benefit that if you overload the `==` operator,
|
||||||
|
|
@ -582,8 +584,7 @@ for IEEE floating point numbers - NaN breaks basic boolean logic.)
|
||||||
Templates are especially useful for lazy evaluation purposes. Consider a
|
Templates are especially useful for lazy evaluation purposes. Consider a
|
||||||
simple proc for logging:
|
simple proc for logging:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
const
|
const
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
|
@ -593,6 +594,7 @@ simple proc for logging:
|
||||||
var
|
var
|
||||||
x = 4
|
x = 4
|
||||||
log("x has the value: " & $x)
|
log("x has the value: " & $x)
|
||||||
|
```
|
||||||
|
|
||||||
This code has a shortcoming: if `debug` is set to false someday, the quite
|
This code has a shortcoming: if `debug` is set to false someday, the quite
|
||||||
expensive `$` and `&` operations are still performed! (The argument
|
expensive `$` and `&` operations are still performed! (The argument
|
||||||
|
|
@ -600,8 +602,7 @@ evaluation for procedures is *eager*).
|
||||||
|
|
||||||
Turning the `log` proc into a template solves this problem:
|
Turning the `log` proc into a template solves this problem:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
const
|
const
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
|
@ -611,6 +612,7 @@ Turning the `log` proc into a template solves this problem:
|
||||||
var
|
var
|
||||||
x = 4
|
x = 4
|
||||||
log("x has the value: " & $x)
|
log("x has the value: " & $x)
|
||||||
|
```
|
||||||
|
|
||||||
The parameters' types can be ordinary types or the meta types `untyped`,
|
The parameters' types can be ordinary types or the meta types `untyped`,
|
||||||
`typed`, or `type`. `type` suggests that only a type symbol may be given
|
`typed`, or `type`. `type` suggests that only a type symbol may be given
|
||||||
|
|
@ -622,9 +624,7 @@ If the template has no explicit return type,
|
||||||
|
|
||||||
To pass a block of statements to a template, use `untyped` for the last parameter:
|
To pass a block of statements to a template, use `untyped` for the last parameter:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
template withFile(f: untyped, filename: string, mode: FileMode,
|
template withFile(f: untyped, filename: string, mode: FileMode,
|
||||||
body: untyped) =
|
body: untyped) =
|
||||||
let fn = filename
|
let fn = filename
|
||||||
|
|
@ -640,6 +640,7 @@ To pass a block of statements to a template, use `untyped` for the last paramete
|
||||||
withFile(txt, "ttempl3.txt", fmWrite):
|
withFile(txt, "ttempl3.txt", fmWrite):
|
||||||
txt.writeLine("line 1")
|
txt.writeLine("line 1")
|
||||||
txt.writeLine("line 2")
|
txt.writeLine("line 2")
|
||||||
|
```
|
||||||
|
|
||||||
In the example the two `writeLine` statements are bound to the `body`
|
In the example the two `writeLine` statements are bound to the `body`
|
||||||
parameter. The `withFile` template contains boilerplate code and helps to
|
parameter. The `withFile` template contains boilerplate code and helps to
|
||||||
|
|
@ -650,8 +651,7 @@ once.
|
||||||
Example: Lifting Procs
|
Example: Lifting Procs
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
.. code-block:: nim
|
`````nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
import std/math
|
import std/math
|
||||||
|
|
||||||
template liftScalarProc(fname) =
|
template liftScalarProc(fname) =
|
||||||
|
|
@ -660,9 +660,10 @@ Example: Lifting Procs
|
||||||
## to provide templated procs that can handle a single
|
## to provide templated procs that can handle a single
|
||||||
## parameter of seq[T] or nested seq[seq[]] or the same type
|
## parameter of seq[T] or nested seq[seq[]] or the same type
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## ```Nim
|
||||||
## liftScalarProc(abs)
|
## liftScalarProc(abs)
|
||||||
## # now abs(@[@[1,-2], @[-2,-3]]) == @[@[1,2], @[2,3]]
|
## # now abs(@[@[1,-2], @[-2,-3]]) == @[@[1,2], @[2,3]]
|
||||||
|
## ```
|
||||||
proc fname[T](x: openarray[T]): auto =
|
proc fname[T](x: openarray[T]): auto =
|
||||||
var temp: T
|
var temp: T
|
||||||
type outType = typeof(fname(temp))
|
type outType = typeof(fname(temp))
|
||||||
|
|
@ -672,6 +673,7 @@ Example: Lifting Procs
|
||||||
|
|
||||||
liftScalarProc(sqrt) # make sqrt() work for sequences
|
liftScalarProc(sqrt) # make sqrt() work for sequences
|
||||||
echo sqrt(@[4.0, 16.0, 25.0, 36.0]) # => @[2.0, 4.0, 5.0, 6.0]
|
echo sqrt(@[4.0, 16.0, 25.0, 36.0]) # => @[2.0, 4.0, 5.0, 6.0]
|
||||||
|
`````
|
||||||
|
|
||||||
Compilation to JavaScript
|
Compilation to JavaScript
|
||||||
=========================
|
=========================
|
||||||
|
|
|
||||||
83
doc/tut3.md
83
doc/tut3.md
|
|
@ -91,14 +91,14 @@ in the expression `foo(x)`, `x` needs to be an integer constant,
|
||||||
but in the macro body `arg` is just like a normal parameter of type
|
but in the macro body `arg` is just like a normal parameter of type
|
||||||
`int`.
|
`int`.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
import std/macros
|
import std/macros
|
||||||
|
|
||||||
macro myMacro(arg: static[int]): untyped =
|
macro myMacro(arg: static[int]): untyped =
|
||||||
echo arg # just an int (7), not `NimNode`
|
echo arg # just an int (7), not `NimNode`
|
||||||
|
|
||||||
myMacro(1 + 2 * 3)
|
myMacro(1 + 2 * 3)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Code Blocks as Arguments
|
Code Blocks as Arguments
|
||||||
|
|
@ -108,12 +108,12 @@ It is possible to pass the last argument of a call expression in a
|
||||||
separate code block with indentation. For example, the following code
|
separate code block with indentation. For example, the following code
|
||||||
example is a valid (but not a recommended) way to call `echo`:
|
example is a valid (but not a recommended) way to call `echo`:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
echo "Hello ":
|
echo "Hello ":
|
||||||
let a = "Wor"
|
let a = "Wor"
|
||||||
let b = "ld!"
|
let b = "ld!"
|
||||||
a & b
|
a & b
|
||||||
|
```
|
||||||
|
|
||||||
For macros this way of calling is very useful; syntax trees of arbitrary
|
For macros this way of calling is very useful; syntax trees of arbitrary
|
||||||
complexity can be passed to macros with this notation.
|
complexity can be passed to macros with this notation.
|
||||||
|
|
@ -134,8 +134,7 @@ and for debug printing of generated syntax tree. `dumpTree` is a
|
||||||
predefined macro that just prints its argument in a tree representation,
|
predefined macro that just prints its argument in a tree representation,
|
||||||
but does nothing else. Here is an example of such a tree representation:
|
but does nothing else. Here is an example of such a tree representation:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
dumpTree:
|
dumpTree:
|
||||||
var mt: MyType = MyType(a:123.456, b:"abcdef")
|
var mt: MyType = MyType(a:123.456, b:"abcdef")
|
||||||
|
|
||||||
|
|
@ -153,6 +152,7 @@ but does nothing else. Here is an example of such a tree representation:
|
||||||
# ExprColonExpr
|
# ExprColonExpr
|
||||||
# Ident "b"
|
# Ident "b"
|
||||||
# StrLit "abcdef"
|
# StrLit "abcdef"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Custom Semantic Checking
|
Custom Semantic Checking
|
||||||
|
|
@ -166,10 +166,10 @@ macro evaluation should be caught and create a nice error message.
|
||||||
the checks need to be more complex, arbitrary error messages can
|
the checks need to be more complex, arbitrary error messages can
|
||||||
be created with the `macros.error` proc.
|
be created with the `macros.error` proc.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
macro myAssert(arg: untyped): untyped =
|
macro myAssert(arg: untyped): untyped =
|
||||||
arg.expectKind nnkInfix
|
arg.expectKind nnkInfix
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Generating Code
|
Generating Code
|
||||||
|
|
@ -187,36 +187,36 @@ tree with calls to `newTree` and `newLit` the macro
|
||||||
Backticks are used to insert code from `NimNode` symbols into the
|
Backticks are used to insert code from `NimNode` symbols into the
|
||||||
generated expression.
|
generated expression.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
import std/macros
|
||||||
import std/macros
|
macro a(i) = quote do:
|
||||||
macro a(i) = quote do:
|
let `i` = 0
|
||||||
let `i` = 0
|
|
||||||
|
|
||||||
a b
|
a b
|
||||||
doAssert b == 0
|
doAssert b == 0
|
||||||
|
```
|
||||||
|
|
||||||
A custom prefix operator can be defined whenever backticks are needed.
|
A custom prefix operator can be defined whenever backticks are needed.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
import std/macros
|
||||||
import std/macros
|
macro a(i) = quote("@") do:
|
||||||
macro a(i) = quote("@") do:
|
assert @i == 0
|
||||||
assert @i == 0
|
|
||||||
|
|
||||||
let b = 0
|
let b = 0
|
||||||
a b
|
a b
|
||||||
|
```
|
||||||
|
|
||||||
The injected symbol needs accent quoted when it resolves to a symbol.
|
The injected symbol needs accent quoted when it resolves to a symbol.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
import std/macros
|
||||||
import std/macros
|
macro a(i) = quote("@") do:
|
||||||
macro a(i) = quote("@") do:
|
let `@i` = 0
|
||||||
let `@i` = 0
|
|
||||||
|
|
||||||
a b
|
a b
|
||||||
doAssert b == 0
|
doAssert b == 0
|
||||||
|
```
|
||||||
|
|
||||||
Make sure to inject only symbols of type `NimNode` into the generated syntax
|
Make sure to inject only symbols of type `NimNode` into the generated syntax
|
||||||
tree. You can use `newLit` to convert arbitrary values into
|
tree. You can use `newLit` to convert arbitrary values into
|
||||||
|
|
@ -224,9 +224,7 @@ expressions trees of type `NimNode` so that it is safe to inject
|
||||||
them into the tree.
|
them into the tree.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
import std/macros
|
import std/macros
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -246,12 +244,14 @@ them into the tree.
|
||||||
echo `mtLit`
|
echo `mtLit`
|
||||||
|
|
||||||
myMacro("Hallo")
|
myMacro("Hallo")
|
||||||
|
```
|
||||||
|
|
||||||
The call to `myMacro` will generate the following code:
|
The call to `myMacro` will generate the following code:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
echo "Hallo"
|
echo "Hallo"
|
||||||
echo MyType(a: 123.456'f64, b: "abcdef")
|
echo MyType(a: 123.456'f64, b: "abcdef")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Building Your First Macro
|
Building Your First Macro
|
||||||
|
|
@ -263,9 +263,7 @@ do is to build a simple example of the macro usage, and then just
|
||||||
print the argument. This way it is possible to get an idea of what a
|
print the argument. This way it is possible to get an idea of what a
|
||||||
correct argument should look like.
|
correct argument should look like.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
import std/macros
|
import std/macros
|
||||||
|
|
||||||
macro myAssert(arg: untyped): untyped =
|
macro myAssert(arg: untyped): untyped =
|
||||||
|
|
@ -275,13 +273,14 @@ correct argument should look like.
|
||||||
let b = 2
|
let b = 2
|
||||||
|
|
||||||
myAssert(a != b)
|
myAssert(a != b)
|
||||||
|
```
|
||||||
|
|
||||||
.. code-block::
|
```
|
||||||
|
|
||||||
Infix
|
Infix
|
||||||
Ident "!="
|
Ident "!="
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
From the output, it is possible to see that the argument is an infix
|
From the output, it is possible to see that the argument is an infix
|
||||||
|
|
@ -289,9 +288,7 @@ operator (node kind is "Infix"), as well as that the two operands are
|
||||||
at index 1 and 2. With this information, the actual macro can be
|
at index 1 and 2. With this information, the actual macro can be
|
||||||
written.
|
written.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim test = "nim c $1"
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
import std/macros
|
import std/macros
|
||||||
|
|
||||||
macro myAssert(arg: untyped): untyped =
|
macro myAssert(arg: untyped): untyped =
|
||||||
|
|
@ -312,6 +309,7 @@ written.
|
||||||
|
|
||||||
myAssert(a != b)
|
myAssert(a != b)
|
||||||
myAssert(a == b)
|
myAssert(a == b)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
This is the code that will be generated. To debug what the macro
|
This is the code that will be generated. To debug what the macro
|
||||||
|
|
@ -319,9 +317,10 @@ actually generated, the statement `echo result.repr` can be used, in
|
||||||
the last line of the macro. It is also the statement that has been
|
the last line of the macro. It is also the statement that has been
|
||||||
used to get this output.
|
used to get this output.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
if not (a != b):
|
if not (a != b):
|
||||||
raise newException(AssertionDefect, $a & " != " & $b)
|
raise newException(AssertionDefect, $a & " != " & $b)
|
||||||
|
```
|
||||||
|
|
||||||
With Power Comes Responsibility
|
With Power Comes Responsibility
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue