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

Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

@@ -654,7 +657,7 @@
proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
-    ...raises: [], tags: [].}
+ ...raises: [], tags: [], forbids: [].}

Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

@@ -671,7 +674,7 @@
-
proc p1() {....raises: [], tags: [].}
+
proc p1() {....raises: [], tags: [], forbids: [].}
cp1 @@ -698,7 +701,7 @@ this is a nested doc comment
-
func someFunc() {....raises: [], tags: [].}
+
func someFunc() {....raises: [], tags: [], forbids: [].}
My someFunc. Stuff in quotes here. Some link @@ -709,7 +712,7 @@ this is a nested doc comment
-
proc tripleStrLitTest() {....raises: [], tags: [].}
+
proc tripleStrLitTest() {....raises: [], tags: [], forbids: [].}
@@ -756,7 +759,7 @@ at indent 0
-
proc z1(): Foo {....raises: [], tags: [].}
+
proc z1(): Foo {....raises: [], tags: [], forbids: [].}
cz1 @@ -767,7 +770,7 @@ at indent 0
-
proc z2() {....raises: [], tags: [].}
+
proc z2() {....raises: [], tags: [], forbids: [].}
cz2 @@ -780,7 +783,7 @@ at indent 0
-
proc z3() {....raises: [], tags: [].}
+
proc z3() {....raises: [], tags: [], forbids: [].}
cz3 @@ -791,7 +794,7 @@ at indent 0
-
proc z4() {....raises: [], tags: [].}
+
proc z4() {....raises: [], tags: [], forbids: [].}
cz4 @@ -802,7 +805,7 @@ at indent 0
-
proc z5(): int {....raises: [], tags: [].}
+
proc z5(): int {....raises: [], tags: [], forbids: [].}
cz5 @@ -813,7 +816,7 @@ at indent 0
-
proc z6(): int {....raises: [], tags: [].}
+
proc z6(): int {....raises: [], tags: [], forbids: [].}
cz6 @@ -824,7 +827,7 @@ at indent 0
-
proc z7(): int {....raises: [], tags: [].}
+
proc z7(): int {....raises: [], tags: [], forbids: [].}
cz7 @@ -835,7 +838,7 @@ at indent 0
-
proc z8(): int {....raises: [], tags: [].}
+
proc z8(): int {....raises: [], tags: [], forbids: [].}
cz8 @@ -846,7 +849,7 @@ at indent 0
-
proc z9() {....raises: [], tags: [].}
+
proc z9() {....raises: [], tags: [], forbids: [].}
@@ -859,7 +862,7 @@ at indent 0
-
proc z10() {....raises: [], tags: [].}
+
proc z10() {....raises: [], tags: [], forbids: [].}
@@ -872,7 +875,7 @@ at indent 0
-
proc z11() {....raises: [], tags: [].}
+
proc z11() {....raises: [], tags: [], forbids: [].}
@@ -885,7 +888,7 @@ at indent 0
-
proc z12(): int {....raises: [], tags: [].}
+
proc z12(): int {....raises: [], tags: [], forbids: [].}
@@ -898,7 +901,7 @@ at indent 0
-
proc z13() {....raises: [], tags: [].}
+
proc z13() {....raises: [], tags: [], forbids: [].}
cz13 @@ -911,7 +914,7 @@ at indent 0
-
proc z17() {....raises: [], tags: [].}
+
proc z17() {....raises: [], tags: [], forbids: [].}
cz17 rest @@ -930,7 +933,7 @@ at indent 0
-
method method1(self: Moo) {.base, ...raises: [], tags: [].}
+
method method1(self: Moo) {.base, ...raises: [], tags: [], forbids: [].}
foo1 @@ -941,7 +944,7 @@ at indent 0
-
method method2(self: Moo): int {.base, ...raises: [], tags: [].}
+
method method2(self: Moo): int {.base, ...raises: [], tags: [], forbids: [].}
foo2 @@ -952,7 +955,7 @@ at indent 0
-
method method3(self: Moo): int {.base, ...raises: [], tags: [].}
+
method method3(self: Moo): int {.base, ...raises: [], tags: [], forbids: [].}
foo3 @@ -969,7 +972,7 @@ at indent 0
-
iterator fromUtils1(): int {....raises: [], tags: [].}
+
iterator fromUtils1(): int {....raises: [], tags: [], forbids: [].}
@@ -984,7 +987,7 @@ at indent 0
-
iterator iter1(n: int): int {....raises: [], tags: [].}
+
iterator iter1(n: int): int {....raises: [], tags: [], forbids: [].}
foo1 @@ -995,7 +998,7 @@ at indent 0
-
iterator iter2(n: int): int {....raises: [], tags: [].}
+
iterator iter2(n: int): int {....raises: [], tags: [], forbids: [].}
foo2 diff --git a/tests/effects/teffects11.nim b/tests/effects/teffects11.nim new file mode 100644 index 0000000000..e4098e9594 --- /dev/null +++ b/tests/effects/teffects11.nim @@ -0,0 +1,21 @@ +discard """ +action: compile +errormsg: "type mismatch: got " +line: 21 +""" + +type + Effect1 = object + Effect2 = object + Effect3 = object + +proc test(fnc: proc(x: int): void {.forbids: [Effect2].}) {.tags: [Effect1, Effect3, RootEffect].} = + fnc(1) + +proc t1(x: int): void = echo $x +proc t2(x: int): void {.tags: [Effect2].} = echo $x +proc t3(x: int): void {.tags: [Effect3].} = echo $x + +test(t1) +test(t3) +test(t2) diff --git a/tests/effects/teffects12.nim b/tests/effects/teffects12.nim new file mode 100644 index 0000000000..5f5499c385 --- /dev/null +++ b/tests/effects/teffects12.nim @@ -0,0 +1,52 @@ +discard """ +action: compile +""" + +import std/locks + +type + Test2Effect* = object + Test2* = object + value2*: int + Test1Effect* = object + Test1* = object + value1*: int + Main* = object + test1Lock: Lock + test1: Test1 + test2Lock: Lock + test2: Test2 + +proc `=copy`(obj1: var Test2, obj2: Test2) {.error.} +proc `=copy`(obj1: var Test1, obj2: Test1) {.error.} +proc `=copy`(obj1: var Main, obj2: Main) {.error.} + +proc withTest1(main: var Main, + fn: proc(test1: var Test1) {.gcsafe, forbids: [Test1Effect].}) {.gcsafe, tags: [Test1Effect, RootEffect].} = + withLock(main.test1Lock): + fn(main.test1) + +proc withTest2(main: var Main, + fn: proc(test1: var Test2) {.gcsafe, forbids: [Test2Effect].}) {.gcsafe, tags: [Test2Effect, RootEffect].} = + withLock(main.test2Lock): + fn(main.test2) + +proc newMain(): Main = + var test1lock: Lock + initLock(test1Lock) + var test2lock: Lock + initLock(test2Lock) + var main = Main(test1Lock: move(test1Lock), test1: Test1(value1: 1), + test2Lock: move(test2Lock), test2: Test2(value2: 2)) + main.withTest1(proc(test1: var Test1) = test1.value1 += 1) + main.withTest2(proc(test2: var Test2) = test2.value2 += 1) + move main + +var main = newMain() +main.withTest1(proc(test1: var Test1) = + test1.value1 += 1 + main.withTest2(proc(test2: var Test2) = test2.value2 += 1) +) + +main.withTest1(proc(test1: var Test1) {.tags: [].} = echo $test1.value1) +main.withTest2(proc(test2: var Test2) {.tags: [].} = echo $test2.value2) diff --git a/tests/effects/teffects13.nim b/tests/effects/teffects13.nim new file mode 100644 index 0000000000..73082f9978 --- /dev/null +++ b/tests/effects/teffects13.nim @@ -0,0 +1,19 @@ +discard """ +action: compile +errormsg: "writeSomething() has an illegal effect: WriteIO" +line: 19 +""" + +type + IO = object of RootEffect ## input/output effect + ReadIO = object of IO ## input effect + WriteIO = object of IO ## output effect + +proc readSomething(): string {.tags: [ReadIO].} = "" +proc writeSomething(): void {.tags: [WriteIO].} = echo "..." + +proc noWritesPlease() {.forbids: [WriteIO].} = + # this is OK: + echo readSomething() + # the compiler prevents this: + writeSomething() diff --git a/tests/effects/teffects14.nim b/tests/effects/teffects14.nim new file mode 100644 index 0000000000..6291d95696 --- /dev/null +++ b/tests/effects/teffects14.nim @@ -0,0 +1,15 @@ +discard """ +action: compile +errormsg: "func1() has an illegal effect: IO" +line: 15 +""" + +type IO = object ## input/output effect +proc func1(): string {.tags: [IO].} = discard +proc func2(): string = discard + +proc no_IO_please() {.forbids: [IO].} = + # this is OK because it didn't define any tag: + discard func2() + # the compiler prevents this: + let y = func1() diff --git a/tests/effects/teffects15.nim b/tests/effects/teffects15.nim new file mode 100644 index 0000000000..c3079cdbc1 --- /dev/null +++ b/tests/effects/teffects15.nim @@ -0,0 +1,18 @@ +discard """ +action: compile +errormsg: "method1(c) has an illegal effect: IO" +line: 18 +""" + +type + IO = object ## input/output effect + CustomObject* = object of RootObj + text: string + +method method1(obj: var CustomObject): string {.tags: [IO].} = obj.text & "." +method method2(obj: var CustomObject): string = obj.text & ":" + +proc noIO() {.forbids: [IO].} = + var c = CustomObject(text: "a") + echo c.method2() + echo c.method1() diff --git a/tests/effects/teffects16.nim b/tests/effects/teffects16.nim new file mode 100644 index 0000000000..ee8f782a3a --- /dev/null +++ b/tests/effects/teffects16.nim @@ -0,0 +1,20 @@ +discard """ +action: compile +errormsg: "writeSomething(\"a\") can have an unlisted effect: WriteIO" +line: 20 +""" + +type + IO = object of RootEffect ## input/output effect + ReadIO = object of IO ## input effect + WriteIO = object of IO ## output effect + LogIO = object of IO ## another output effect + +proc readSomething(): string {.tags: [ReadIO].} = "" +proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg +proc logSomething(msg: string): void {.tags: [LogIo].} = echo msg + +proc noWritesPlease() {.forbids: [WriteIO], tags: [LogIO, ReadIO].} = + echo readSomething() + logSomething("a") + writeSomething("a") diff --git a/tests/effects/teffects17.nim b/tests/effects/teffects17.nim new file mode 100644 index 0000000000..5e6b838962 --- /dev/null +++ b/tests/effects/teffects17.nim @@ -0,0 +1,17 @@ +discard """ +action: compile +errormsg: "writeSomething(\"a\") has an illegal effect: WriteIO" +line: 17 +""" + +type + IO = object of RootEffect ## input/output effect + ReadIO = object of IO ## input effect + WriteIO = object of IO ## output effect + +proc readSomething(): string {.tags: [ReadIO].} = "" +proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg + +proc illegalEffectNegation() {.forbids: [WriteIO], tags: [ReadIO, WriteIO].} = + echo readSomething() + writeSomething("a") diff --git a/tests/effects/teffects18.nim b/tests/effects/teffects18.nim new file mode 100644 index 0000000000..576e766358 --- /dev/null +++ b/tests/effects/teffects18.nim @@ -0,0 +1,19 @@ +discard """ +action: compile +errormsg: "type mismatch: got " +line: 19 +""" + +type MyEffect = object +type ProcType1 = proc (i: int): void {.forbids: [MyEffect].} +type ProcType2 = proc (i: int): void + +proc testFunc(p: ProcType1): void = p(1) + +proc toBeCalled(i: int): void {.tags: [MyEffect].} = echo $i + +let emptyTags = proc(i: int): void {.tags: [].} = echo $i +let noTags: ProcType2 = proc(i: int): void = toBeCalled(i) + +testFunc(emptyTags) +testFunc(noTags) diff --git a/tests/effects/teffects19.nim b/tests/effects/teffects19.nim new file mode 100644 index 0000000000..49fb87523b --- /dev/null +++ b/tests/effects/teffects19.nim @@ -0,0 +1,23 @@ +discard """ +action: compile +errormsg: "type mismatch: got " +line: 23 +""" + +type MyEffect = object +type ProcType1 = proc (i: int): void {.forbids: [MyEffect].} +type ProcType2 = proc (i: int): void + +proc caller1(p: ProcType1): void = p(1) +proc caller2(p: ProcType2): void = p(1) + +proc effectful(i: int): void {.tags: [MyEffect].} = echo $i +proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i + +proc toBeCalled1(i: int): void = effectful(i) +proc toBeCalled2(i: int): void = effectless(i) + +caller1(toBeCalled2) +caller2(toBeCalled1) +caller2(toBeCalled2) +caller1(toBeCalled1) From 3d5f10f0d05b3510f0738471fa78b0fda1873fdf Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 26 Jul 2022 17:44:13 +0300 Subject: [PATCH 03/33] clean up and clarify changelog [skip ci] (#20093) --- changelog.md | 53 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/changelog.md b/changelog.md index c698f09d76..fd8878ada8 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,20 @@ ## Changes affecting backward compatibility +- `addr` is now available for all addressable locations, + `unsafeAddr` is now deprecated and an alias for `addr`. + +- `io` and `assertions` are about to move out of the `system` module. + You may instead import `std/syncio` and `std/assertions`. + The `-d:nimPreviewSlimSystem` option makes these imports required. + +- The `gc:v2` option is removed. + +- The `threads:on` option is now the default. + +- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via + `experimental:flexibleOptionalParams`. + - The `Math.trunc` polyfill for targeting Internet Explorer was previously emitted for every JavaScript output file except if the symbol `nodejs` was defined via `-d:nodejs`. Now, it is only @@ -11,51 +25,38 @@ or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). Nim uses `Math.trunc` for the division and modulo operators for integers. -- Deprecated `std/sums`. - -- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via - `experimental:flexibleOptionalParams`. - -- `std/sharedstrings` module is removed. -- Constants `colors.colPaleVioletRed` and `colors.colMediumPurple` changed to match the CSS color standard. - -- `addr` is now available for all addressable locations, `unsafeAddr` is deprecated and -becomes an alias for `addr`. - -- `io` and `assertions` are about to move out of system; use `-d:nimPreviewSlimSystem`, import `std/syncio` and import `std/assertions`. - -- The `gc:v2` option is removed. - -- The `threads:on` option becomes the default. - ## Standard library additions and changes [//]: # "Changes:" -- `macros.parseExpr` and `macros.parseStmt` now accept an optional. +- `macros.parseExpr` and `macros.parseStmt` now accept an optional filename argument for more informative errors. - Module `colors` expanded with missing colors from the CSS color standard. + `colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard. - Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). - `md5` now works at compile time and in JavaScript. - `std/smtp` sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. -- Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. +- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables. - `strutils.find` now use and default to `last=-1` for whole string searches, making limiting it to just the first char (`last=0`) valid. - `random.rand` now works with `Ordinal`s. [//]: # "Additions:" -- Added `IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. -- Added `IsoYear`, a distinct int type to prevent bugs from confusing the week-based year and the regular year. -- Added `initDateTime` in `times` to create a datetime from a weekday, and ISO 8601 week number and week-based year. -- Added `getIsoWeekAndYear` in `times` to get an ISO week number along with the corresponding ISO week-based year from a datetime. -- Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. +- Added `times.IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. +- Added `times.IsoYear`, a distinct int type to prevent bugs from confusing the week-based year and the regular year. +- Added `times.initDateTime` to create a datetime from a weekday, and ISO 8601 week number and week-based year. +- Added `times.getIsoWeekAndYear` to get an ISO week number along with the corresponding ISO week-based year from a datetime. +- Added `times.getIsoWeeksInYear` to return the number of weeks in an ISO week-based year. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - Added `sep` parameter in `std/uri` to specify the query separator. -- Added [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) for JavaScript targets. -- Added [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) for JavaScript targets. +- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) + and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) + in `jscore` for JavaScript targets. [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. +- Deprecated `std/sums`. [//]: # "Removals:" +- Removed deprecated `std/sharedstrings`. - Removed deprecated `oids.oidToString`. - Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. - Removed deprecated `jsre.test` and `jsre.toString`. From 1c39af3389b2251eb93b2f8e77911078cb7d5679 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 26 Jul 2022 22:48:01 +0800 Subject: [PATCH 04/33] fixes #20089; remove setPointer since strings/seqs are not pointers with ORC (#20090) fixes #20089; remove setPointer since strings/seqs are not pointers anymore --- lib/pure/marshal.nim | 10 ++++++++-- tests/stdlib/tmarshal.nim | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 452af54d5d..df527853e4 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -163,7 +163,10 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = of akSequence: case p.kind of jsonNull: - setPointer(a, nil) + when defined(nimSeqsV2): + invokeNewSeq(a, 0) + else: + setPointer(a, nil) next(p) of jsonArrayStart: next(p) @@ -230,7 +233,10 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = of akString: case p.kind of jsonNull: - setPointer(a, nil) + when defined(nimSeqsV2): + setString(a, "") + else: + setPointer(a, nil) next(p) of jsonString: setString(a, p.str) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index e539b1c344..6b71e3bebd 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:orc; --mm:refc" +""" + import std/marshal # TODO: add static tests @@ -136,6 +140,16 @@ block: let test = to[LegacyEntry](str) doAssert $test == """(numeric: "")""" +block: + let str = """{"numeric": null}""" + + type + LegacyEntry = object + numeric: seq[int] + + var test = to[LegacyEntry](str) + doAssert $test == """(numeric: @[])""" + # bug #16022 block: let p: proc (): string = proc (): string = "hello world" From 4c46358db1c11b7c4772431ad5e158ab00a7f4fc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 26 Jul 2022 22:51:01 +0800 Subject: [PATCH 05/33] remove shallowCopy for ARC/ORC (#20070) * remove shallowCopy for ARC/ORC * use move * fix * more fixes * typo * Update lib/system.nim * follow * add nodestroy * move * copy string * add a changelog entry Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: Andreas Rumpf --- changelog.md | 3 +++ compiler/btrees.nim | 10 ++++++++-- compiler/msgs.nim | 11 +++++++++-- compiler/nimfix/prettybase.nim | 10 ++++++++-- compiler/pragmas.nim | 5 ++++- compiler/vm.nim | 8 ++++++-- lib/pure/asynchttpserver.nim | 7 +++++-- lib/pure/marshal.nim | 14 ++++++++++---- lib/system.nim | 33 +++++++++++++++++++-------------- tests/gc/cyclecollector.nim | 5 ++++- 10 files changed, 76 insertions(+), 30 deletions(-) diff --git a/changelog.md b/changelog.md index fd8878ada8..580db2cd05 100644 --- a/changelog.md +++ b/changelog.md @@ -25,6 +25,9 @@ or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). Nim uses `Math.trunc` for the division and modulo operators for integers. +- `shallowCopy` is removed for ARC/ORC. Use `move` when possible or combine assignment and +`sink` for optimization purposes. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 1701f8d7bf..c79442249d 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -68,7 +68,10 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) = result.links[j] = h.links[Mhalf + j] else: for j in 0..= 0 - shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash) + when defined(gcArc) or defined(gcOrc): + conf.m.fileInfos[fileIdx.int32].hash = hash + else: + shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash) + proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string = assert fileIdx.int32 >= 0 - shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash) + when defined(gcArc) or defined(gcOrc): + result = conf.m.fileInfos[fileIdx.int32].hash + else: + shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash) proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): AbsoluteFile = if fileIdx.int32 < 0: diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index fbc2e3bd18..78c24bae30 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -22,7 +22,10 @@ proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent let last = first+identLen(line, first)-1 if cmpIgnoreStyle(line[first..last], oldSym.s) == 0: var x = line.substr(0, first-1) & newSym.s & line.substr(last+1) - system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) + when defined(gcArc) or defined(gcOrc): + conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x + else: + system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) conf.m.fileInfos[info.fileIndex.int32].dirty = true #if newSym.s == "File": writeStackTrace() @@ -35,5 +38,8 @@ proc replaceComment*(conf: ConfigRef; info: TLineInfo) = if line[first] != '#': inc first var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape - system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) + when defined(gcArc) or defined(gcOrc): + conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x + else: + system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) conf.m.fileInfos[info.fileIndex.int32].dirty = true diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 417941cd1b..8c7d75024e 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -511,7 +511,10 @@ proc processCompile(c: PContext, n: PNode) = n[i] = c.semConstExpr(c, n[i]) case n[i].kind of nkStrLit, nkRStrLit, nkTripleStrLit: - shallowCopy(result, n[i].strVal) + when defined(gcArc) or defined(gcOrc): + result = n[i].strVal + else: + shallowCopy(result, n[i].strVal) else: localError(c.config, n.info, errStringLiteralExpected) result = "" diff --git a/compiler/vm.nim b/compiler/vm.nim index 3cb699482c..28df27ef38 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -114,8 +114,12 @@ template decodeBx(k: untyped) {.dirty.} = let rbx = instr.regBx - wordExcess ensureKind(k) -template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b) -# XXX fix minor 'shallowCopy' overloading bug in compiler +template move(a, b: untyped) {.dirty.} = + when defined(gcArc) or defined(gcOrc): + a = move b + else: + system.shallowCopy(a, b) + # XXX fix minor 'shallowCopy' overloading bug in compiler proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: bool): bool = # nim bug: `isAssign: static bool` doesn't work, giving odd compiler error diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index d7daacd03f..ac51d768d5 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -170,7 +170,7 @@ proc processRequest( server: AsyncHttpServer, req: FutureVar[Request], client: AsyncSocket, - address: string, + address: sink string, lineFut: FutureVar[string], callback: proc (request: Request): Future[void] {.closure, gcsafe.}, ): Future[bool] {.async.} = @@ -184,7 +184,10 @@ proc processRequest( # \n request.headers.clear() request.body = "" - request.hostname.shallowCopy(address) + when defined(gcArc) or defined(gcOrc): + request.hostname = address + else: + request.hostname.shallowCopy(address) assert client != nil request.client = client diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index df527853e4..06a21976b7 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -288,7 +288,7 @@ proc load*[T](s: Stream, data: var T) = var tab = initTable[BiggestInt, pointer]() loadAny(s, toAny(data), tab) -proc store*[T](s: Stream, data: T) = +proc store*[T](s: Stream, data: sink T) = ## Stores `data` into the stream `s`. Raises `IOError` in case of an error. runnableExamples: import std/streams @@ -301,13 +301,16 @@ proc store*[T](s: Stream, data: T) = var stored = initIntSet() var d: T - shallowCopy(d, data) + when defined(gcArc) or defined(gcOrc): + d = data + else: + shallowCopy(d, data) storeAny(s, toAny(d), stored) proc loadVM[T](typ: typedesc[T], x: T): string = discard "the implementation is in the compiler/vmops" -proc `$$`*[T](x: T): string = +proc `$$`*[T](x: sink T): string = ## Returns a string representation of `x` (serialization, marshalling). ## ## **Note:** to serialize `x` to JSON use `%x` from the `json` module @@ -327,7 +330,10 @@ proc `$$`*[T](x: T): string = else: var stored = initIntSet() var d: T - shallowCopy(d, x) + when defined(gcArc) or defined(gcOrc): + d = x + else: + shallowCopy(d, x) var s = newStringStream() storeAny(s, toAny(d), stored) result = s.data diff --git a/lib/system.nim b/lib/system.nim index 6e8519cf6a..6d737d5521 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -464,17 +464,16 @@ proc low*(x: string): int {.magic: "Low", noSideEffect.} ## var str = "Hello world!" ## low(str) # => 0 -proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} - ## Use this instead of `=` for a `shallow copy`:idx:. - ## - ## The shallow copy only changes the semantics for sequences and strings - ## (and types which contain those). - ## - ## Be careful with the changed semantics though! - ## There is a reason why the default assignment does a deep copy of sequences - ## and strings. - ## - ## .. warning:: `shallowCopy` does a deep copy with ARC/ORC. +when not defined(gcArc) and not defined(gcOrc): + proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} + ## Use this instead of `=` for a `shallow copy`:idx:. + ## + ## The shallow copy only changes the semantics for sequences and strings + ## (and types which contain those). + ## + ## Be careful with the changed semantics though! + ## There is a reason why the default assignment does a deep copy of sequences + ## and strings. # :array|openArray|string|seq|cstring|tuple proc `[]`*[I: Ordinal;T](a: T; i: I): T {. @@ -492,9 +491,12 @@ proc arrPut[I: Ordinal;T,S](a: T; i: I; proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = ## Generic `destructor`:idx: implementation that can be overridden. discard -proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} = +proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} = ## Generic `sink`:idx: implementation that can be overridden. - shallowCopy(x, y) + when defined(gcArc) or defined(gcOrc): + x = y + else: + shallowCopy(x, y) when defined(nimHasTrace): proc `=trace`*[T](x: var T; env: pointer) {.inline, magic: "Trace".} = @@ -2852,7 +2854,10 @@ when hasAlloc or defined(nimscript): setLen(x, xl+item.len) var j = xl-1 while j >= i: - shallowCopy(x[j+item.len], x[j]) + when defined(gcArc) or defined(gcOrc): + x[j+item.len] = move x[j] + else: + shallowCopy(x[j+item.len], x[j]) dec(j) j = 0 while j < item.len: diff --git a/tests/gc/cyclecollector.nim b/tests/gc/cyclecollector.nim index 7b47758f23..2d02a7a3c4 100644 --- a/tests/gc/cyclecollector.nim +++ b/tests/gc/cyclecollector.nim @@ -9,7 +9,10 @@ type proc createCycle(leaf: string): Node = new result result.a = result - shallowCopy result.leaf, leaf + when defined(gcArc) or defined(gcOrc): + result.leaf = leaf + else: + shallowCopy result.leaf, leaf proc main = for i in 0 .. 100_000: From 5bbc5edf43e6ede3d162f0463cb74c0a6d58cc1d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 27 Jul 2022 17:15:51 +0800 Subject: [PATCH 06/33] fixes #20031; uint64 is an ordinal type since 1.0 (#20094) * fixes #20031; uint64 is an ordinal type since 1.0 * Update compiler/semstmts.nim --- compiler/semstmts.nim | 2 +- tests/casestmt/tcasestmt.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f6136c363b..8b0691abf4 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1050,7 +1050,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode = var typ = commonTypeBegin var hasElse = false let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc}) - const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool} + const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool} case caseTyp.kind of shouldChckCovered: chckCovered = true diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 53cccdb641..3a4907494a 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -287,3 +287,14 @@ doAssert(foo2("Y", "a2") == 0) doAssert(foo2("Y", "2a") == 2) doAssert(foo2("N", "a3") == 3) doAssert(foo2("z", "2") == 0) + + +# bug #20031 +proc main(a: uint64) = + case a + else: + discard + +static: + main(10) +main(10) From 8ef509b85bc53a452ee44ee4757fd072a6d77e8f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 27 Jul 2022 21:06:34 +0800 Subject: [PATCH 07/33] fixes broken CI; bump macOS version to macos-11 (#20098) * bump macOS image on Azure CI to macos-11 ##[warning]The macOS-10.15 environment is deprecated, consider switching to macos-11(macos-latest), macos-12 instead. For more details see https://github.com/actions/virtual-environments/issues/5583 * fix CI error --- .github/workflows/ci_docs.yml | 2 +- .github/workflows/ci_packages.yml | 2 +- azure-pipelines.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 6ae228d2d0..9055fab2af 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -40,7 +40,7 @@ jobs: - target: windows os: windows-2019 - target: osx - os: macos-10.15 + os: macos-11 name: ${{ matrix.target }} runs-on: ${{ matrix.os }} diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 529e6e8b6b..a939936b6f 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -6,7 +6,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, macos-10.15] + os: [ubuntu-20.04, macos-11] cpu: [amd64] batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a70a86faee..a2f7552964 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,10 +28,10 @@ jobs: vmImage: 'ubuntu-18.04' CPU: i386 OSX_amd64: - vmImage: 'macOS-10.15' + vmImage: 'macOS-11' CPU: amd64 OSX_amd64_cpp: - vmImage: 'macOS-10.15' + vmImage: 'macOS-11' CPU: amd64 NIM_COMPILE_TO_CPP: true Windows_amd64_batch0_3: From 424e87fd0917704155d2e7a94f69435eb50d6037 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 28 Jul 2022 12:43:41 +0200 Subject: [PATCH 08/33] Fixed noinit pragma for closure variables (#20101) --- compiler/ccgstmts.nim | 2 +- compiler/lowerings.nim | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 3ecf684021..0d17031df2 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -405,7 +405,7 @@ proc genClosureVar(p: BProc, a: PNode) = genLineDir(p, a) if immediateAsgn: loadInto(p, a[0], a[2], v) - else: + elif sfNoInit notin a[0][1].sym.flags: constructLoc(p, v) proc genVarStmt(p: BProc, n: PNode) = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index de2f678d70..fc66fc9fa2 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -241,7 +241,8 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym assert t.kind != tyTyped propagateToOwner(obj, t) field.position = obj.n.len - field.flags = s.flags * {sfCursor} + # sfNoInit flag for skField is used in closureiterator codegen + field.flags = s.flags * {sfCursor, sfNoInit} obj.n.add newSymNode(field) fieldCheck() result = field From 528b6d1c3f001944a7a7754c8884178e365e6871 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 28 Jul 2022 15:09:58 +0200 Subject: [PATCH 09/33] Warn when casting to a larger type (#20103) * Warn when casting to a larger type * Revert change to error message to fix CI --- compiler/lineinfos.nim | 2 ++ compiler/semexprs.nim | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 071316f15b..07cc988a92 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -80,6 +80,7 @@ type warnHoleEnumConv = "HoleEnumConv", warnCstringConv = "CStringConv", warnEffect = "Effect", + warnCastSizes = "CastSizes" warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -173,6 +174,7 @@ const warnHoleEnumConv: "$1", warnCstringConv: "$1", warnEffect: "$1", + warnCastSizes: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1bb4f49ce4..d3c62629d3 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -196,10 +196,10 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = else: discard -proc isCastable(c: PContext; dst, src: PType): bool = +proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool = ## Checks whether the source type can be cast to the destination type. ## Casting is very unrestrictive; casts are allowed as long as - ## castDest.size >= src.size, and typeAllowed(dst, skParam) + ## dst.size >= src.size, and typeAllowed(dst, skParam) #const # castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, # tySequence, tyPointer, tyNil, tyOpenArray, @@ -228,19 +228,21 @@ proc isCastable(c: PContext; dst, src: PType): bool = # Just assume the programmer knows what he is doing. return true if dstSize < 0: - result = false + return false elif srcSize < 0: - result = false + return false elif typeAllowed(dst, skParam, c) != nil: - result = false + return false elif dst.kind == tyProc and dst.callConv == ccClosure: - result = src.kind == tyProc and src.callConv == ccClosure + return src.kind == tyProc and src.callConv == ccClosure else: result = (dstSize >= srcSize) or (skipTypes(dst, abstractInst).kind in IntegralTypes) or (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes) + if result and (dstSize > srcSize): + message(conf, info, warnCastSizes, "target type is larger than source type") if result and src.kind == tyNil: - result = dst.size <= conf.target.ptrSize + return dst.size <= conf.target.ptrSize proc isSymChoice(n: PNode): bool {.inline.} = result = n.kind in nkSymChoices @@ -359,7 +361,7 @@ proc semCast(c: PContext, n: PNode): PNode = let castedExpr = semExprWithType(c, n[1]) if tfHasMeta in targetType.flags: localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) - if not isCastable(c, targetType, castedExpr.typ): + if not isCastable(c, targetType, castedExpr.typ, n.info): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar From 99dd588d6b9f80229fcd9ae47163649889211b33 Mon Sep 17 00:00:00 2001 From: Sojin <77185816+SojinSamuel@users.noreply.github.com> Date: Sun, 31 Jul 2022 14:37:06 +0530 Subject: [PATCH 10/33] The internal link to koch.rst docs was broken (#20113) Broken Link found for koch.rst docs The Current internal link was broken. Updated with a new link to the same path --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8999091e64..39ddca17a6 100644 --- a/readme.md +++ b/readme.md @@ -104,7 +104,7 @@ can run a subset of tests by specifying a category (for example ``./koch tests cat async``). For more information on the ``koch`` build tool please see the documentation -within the [doc/koch.rst](doc/koch.rst) file. +within the [doc/koch.md](doc/koch.md) file. ## Nimble From 40e0048a504c1009e143fb62ad260625a2b2a53d Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 31 Jul 2022 16:38:00 +0300 Subject: [PATCH 11/33] Highlight Nim default in Markdown code in .nim (#20110) Highlight Nim by default in Markdown code in .nim --- lib/packages/docutils/rst.nim | 25 +++++++++++++++---------- lib/packages/docutils/rstgen.nim | 2 +- tests/stdlib/trst.nim | 7 ++++++- tests/stdlib/trstgen.nim | 7 ++++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index bca877c2fa..f9fbb521fe 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1688,6 +1688,18 @@ proc mayLoadFile(p: RstParser, result: var PRstNode) = n.add newLeaf(readFile(path)) result.sons[2] = n +proc defaultCodeLangNim(p: RstParser, result: var PRstNode) = + # Create a field block if the input block didn't have any. + if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) + assert result.sons[1].kind == rnFieldList + # Hook the extra field and specify the Nim language as value. + var extraNode = newRstNode(rnField, info=lineInfo(p)) + extraNode.add(newRstNode(rnFieldName)) + extraNode.add(newRstNode(rnFieldBody)) + extraNode.sons[0].add newLeaf("default-language") + extraNode.sons[1].add newLeaf("Nim") + result.sons[1].add(extraNode) + proc parseMarkdownCodeblock(p: var RstParser): PRstNode = result = newRstNodeA(p, rnCodeBlock) result.sons.setLen(3) @@ -1731,6 +1743,8 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = var lb = newRstNode(rnLiteralBlock) lb.add(n) result.sons[2] = lb + if result.sons[0].isNil and roNimFile in p.s.options: + defaultCodeLangNim(p, result) proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = var desc, link = "" @@ -3227,16 +3241,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = # Extend the field block if we are using our custom Nim extension. if nimExtension: - # Create a field block if the input block didn't have any. - if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) - assert result.sons[1].kind == rnFieldList - # Hook the extra field and specify the Nim language as value. - var extraNode = newRstNode(rnField, info=lineInfo(p)) - extraNode.add(newRstNode(rnFieldName)) - extraNode.add(newRstNode(rnFieldBody)) - extraNode.sons[0].add newLeaf("default-language") - extraNode.sons[1].add newLeaf("Nim") - result.sons[1].add(extraNode) + defaultCodeLangNim(p, result) proc dirContainer(p: var RstParser): PRstNode = result = parseDirective(p, rnContainer, {hasArg}, parseSectionWrapper) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 8eb4be6754..11c91a40cd 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1074,7 +1074,7 @@ proc renderCode(d: PDoc, n: PRstNode, result: var string) = blockEnd = "}" dispA(d.target, result, blockStart, blockStart, []) if params.lang == langNone: - if len(params.langStr) > 0: + if len(params.langStr) > 0 and params.langStr.toLowerAscii != "none": rstMessage(d.filenames, d.msgHandler, n.info, mwUnsupportedLanguage, params.langStr) for letter in m.text: escChar(d.target, result, letter, emText) diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 6550a26135..70d9921662 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -474,7 +474,12 @@ suite "RST parsing": let expectCodeBlock = dedent""" rnCodeBlock [nil] - [nil] + rnFieldList + rnField + rnFieldName + rnLeaf 'default-language' + rnFieldBody + rnLeaf 'Nim' rnLiteralBlock rnLeaf ' let a = 1 diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 3a9e79bf7d..42e463a045 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -582,9 +582,14 @@ Test literal block ``` let x = 1 ``` """ - let output1 = input1.toHtml + let output1 = input1.toHtml({roSupportMarkdown, roPreferMarkdown}) doAssert " Date: Mon, 1 Aug 2022 08:01:36 +0800 Subject: [PATCH 12/33] replace the broken link for ORC implementation with a working one (#20105) --- lib/system/orc.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 4c23aea6c6..32c6b9adc4 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -8,7 +8,7 @@ # # Cycle collector based on -# https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf +# https://www.cs.purdue.edu/homes/hosking/690M/Bacon01Concurrent.pdf # And ideas from Lins' in 2008 by the notion of "critical links", see # "Cyclic reference counting" by Rafael Dueire Lins # R.D. Lins / Information Processing Letters 109 (2008) 71–78 From a8590d6707ebc5e1e278cd45f43acd15f5f92fe4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 1 Aug 2022 08:02:23 +0800 Subject: [PATCH 13/33] [ORC] replace threadpool with createThread in the runnableExamples (#20106) replace threadpool with createThreads in the runnableExamples --- lib/pure/random.nim | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 7676ce6cf7..bcf6156afb 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -178,24 +178,31 @@ proc skipRandomNumbers*(s: var Rand) = ## **See also:** ## * `next proc<#next,Rand>`_ runnableExamples("--threads:on"): - import std/[random, threadpool] + import std/random - const spawns = 4 const numbers = 100000 - proc randomSum(r: Rand): int = - var r = r + var + thr: array[0..3, Thread[(Rand, int)]] + vals: array[0..3, int] + + proc randomSum(params: tuple[r: Rand, index: int]) {.thread.} = + var r = params.r for i in 1..numbers: - result += r.rand(0..10) + vals[params.index] += r.rand(0..10) var r = initRand(2019) - var vals: array[spawns, FlowVar[int]] - for val in vals.mitems: - val = spawn randomSum(r) + for i in 0.. Date: Sun, 31 Jul 2022 20:08:01 -0400 Subject: [PATCH 14/33] [Doc] Fix some minor markup errors in manual (#20112) * Fix header level for noalias pragma section. * Fix code snippet outside of code block that raised an error with `rst2html`. * Fix broken 'Convertible relation' links that were raising warnings. Co-authored-by: quantimnot --- doc/manual.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index ae9ad5aad4..75ed3d0145 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -1145,11 +1145,11 @@ The following floating-point types are pre-defined: have the suffix 'fXX. -Automatic type conversion in expressions with different kinds -of floating-point types is performed: See `Convertible relation`_ for further -details. Arithmetic performed on floating-point types follows the IEEE -standard. Integer types are not converted to floating-point types automatically -and vice versa. +Automatic type conversion in expressions with different kinds of floating-point +types is performed: See `Convertible relation +<#type-relations-convertible-relation>`_ for further details. Arithmetic +performed on floating-point types follows the IEEE standard. Integer types are +not converted to floating-point types automatically and vice versa. The IEEE standard defines five types of floating-point exceptions: @@ -3731,9 +3731,9 @@ notation. (Thus an operator can have more than two parameters): proc `*+` (a, b, c: int): int = # Multiply and add result = a * b + c - ``` assert `*+`(3, 4, 6) == `+`(`*`(a, b), c) + ``` Export marker @@ -4589,7 +4589,8 @@ Converters ========== A converter is like an ordinary proc except that it enhances -the "implicitly convertible" type relation (see `Convertible relation`_): +the "implicitly convertible" type relation (see `Convertible relation +<#type-relations-convertible-relation>`_): ```nim # bad style ahead: Nim is not C. @@ -7312,7 +7313,7 @@ This pragma has no effect on the JS backend. Noalias pragma -============== +-------------- Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables and parameters. It is mapped directly to C/C++'s `restrict`:c: keyword and means that From 3987a3bf9719362306cb824f99f865da2f59c131 Mon Sep 17 00:00:00 2001 From: Sultan Al Isaiee Date: Mon, 1 Aug 2022 04:20:25 +0400 Subject: [PATCH 15/33] Add Wider Ascii Chars sets and func for string formatting (#19994) * Add more Ascii Chars sets - add UpperCaseLetters set - add LowerCaseLetters set - add Punctuations set - add PrintablesNoWhiteSpace set - add Printables set - add isPunctuationAscii func - add isPrintableAscii func * Omit isPunctuationAscii and isPrintableAscii procs * Apply suggestions for adding Wider Ascii Chars sets Co-authored-by: Clay Sweetser * Update strutils.nim Co-authored-by: Clay Sweetser --- lib/pure/strutils.nim | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index ffbefd0fb8..9302e9cffb 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -80,7 +80,8 @@ export toLower, toUpper include "system/inclrtl" import std/private/since -from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl +from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, + startsWithImpl, endsWithImpl when defined(nimPreviewSlimSystem): import std/assertions @@ -94,6 +95,18 @@ const Letters* = {'A'..'Z', 'a'..'z'} ## The set of letters. + UppercaseLetters* = {'A'..'Z'} + ## The set of uppercase ASCII letters. + + LowercaseLetters* = {'a'..'z'} + ## The set of lowercase ASCII letters. + + PunctuationChars* = {'!'..'/', ':'..'@', '['..'`', '{'..'~'} + ## The set of all ASCII punctuation characters. + + PrintableChars* = Letters + Digits + PunctuationChars + Whitespace + ## The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). + Digits* = {'0'..'9'} ## The set of digits. @@ -172,7 +185,7 @@ func isLowerAscii*(c: char): bool {.rtl, extern: "nsuIsLowerAsciiChar".} = doAssert isLowerAscii('e') == true doAssert isLowerAscii('E') == false doAssert isLowerAscii('7') == false - return c in {'a'..'z'} + return c in LowercaseLetters func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = ## Checks whether or not `c` is an upper case character. @@ -186,8 +199,7 @@ func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = doAssert isUpperAscii('e') == false doAssert isUpperAscii('E') == true doAssert isUpperAscii('7') == false - return c in {'A'..'Z'} - + return c in UppercaseLetters func toLowerAscii*(c: char): char {.rtl, extern: "nsuToLowerAsciiChar".} = ## Returns the lower case version of character `c`. @@ -202,7 +214,7 @@ func toLowerAscii*(c: char): char {.rtl, extern: "nsuToLowerAsciiChar".} = runnableExamples: doAssert toLowerAscii('A') == 'a' doAssert toLowerAscii('e') == 'e' - if c in {'A'..'Z'}: + if c in UppercaseLetters: result = char(uint8(c) xor 0b0010_0000'u8) else: result = c @@ -239,7 +251,7 @@ func toUpperAscii*(c: char): char {.rtl, extern: "nsuToUpperAsciiChar".} = runnableExamples: doAssert toUpperAscii('a') == 'A' doAssert toUpperAscii('E') == 'E' - if c in {'a'..'z'}: + if c in LowercaseLetters: result = char(uint8(c) xor 0b0010_0000'u8) else: result = c @@ -289,7 +301,7 @@ func nimIdentNormalize*(s: string): string = result[0] = s[0] var j = 1 for i in 1..len(s) - 1: - if s[i] in {'A'..'Z'}: + if s[i] in UppercaseLetters: result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) inc j elif s[i] != '_': @@ -311,7 +323,7 @@ func normalize*(s: string): string {.rtl, extern: "nsuNormalize".} = result = newString(s.len) var j = 0 for i in 0..len(s) - 1: - if s[i] in {'A'..'Z'}: + if s[i] in UppercaseLetters: result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) inc j elif s[i] != '_': @@ -1515,7 +1527,8 @@ func delete*(s: var string, slice: Slice[int]) = inc(j) setLen(s, newLen) -func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete", deprecated: "use `delete(s, first..last)`".} = +func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete", + deprecated: "use `delete(s, first..last)`".} = ## Deletes in `s` the characters at positions `first .. last` (both ends included). runnableExamples("--warning:deprecated:off"): var a = "abracadabra" @@ -2239,7 +2252,7 @@ func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, doAssert insertSep("1000000") == "1_000_000" result = newStringOfCap(s.len) let hasPrefix = isDigit(s[s.low]) == false - var idx:int + var idx: int if hasPrefix: result.add s[s.low] for i in (s.low + 1)..s.high: @@ -2253,7 +2266,7 @@ func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, result.setLen(L + idx) var j = 0 dec(L) - for i in countdown(partsLen-1,0): + for i in countdown(partsLen-1, 0): if j == digits: result[L + idx] = sep dec(L) @@ -2354,7 +2367,7 @@ func validIdentifier*(s: string): bool {.rtl, extern: "nsuValidIdentifier".} = # floating point formatting: when not defined(js): func c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs} + importc: "sprintf", varargs.} type FloatFormatMode* = enum From 77891cedaeeb9283793c34b231d8d8c4f19002de Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Sun, 31 Jul 2022 23:24:14 -0400 Subject: [PATCH 16/33] Fix "Add Wider Ascii Chars sets and func for string formatting" (#20120) --- lib/pure/strutils.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 9302e9cffb..0585b64804 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -104,9 +104,6 @@ const PunctuationChars* = {'!'..'/', ':'..'@', '['..'`', '{'..'~'} ## The set of all ASCII punctuation characters. - PrintableChars* = Letters + Digits + PunctuationChars + Whitespace - ## The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). - Digits* = {'0'..'9'} ## The set of digits. @@ -123,6 +120,9 @@ const ## The set of characters a newline terminator can start with (carriage ## return, line feed). + PrintableChars* = Letters + Digits + PunctuationChars + Whitespace + ## The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). + AllChars* = {'\x00'..'\xFF'} ## A set with all the possible characters. ## From 59befed8ee44f9e1749d5e8417fa301ef8e1c953 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 2 Aug 2022 00:06:27 +0800 Subject: [PATCH 17/33] prevent cache thrashing (#20129) * prevent cache thrash Co-authored-by: Charles Blake * Update lib/pure/random.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Charles Blake Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/random.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index bcf6156afb..e2a7ff5bd5 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -188,8 +188,10 @@ proc skipRandomNumbers*(s: var Rand) = proc randomSum(params: tuple[r: Rand, index: int]) {.thread.} = var r = params.r + var s = 0 # avoid cache thrashing for i in 1..numbers: - vals[params.index] += r.rand(0..10) + s += r.rand(0..10) + vals[params.index] = s var r = initRand(2019) for i in 0.. Date: Tue, 2 Aug 2022 15:50:42 +0400 Subject: [PATCH 18/33] [Changelog] Add Wider Ascii Chars sets string formatting in strutils.nim (#20137) * Add Wider Ascii Chars sets string formatting in strutils.nim Add Wider Ascii Chars sets for string formatting (#19994) (#20120): - Added `UppercaseLetters`, `LowercaseLetters` The set of UppercaseLetters and lowercase ASCII letters. - Added `PunctuationChars` The set of all ASCII punctuation characters. - Added `PrintableChars` The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). * Update changelog.md Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update changelog.md Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 580db2cd05..b36ebf6106 100644 --- a/changelog.md +++ b/changelog.md @@ -53,6 +53,7 @@ - Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) in `jscore` for JavaScript targets. +- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. From 02cbd7dc5360a175ca32d13ce0fe06467d59d51e Mon Sep 17 00:00:00 2001 From: random-bites <86238293+random-bites@users.noreply.github.com> Date: Tue, 2 Aug 2022 22:44:14 -0800 Subject: [PATCH 19/33] Edits to sections 'Open arrays' and 'varargs'. (#20140) --- doc/manual.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index 75ed3d0145..380cddf2eb 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -1528,14 +1528,14 @@ Open arrays Often fixed size arrays turn out to be too inflexible; procedures should be able to deal with arrays of different sizes. The `openarray`:idx: type -allows this; it can only be used for parameters. Openarrays are always +allows this; it can only be used for parameters. Open arrays are always indexed with an `int` starting at position 0. The `len`, `low` and `high` operations are available for open arrays too. Any array with -a compatible base type can be passed to an openarray parameter, the index +a compatible base type can be passed to an open array parameter, the index type does not matter. In addition to arrays, sequences can also be passed to an open array parameter. -The openarray type cannot be nested: multidimensional openarrays are not +The `openarray` type cannot be nested: multidimensional open arrays are not supported because this is seldom needed and cannot be done efficiently. ```nim @@ -1548,8 +1548,8 @@ supported because this is seldom needed and cannot be done efficiently. Varargs ------- -A `varargs` parameter is an openarray parameter that additionally -allows to pass a variable number of arguments to a procedure. The compiler +A `varargs` parameter is an open array parameter that additionally +allows a variable number of arguments to be passed to a procedure. The compiler converts the list of arguments to an array implicitly: ```nim @@ -1563,7 +1563,7 @@ converts the list of arguments to an array implicitly: myWriteln(stdout, ["abc", "def", "xyz"]) ``` -This transformation is only done if the varargs parameter is the +This transformation is only done if the `varargs` parameter is the last parameter in the procedure header. It is also possible to perform type conversions in this context: From 0d734d7966644018207a20cf23f16912f9c276d8 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 3 Aug 2022 08:46:36 +0200 Subject: [PATCH 20/33] Fixed compilation of void closureiters with try stmt (#20138) [backport] --- compiler/closureiters.nim | 11 +++++++---- tests/iter/tyieldintry.nim | 8 ++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 2848942fa7..613fbe582c 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -825,10 +825,13 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode = let retStmt = if ctx.nearestFinally == 0: # last finally, we can return - let asgn = newTree(nkFastAsgn, - newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info), - ctx.newTmpResultAccess()) - newTree(nkReturnStmt, asgn) + let retValue = if ctx.fn.typ[0].isNil: + ctx.g.emptyNode + else: + newTree(nkFastAsgn, + newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info), + ctx.newTmpResultAccess()) + newTree(nkReturnStmt, retValue) else: # bubble up to next finally newTree(nkGotoState, ctx.g.newIntLit(info, ctx.nearestFinally)) diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 9862fe1dec..9df201dd46 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -495,3 +495,11 @@ block: #17849 - yield in case subject yield 5 test(it, 1, 2, 13, 5) + +block: # void iterator + iterator it() {.closure.} = + try: + yield + except: + discard + var a = it From c08c455016b9e8d1022306939db75b86e5216841 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 3 Aug 2022 22:39:14 +0800 Subject: [PATCH 21/33] Revert "enable nimPreviewDotLikeOps" (#19919) * Revert "enable nimPreviewDotLikeOps (#19598)" This reverts commit 6773ffa63d0b3ab8b8894e84ed417f4eaced9122. * add deprecated message Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- changelog.md | 2 ++ config/config.nims | 1 - tests/config.nims | 1 + tests/stdlib/texperimental.nim | 1 - 4 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 tests/stdlib/texperimental.nim diff --git a/changelog.md b/changelog.md index b36ebf6106..cfbd51de9e 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,8 @@ - `shallowCopy` is removed for ARC/ORC. Use `move` when possible or combine assignment and `sink` for optimization purposes. +- `nimPreviewDotLikeOps` is going to be removed or deprecated. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/config/config.nims b/config/config.nims index b50181eaf4..aa1eda8949 100644 --- a/config/config.nims +++ b/config/config.nims @@ -26,4 +26,3 @@ when defined(windows) and not defined(booting): switch("define", "nimRawSetjmp") switch("define", "nimVersion:" & NimVersion) -switch("define", "nimPreviewDotLikeOps") diff --git a/tests/config.nims b/tests/config.nims index 8c43055212..894c4bea0a 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -37,5 +37,6 @@ switch("define", "nimExperimentalLinenoiseExtra") # preview APIs are expected to be the new default in upcoming versions switch("define", "nimPreviewFloatRoundtrip") +switch("define", "nimPreviewDotLikeOps") switch("define", "nimPreviewJsonutilsHoleyEnum") switch("define", "nimPreviewHashRef") diff --git a/tests/stdlib/texperimental.nim b/tests/stdlib/texperimental.nim deleted file mode 100644 index ba8c4eb80d..0000000000 --- a/tests/stdlib/texperimental.nim +++ /dev/null @@ -1 +0,0 @@ -doAssert defined(nimPreviewDotLikeOps) \ No newline at end of file From 09840c09e4407400cd61ff2b3696c80b5ca0ec92 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 4 Aug 2022 04:05:57 +0800 Subject: [PATCH 22/33] closes #20123; remove builds.sr.ht (#20131) --- .builds/freebsd.yml | 33 --------------------------------- .builds/openbsd_0.yml | 33 --------------------------------- .builds/openbsd_1.yml | 33 --------------------------------- 3 files changed, 99 deletions(-) delete mode 100644 .builds/freebsd.yml delete mode 100644 .builds/openbsd_0.yml delete mode 100644 .builds/openbsd_1.yml diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml deleted file mode 100644 index 15d09dda0c..0000000000 --- a/.builds/freebsd.yml +++ /dev/null @@ -1,33 +0,0 @@ -## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` - -# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd -image: freebsd/latest -packages: -- databases/sqlite3 -- devel/boehm-gc-threaded -- devel/pcre -- devel/sdl20 -- devel/sfml -- www/node -- devel/gmake - - -sources: -- https://github.com/nim-lang/Nim -environment: - NIM_TESTAMENT_BATCH: "0_1" - CC: /usr/bin/clang -tasks: -- setup: | - set -e - cd Nim - . ci/funs.sh && nimBuildCsourcesIfNeeded - echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv -- test: | - set -e - cd Nim - . ci/funs.sh && nimInternalBuildKochAndRunCI -triggers: -- action: email - condition: failure - to: Andreas Rumpf diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml deleted file mode 100644 index c3b2fd43e8..0000000000 --- a/.builds/openbsd_0.yml +++ /dev/null @@ -1,33 +0,0 @@ -## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` - -image: openbsd/latest -packages: -- gmake -- sqlite3 -- node -- boehm-gc -- pcre -- sfml -- sdl2 -- libffi - - -sources: -- https://github.com/nim-lang/Nim -environment: - NIM_TESTAMENT_BATCH: "0_2" - CC: /usr/bin/clang -tasks: -- setup: | - set -e - cd Nim - . ci/funs.sh && nimBuildCsourcesIfNeeded - echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv -- test: | - set -e - cd Nim - . ci/funs.sh && nimInternalBuildKochAndRunCI -triggers: -- action: email - condition: failure - to: Andreas Rumpf diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml deleted file mode 100644 index e98ec46409..0000000000 --- a/.builds/openbsd_1.yml +++ /dev/null @@ -1,33 +0,0 @@ -## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` - -image: openbsd/latest -packages: -- gmake -- sqlite3 -- node -- boehm-gc -- pcre -- sfml -- sdl2 -- libffi - - -sources: -- https://github.com/nim-lang/Nim -environment: - NIM_TESTAMENT_BATCH: "1_2" - CC: /usr/bin/clang -tasks: -- setup: | - set -e - cd Nim - . ci/funs.sh && nimBuildCsourcesIfNeeded - echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv -- test: | - set -e - cd Nim - . ci/funs.sh && nimInternalBuildKochAndRunCI -triggers: -- action: email - condition: failure - to: Andreas Rumpf From 7af484da947abc5dfc1e941a45c1cde5ee995aae Mon Sep 17 00:00:00 2001 From: gecko Date: Thu, 4 Aug 2022 05:46:08 +0100 Subject: [PATCH 23/33] Add client.close() in httpclient examples. (#20118) Without this, the httpclient examples are essentially setting you up for failure. I was bitten by this when my app became unable to open any more sockets. I'm not entirely sure how long this will relevant, as I hope destructors will be added to an upcoming version of the stdlib. But figured it was worth submitting anyways! --- lib/pure/httpclient.nim | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 5b6e439dbd..dcd1f87d6c 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -19,7 +19,10 @@ ## .. code-block:: Nim ## import std/httpclient ## var client = newHttpClient() -## echo client.getContent("http://google.com") +## try: +## echo client.getContent("http://google.com") +## finally: +## client.close() ## ## The same action can also be performed asynchronously, simply use the ## `AsyncHttpClient`: @@ -29,7 +32,10 @@ ## ## proc asyncProc(): Future[string] {.async.} = ## var client = newAsyncHttpClient() -## return await client.getContent("http://example.com") +## try: +## return await client.getContent("http://example.com") +## finally: +## client.close() ## ## echo waitFor asyncProc() ## @@ -53,8 +59,10 @@ ## data["output"] = "soap12" ## data["uploaded_file"] = ("test.html", "text/html", ## "

test

") -## -## echo client.postContent("http://validator.w3.org/check", multipart=data) +## try: +## echo client.postContent("http://validator.w3.org/check", multipart=data) +## finally: +## client.close() ## ## To stream files from disk when performing the request, use `addFiles`. ## @@ -66,8 +74,10 @@ ## var client = newHttpClient() ## var data = newMultipartData() ## data.addFiles({"uploaded_file": "test.html"}, mimeDb = mimes) -## -## echo client.postContent("http://validator.w3.org/check", multipart=data) +## try: +## echo client.postContent("http://validator.w3.org/check", multipart=data) +## finally: +## client.close() ## ## You can also make post requests with custom headers. ## This example sets `Content-Type` to `application/json` @@ -81,8 +91,11 @@ ## let body = %*{ ## "data": "some text" ## } -## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body) -## echo response.status +## try: +## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body) +## echo response.status +## finally: +## client.close() ## ## Progress reporting ## ================== @@ -101,7 +114,10 @@ ## proc asyncProc() {.async.} = ## var client = newAsyncHttpClient() ## client.onProgressChanged = onProgressChanged -## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## try: +## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## finally: +## client.close() ## ## waitFor asyncProc() ## From 2aeb0d516b5e4cde1abb68a0c0d5393cf8c65915 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:49:51 +0800 Subject: [PATCH 24/33] fixes #20132; fixes the broken jsondoc comand [backport] (#20135) * fixes #20132; fixes the broken jsondoc comand * add testcase --- compiler/docgen.nim | 3 ++- tests/misc/mjsondoc.nim | 11 +++++++++++ tests/misc/trunner.nim | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/misc/mjsondoc.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 0ca1b8c52a..52bb93c19a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1360,9 +1360,10 @@ proc finishGenerateDoc*(d: var PDoc) = var str: string renderRstToOut(d[], resolved, str) entry.json[entry.rstField] = %str - d.jEntriesFinal.add entry.json d.jEntriesPre[i].rst = nil + d.jEntriesFinal.add entry.json # generates docs + proc add(d: PDoc; j: JsonItem) = if j.json != nil or j.rst != nil: d.jEntriesPre.add j diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim new file mode 100644 index 0000000000..e4642f0b49 --- /dev/null +++ b/tests/misc/mjsondoc.nim @@ -0,0 +1,11 @@ +proc doSomething*(x, y: int): int = + ## do something + x + y + +const + a* = 1 ## echo 1234 + b* = "test" + +type + MyEnum* = enum + foo, bar diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 5d12c38b6f..67615cee94 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -216,6 +216,23 @@ sub/mmain.idx""", context let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}" check execCmdEx(cmd) == ("ok3\n", 0) + block: # nim jsondoc # bug #20132 + let file = testsDir / "misc/mjsondoc.nim" + let output = "nimcache_tjsondoc.json" + defer: removeFile(output) + let (msg, exitCode) = execCmdEx(fmt"{nim} jsondoc -o:{output} {file}") + doAssert exitCode == 0, msg + + let data = parseJson(readFile(output))["entries"] + doAssert data.len == 4 + let doSomething = data[0] + doAssert doSomething["name"].getStr == "doSomething" + doAssert doSomething["type"].getStr == "skProc" + doAssert doSomething["line"].getInt == 1 + doAssert doSomething["col"].getInt == 0 + doAssert doSomething["code"].getStr == "proc doSomething(x, y: int): int {.raises: [], tags: [], forbids: [].}" + + block: # further issues with `--backend` let file = testsDir / "misc/mbackend.nim" var cmd = fmt"{nim} doc -b:cpp --hints:off --nimcache:{nimcache} {file}" From a34dd3d77a3c76b5bb5c1939412f592c6fdbd771 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 4 Aug 2022 10:32:23 +0300 Subject: [PATCH 25/33] Markdown code blocks part 3 (#20117) No logic was added, just 4 more files migrated. --- doc/astspec.txt | 400 +++++++++++++++++++++++++++++--------------- doc/backends.md | 63 +++---- doc/contributing.md | 120 ++++++------- doc/destructors.md | 103 +++++------- doc/manual.md | 6 +- 5 files changed, 409 insertions(+), 283 deletions(-) diff --git a/doc/astspec.txt b/doc/astspec.txt index dbbe2799df..bfaec71556 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -6,8 +6,7 @@ The AST consists of nodes (``NimNode``) with a variable number of children. Each node has a field named ``kind`` which describes what the node contains: -.. code-block:: nim - + ```nim type NimNodeKind = enum ## kind of a node; only explanatory nnkNone, ## invalid node kind @@ -32,6 +31,7 @@ contains: strVal: string ## the string literal else: sons: seq[NimNode] ## the node's sons (or children) + ``` For the ``NimNode`` type, the ``[]`` operator has been overloaded: ``n[i]`` is ``n``'s ``i``-th child. @@ -86,17 +86,19 @@ Command call Concrete syntax: -.. code-block:: nim + ```nim echo "abc", "xyz" + ``` AST: -.. code-block:: nim + ```nim nnkCommand( nnkIdent("echo"), nnkStrLit("abc"), nnkStrLit("xyz") ) + ``` Call with ``()`` @@ -104,17 +106,19 @@ Call with ``()`` Concrete syntax: -.. code-block:: nim + ```nim echo("abc", "xyz") + ``` AST: -.. code-block:: nim + ```nim nnkCall( nnkIdent("echo"), nnkStrLit("abc"), nnkStrLit("xyz") ) + ``` Infix operator call @@ -122,29 +126,32 @@ Infix operator call Concrete syntax: -.. code-block:: nim + ```nim "abc" & "xyz" + ``` AST: -.. code-block:: nim + ```nim nnkInfix( nnkIdent("&"), nnkStrLit("abc"), nnkStrLit("xyz") ) + ``` Note that with multiple infix operators, the command is parsed by operator precedence. Concrete syntax: -.. code-block:: nim + ```nim 5 + 3 * 4 + ``` AST: -.. code-block:: nim + ```nim nnkInfix( nnkIdent("+"), nnkIntLit(5), @@ -154,6 +161,7 @@ AST: nnkIntLit(4) ) ) + ``` As a side note, if you choose to use infix operators in a prefix form, the AST behaves as a @@ -162,12 +170,13 @@ behaves as a Concrete syntax: -.. code-block:: nim + ```nim `+`(3, 4) + ``` AST: -.. code-block:: nim + ```nim nnkCall( nnkAccQuoted( nnkIdent("+") @@ -175,22 +184,25 @@ AST: nnkIntLit(3), nnkIntLit(4) ) + ``` Prefix operator call -------------------- Concrete syntax: -.. code-block:: nim + ```nim ? "xyz" + ``` AST: -.. code-block:: nim + ```nim nnkPrefix( nnkIdent("?"), nnkStrLit("abc") ) + ``` Postfix operator call @@ -201,16 +213,18 @@ Postfix operator call Concrete syntax: -.. code-block:: nim + ```nim identifier* + ``` AST: -.. code-block:: nim + ```nim nnkPostfix( nnkIdent("*"), nnkIdent("identifier") ) + ``` Call with named arguments @@ -218,12 +232,13 @@ Call with named arguments Concrete syntax: -.. code-block:: nim + ```nim writeLine(file=stdout, "hallo") + ``` AST: -.. code-block:: nim + ```nim nnkCall( nnkIdent("writeLine"), nnkExprEqExpr( @@ -232,6 +247,7 @@ AST: ), nnkStrLit("hallo") ) + ``` Call with raw string literal ---------------------------- @@ -242,29 +258,33 @@ This is used, for example, in the ``bindSym`` examples Concrete syntax: -.. code-block:: nim + ```nim echo"abc" + ``` AST: -.. code-block:: nim + ```nim nnkCallStrLit( nnkIdent("echo"), nnkRStrLit("hello") ) + ``` Dereference operator ``[]`` --------------------------- Concrete syntax: -.. code-block:: nim + ```nim x[] + ``` AST: -.. code-block:: nim + ```nim nnkDerefExpr(nnkIdent("x")) + ``` Addr operator @@ -272,13 +292,15 @@ Addr operator Concrete syntax: -.. code-block:: nim + ```nim addr(x) + ``` AST: -.. code-block:: nim + ```nim nnkAddr(nnkIdent("x")) + ``` Cast operator @@ -286,13 +308,15 @@ Cast operator Concrete syntax: -.. code-block:: nim + ```nim cast[T](x) + ``` AST: -.. code-block:: nim + ```nim nnkCast(nnkIdent("T"), nnkIdent("x")) + ``` Object access operator ``.`` @@ -300,13 +324,15 @@ Object access operator ``.`` Concrete syntax: -.. code-block:: nim + ```nim x.y + ``` AST: -.. code-block:: nim + ```nim nnkDotExpr(nnkIdent("x"), nnkIdent("y")) + ``` If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the same as above but wrapped in an ``nnkCall``. @@ -317,13 +343,15 @@ Array access operator ``[]`` Concrete syntax: -.. code-block:: nim + ```nim x[y] + ``` AST: -.. code-block:: nim + ```nim nnkBracketExpr(nnkIdent("x"), nnkIdent("y")) + ``` Parentheses @@ -333,16 +361,18 @@ Parentheses for affecting operator precedence use the ``nnkPar`` node. Concrete syntax: -.. code-block:: nim + ```nim (a + b) * c + ``` AST: -.. code-block:: nim + ```nim nnkInfix(nnkIdent("*"), nnkPar( nnkInfix(nnkIdent("+"), nnkIdent("a"), nnkIdent("b"))), nnkIdent("c")) + ``` Tuple Constructors ------------------ @@ -351,35 +381,39 @@ Nodes for tuple construction are built with the ``nnkTupleConstr`` node. Concrete syntax: -.. code-block:: nim + ```nim (1, 2, 3) (a: 1, b: 2, c: 3) () + ``` AST: -.. code-block:: nim + ```nim nnkTupleConstr(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) nnkTupleConstr( nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)), nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)), nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3))) nnkTupleConstr() + ``` Since the one tuple would be syntactically identical to parentheses with an expression in them, the parser expects a trailing comma for them. For tuple constructors with field names, this is not necessary. -.. code-block:: nim + ```nim (1,) (a: 1) + ``` AST: -.. code-block:: nim + ```nim nnkTupleConstr(nnkIntLit(1)) nnkTupleConstr( nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1))) + ``` Curly braces ------------ @@ -388,28 +422,32 @@ Curly braces are used as the set constructor. Concrete syntax: -.. code-block:: nim + ```nim {1, 2, 3} + ``` AST: -.. code-block:: nim + ```nim nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) + ``` When used as a table constructor, the syntax is different. Concrete syntax: -.. code-block:: nim + ```nim {a: 3, b: 5} + ``` AST: -.. code-block:: nim + ```nim nnkTableConstr( nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)), nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5)) ) + ``` Brackets @@ -419,13 +457,15 @@ Brackets are used as the array constructor. Concrete syntax: -.. code-block:: nim + ```nim [1, 2, 3] + ``` AST: -.. code-block:: nim + ```nim nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) + ``` Ranges @@ -437,21 +477,23 @@ AST, construction with ``..`` as an infix operator should be used instead. Concrete syntax: -.. code-block:: nim + ```nim 1..3 + ``` AST: -.. code-block:: nim + ```nim nnkInfix( nnkIdent(".."), nnkIntLit(1), nnkIntLit(3) ) + ``` Example code: -.. code-block:: nim + ```nim macro genRepeatEcho() = result = newNimNode(nnkStmtList) @@ -470,6 +512,7 @@ Example code: # 3 # 3 # 3 + ``` If expression @@ -479,17 +522,19 @@ The representation of the ``if`` expression is subtle, but easy to traverse. Concrete syntax: -.. code-block:: nim + ```nim if cond1: expr1 elif cond2: expr2 else: expr3 + ``` AST: -.. code-block:: nim + ```nim nnkIfExpr( nnkElifExpr(cond1, expr1), nnkElifExpr(cond2, expr2), nnkElseExpr(expr3) ) + ``` Documentation Comments ---------------------- @@ -500,19 +545,21 @@ comments are ignored. Concrete syntax: -.. code-block:: nim + ```nim ## This is a comment ## This is part of the first comment stmt1 ## Yet another + ``` AST: -.. code-block:: nim + ```nim nnkCommentStmt() # only appears once for the first two lines! stmt1 nnkCommentStmt() # another nnkCommentStmt because there is another comment # (separate from the first) + ``` Pragmas ------- @@ -523,30 +570,33 @@ objects, but the standalone ``emit`` pragma shows the basics with the AST. Concrete syntax: -.. code-block:: nim + ```nim {.emit: "#include ".} + ``` AST: -.. code-block:: nim + ```nim nnkPragma( nnkExprColonExpr( nnkIdent("emit"), nnkStrLit("#include ") # the "argument" ) ) + ``` As many ``nnkIdent`` appear as there are pragmas between ``{..}``. Note that the declaration of new pragmas is essentially the same: Concrete syntax: -.. code-block:: nim + ```nim {.pragma: cdeclRename, cdecl.} + ``` AST: -.. code-block:: nim + ```nim nnkPragma( nnkExprColonExpr( nnkIdent("pragma"), # this is always first when declaring a new pragma @@ -554,6 +604,7 @@ AST: ), nnkIdent("cdecl") ) + ``` Statements ========== @@ -566,7 +617,7 @@ there is no ``else`` branch, no ``nnkElse`` child exists. Concrete syntax: -.. code-block:: nim + ```nim if cond1: stmt1 elif cond2: @@ -575,16 +626,18 @@ Concrete syntax: stmt3 else: stmt4 + ``` AST: -.. code-block:: nim + ```nim nnkIfStmt( nnkElifBranch(cond1, stmt1), nnkElifBranch(cond2, stmt2), nnkElifBranch(cond3, stmt3), nnkElse(stmt4) ) + ``` When statement @@ -598,13 +651,15 @@ Assignment Concrete syntax: -.. code-block:: nim + ```nim x = 42 + ``` AST: -.. code-block:: nim + ```nim nnkAsgn(nnkIdent("x"), nnkIntLit(42)) + ``` This is not the syntax for assignment when combined with ``var``, ``let``, or ``const``. @@ -614,15 +669,17 @@ Statement list Concrete syntax: -.. code-block:: nim + ```nim stmt1 stmt2 stmt3 + ``` AST: -.. code-block:: nim + ```nim nnkStmtList(stmt1, stmt2, stmt3) + ``` Case statement @@ -630,7 +687,7 @@ Case statement Concrete syntax: -.. code-block:: nim + ```nim case expr1 of expr2, expr3..expr4: stmt1 @@ -640,10 +697,11 @@ Concrete syntax: stmt3 else: stmt4 + ``` AST: -.. code-block:: nim + ```nim nnkCaseStmt( expr1, nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1), @@ -651,6 +709,7 @@ AST: nnkElifBranch(cond1, stmt3), nnkElse(stmt4) ) + ``` The ``nnkElifBranch`` and ``nnkElse`` parts may be missing. @@ -660,14 +719,16 @@ While statement Concrete syntax: -.. code-block:: nim + ```nim while expr1: stmt1 + ``` AST: -.. code-block:: nim + ```nim nnkWhileStmt(expr1, stmt1) + ``` For statement @@ -675,14 +736,16 @@ For statement Concrete syntax: -.. code-block:: nim + ```nim for ident1, ident2 in expr1: stmt1 + ``` AST: -.. code-block:: nim + ```nim nnkForStmt(ident1, ident2, expr1, stmt1) + ``` Try statement @@ -690,7 +753,7 @@ Try statement Concrete syntax: -.. code-block:: nim + ```nim try: stmt1 except e1, e2: @@ -701,10 +764,11 @@ Concrete syntax: stmt4 finally: stmt5 + ``` AST: -.. code-block:: nim + ```nim nnkTryStmt( stmt1, nnkExceptBranch(e1, e2, stmt2), @@ -712,6 +776,7 @@ AST: nnkExceptBranch(stmt4), nnkFinally(stmt5) ) + ``` Return statement @@ -719,13 +784,15 @@ Return statement Concrete syntax: -.. code-block:: nim + ```nim return expr1 + ``` AST: -.. code-block:: nim + ```nim nnkReturnStmt(expr1) + ``` Yield statement @@ -733,8 +800,9 @@ Yield statement Like ``return``, but with ``nnkYieldStmt`` kind. -.. code-block:: nim + ```nim nnkYieldStmt(expr1) + ``` Discard statement @@ -742,8 +810,9 @@ Discard statement Like ``return``, but with ``nnkDiscardStmt`` kind. -.. code-block:: nim + ```nim nnkDiscardStmt(expr1) + ``` Continue statement @@ -751,26 +820,30 @@ Continue statement Concrete syntax: -.. code-block:: nim + ```nim continue + ``` AST: -.. code-block:: nim + ```nim nnkContinueStmt() + ``` Break statement --------------- Concrete syntax: -.. code-block:: nim + ```nim break otherLocation + ``` AST: -.. code-block:: nim + ```nim nnkBreakStmt(nnkIdent("otherLocation")) + ``` If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``. @@ -779,13 +852,15 @@ Block statement Concrete syntax: -.. code-block:: nim + ```nim block name: + ``` AST: -.. code-block:: nim + ```nim nnkBlockStmt(nnkIdent("name"), nnkStmtList(...)) + ``` A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used. @@ -794,18 +869,20 @@ Asm statement Concrete syntax: -.. code-block:: nim + ```nim asm """ some asm """ + ``` AST: -.. code-block:: nim + ```nim nnkAsmStmt( nnkEmpty(), # for pragmas nnkTripleStrLit("some asm"), ) + ``` Import section -------------- @@ -815,37 +892,42 @@ on what keywords are present. Let's start with the simplest form. Concrete syntax: -.. code-block:: nim + ```nim import math + ``` AST: -.. code-block:: nim + ```nim nnkImportStmt(nnkIdent("math")) + ``` With ``except``, we get ``nnkImportExceptStmt``. Concrete syntax: -.. code-block:: nim + ```nim import math except pow + ``` AST: -.. code-block:: nim + ```nim nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow")) + ``` Note that ``import math as m`` does not use a different node; rather, we use ``nnkImportStmt`` with ``as`` as an infix operator. Concrete syntax: -.. code-block:: nim + ```nim import strutils as su + ``` AST: -.. code-block:: nim + ```nim nnkImportStmt( nnkInfix( nnkIdent("as"), @@ -853,6 +935,7 @@ AST: nnkIdent("su") ) ) + ``` From statement -------------- @@ -861,13 +944,15 @@ If we use ``from ... import``, the result is different, too. Concrete syntax: -.. code-block:: nim + ```nim from math import pow + ``` AST: -.. code-block:: nim + ```nim nnkFromStmt(nnkIdent("math"), nnkIdent("pow")) + ``` Using ``from math as m import pow`` works identically to the ``as`` modifier with the ``import`` statement, but wrapped in ``nnkFromStmt``. @@ -880,26 +965,30 @@ the ``export`` syntax is pretty straightforward. Concrete syntax: -.. code-block:: nim + ```nim export unsigned + ``` AST: -.. code-block:: nim + ```nim nnkExportStmt(nnkIdent("unsigned")) + ``` Similar to the ``import`` statement, the AST is different for ``export ... except``. Concrete syntax: -.. code-block:: nim + ```nim export math except pow # we're going to implement our own exponentiation + ``` AST: -.. code-block:: nim + ```nim nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow")) + ``` Include statement ----------------- @@ -908,25 +997,28 @@ Like a plain ``import`` statement but with ``nnkIncludeStmt``. Concrete syntax: -.. code-block:: nim + ```nim include blocks + ``` AST: -.. code-block:: nim + ```nim nnkIncludeStmt(nnkIdent("blocks")) + ``` Var section ----------- Concrete syntax: -.. code-block:: nim + ```nim var a = 3 + ``` AST: -.. code-block:: nim + ```nim nnkVarSection( nnkIdentDefs( nnkIdent("a"), @@ -934,6 +1026,7 @@ AST: nnkIntLit(3), ) ) + ``` Note that either the second or third (or both) parameters above must exist, as the compiler needs to know the type somehow (which it can infer from @@ -951,12 +1044,13 @@ This is equivalent to ``var``, but with ``nnkLetSection`` rather than Concrete syntax: -.. code-block:: nim + ```nim let a = 3 + ``` AST: -.. code-block:: nim + ```nim nnkLetSection( nnkIdentDefs( nnkIdent("a"), @@ -964,18 +1058,20 @@ AST: nnkIntLit(3), ) ) + ``` Const section ------------- Concrete syntax: -.. code-block:: nim + ```nim const a = 3 + ``` AST: -.. code-block:: nim + ```nim nnkConstSection( nnkConstDef( # not nnkConstDefs! nnkIdent("a"), @@ -983,6 +1079,7 @@ AST: nnkIntLit(3), # required in a const declaration! ) ) + ``` Type section ------------ @@ -992,12 +1089,13 @@ and ``const``. Concrete syntax: -.. code-block:: nim + ```nim type A = int + ``` AST: -.. code-block:: nim + ```nim nnkTypeSection( nnkTypeDef( nnkIdent("A"), @@ -1005,18 +1103,20 @@ AST: nnkIdent("int") ) ) + ``` Declaring ``distinct`` types is similar, with the last ``nnkIdent`` wrapped in ``nnkDistinctTy``. Concrete syntax: -.. code-block:: nim + ```nim type MyInt = distinct int + ``` AST: -.. code-block:: nim + ```nim # ... nnkTypeDef( nnkIdent("MyInt"), @@ -1025,17 +1125,19 @@ AST: nnkIdent("int") ) ) + ``` If a type section uses generic parameters, they are treated here: Concrete syntax: -.. code-block:: nim + ```nim type A[T] = expr1 + ``` AST: -.. code-block:: nim + ```nim nnkTypeSection( nnkTypeDef( nnkIdent("A"), @@ -1050,6 +1152,7 @@ AST: expr1, ) ) + ``` Note that not all ``nnkTypeDef`` utilize ``nnkIdent`` as their parameter. One of the most common uses of type declarations @@ -1057,12 +1160,13 @@ is to work with objects. Concrete syntax: -.. code-block:: nim + ```nim type IO = object of RootObj + ``` AST: -.. code-block:: nim + ```nim # ... nnkTypeDef( nnkIdent("IO"), @@ -1075,13 +1179,14 @@ AST: nnkEmpty() ) ) + ``` Nim's object syntax is rich. Let's take a look at an involved example in its entirety to see some of the complexities. Concrete syntax: -.. code-block:: nim + ```nim type Obj[T] {.inheritable.} = object name: string case isFat: bool @@ -1089,10 +1194,11 @@ Concrete syntax: m: array[100_000, T] of false: m: array[10, T] + ``` AST: -.. code-block:: nim + ```nim # ... nnkPragmaExpr( nnkIdent("Obj"), @@ -1149,36 +1255,40 @@ AST: ) ) ) + ``` Using an ``enum`` is similar to using an ``object``. Concrete syntax: -.. code-block:: nim + ```nim type X = enum First + ``` AST: -.. code-block:: nim + ```nim # ... nnkEnumTy( nnkEmpty(), nnkIdent("First") # you need at least one nnkIdent or the compiler complains ) + ``` The usage of ``concept`` (experimental) is similar to objects. Concrete syntax: -.. code-block:: nim + ```nim type Con = concept x,y,z (x & y & z) is string + ``` AST: -.. code-block:: nim + ```nim # ... nnkTypeClassTy( # note this isn't nnkConceptTy! nnkArgList( @@ -1186,18 +1296,20 @@ AST: ) # ... ) + ``` Static types, like ``static[int]``, use ``nnkIdent`` wrapped in ``nnkStaticTy``. Concrete syntax: -.. code-block:: nim + ```nim type A[T: static[int]] = object + ``` AST: -.. code-block:: nim + ```nim # ... within nnkGenericParams nnkIdentDefs( nnkIdent("T"), @@ -1207,6 +1319,7 @@ AST: nnkEmpty() ) # ... + ``` In general, declaring types mirrors this syntax (i.e., ``nnkStaticTy`` for ``static``, etc.). Examples follow (exceptions marked by ``*``): @@ -1234,12 +1347,13 @@ Generic parameters are treated in the type, not the ``proc`` itself. Concrete syntax: -.. code-block:: nim + ```nim type MyProc[T] = proc(x: T) + ``` AST: -.. code-block:: nim + ```nim # ... nnkTypeDef( nnkIdent("MyProc"), @@ -1252,6 +1366,7 @@ AST: ) ) ) + ``` The same syntax applies to ``iterator`` (with ``nnkIteratorTy``), but *does not* apply to ``converter`` or ``template``. @@ -1261,26 +1376,30 @@ Mixin statement Concrete syntax: -.. code-block:: nim + ```nim mixin x + ``` AST: -.. code-block:: nim + ```nim nnkMixinStmt(nnkIdent("x")) + ``` Bind statement -------------- Concrete syntax: -.. code-block:: nim + ```nim bind x + ``` AST: -.. code-block:: nim + ```nim nnkBindStmt(nnkIdent("x")) + ``` Procedure declaration --------------------- @@ -1290,12 +1409,13 @@ a feel for how procedure calls are broken down. Concrete syntax: -.. code-block:: nim + ```nim proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard + ``` AST: -.. code-block:: nim + ```nim nnkProcDef( nnkPostfix(nnkIdent("*"), nnkIdent("hello")), # the exported proc name nnkEmpty(), # patterns for term rewriting in templates and macros (not procs) @@ -1323,6 +1443,7 @@ AST: nnkEmpty(), # reserved slot for future use nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc ) + ``` There is another consideration. Nim has flexible type identification for its procs. Even though ``proc(a: int, b: int)`` and ``proc(a, b: int)`` @@ -1330,12 +1451,13 @@ are equivalent in the code, the AST is a little different for the latter. Concrete syntax: -.. code-block:: nim + ```nim proc(a, b: int) + ``` AST: -.. code-block:: nim + ```nim # ...AST as above... nnkFormalParams( nnkEmpty(), # no return here @@ -1347,24 +1469,27 @@ AST: ) ), # ... + ``` When a procedure uses the special ``var`` type return variable, the result is different from that of a var section. Concrete syntax: -.. code-block:: nim + ```nim proc hello(): var int + ``` AST: -.. code-block:: nim + ```nim # ... nnkFormalParams( nnkVarTy( nnkIdent("int") ) ) + ``` Iterator declaration -------------------- @@ -1374,17 +1499,19 @@ replacing ``nnkProcDef``. Concrete syntax: -.. code-block:: nim + ```nim iterator nonsense[T](x: seq[T]): float {.closure.} = ... + ``` AST: -.. code-block:: nim + ```nim nnkIteratorDef( nnkIdent("nonsense"), nnkEmpty(), ... ) + ``` Converter declaration --------------------- @@ -1393,16 +1520,18 @@ A converter is similar to a proc. Concrete syntax: -.. code-block:: nim + ```nim converter toBool(x: float): bool + ``` AST: -.. code-block:: nim + ```nim nnkConverterDef( nnkIdent("toBool"), # ... ) + ``` Template declaration -------------------- @@ -1415,12 +1544,13 @@ the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and Concrete syntax: -.. code-block:: nim + ```nim template optOpt{expr1}(a: int): int + ``` AST: -.. code-block:: nim + ```nim nnkTemplateDef( nnkIdent("optOpt"), nnkStmtList( # instead of nnkEmpty() @@ -1428,6 +1558,7 @@ AST: ), # follows like a proc or iterator ) + ``` If the template does not have types for its parameters, the type identifiers inside ``nnkFormalParams`` just becomes ``nnkEmpty``. @@ -1441,8 +1572,9 @@ Macros behave like templates, but ``nnkTemplateDef`` is replaced with Hidden Standard Conversion -------------------------- -.. code-block:: nim + ```nim var f: float = 1 + ``` The type of "f" is ``float`` but the type of "1" is actually ``int``. Inserting ``int`` into a ``float`` is a type error. Nim inserts the ``nnkHiddenStdConv`` diff --git a/doc/backends.md b/doc/backends.md index 4f8a2bffff..1347314614 100644 --- a/doc/backends.md +++ b/doc/backends.md @@ -57,11 +57,11 @@ project. This allows you to take the generated code and place it directly into a project using any of these languages. Here are some typical command- line invocations: -.. code:: cmd - - nim c hallo.nim - nim cpp hallo.nim - nim objc hallo.nim + ```cmd + nim c hallo.nim + nim cpp hallo.nim + nim objc hallo.nim + ``` The compiler commands select the target backend, but if needed you can `specify additional switches for cross-compilation @@ -99,9 +99,9 @@ default is a ``.js`` file that is supposed to be referenced in an ``.html`` file. However, you can also run the code with `nodejs`:idx: (``_): -.. code:: cmd - + ```cmd nim js -d:nodejs -r examples/hallo.nim + ``` If you experience errors saying that `globalThis` is not defined, be sure to run a recent version of Node.js (at least 12.0). @@ -159,21 +159,22 @@ interface. Create a ``logic.c`` file with the following content: -.. code-block:: c + ```c int addTwoIntegers(int a, int b) { return a + b; } + ``` Create a ``calculator.nim`` file with the following content: -.. code-block:: nim - + ```nim {.compile: "logic.c".} proc addTwoIntegers(a, b: cint): cint {.importc.} when isMainModule: echo addTwoIntegers(3, 7) + ``` With these two files in place, you can run `nim c -r calculator.nim`:cmd: and the Nim compiler will compile the ``logic.c`` file in addition to @@ -182,11 +183,11 @@ run. Another way to link the C file statically and get the same effect would be to remove the line with the `compile` pragma and run the following typical Unix commands: -.. code:: cmd - - gcc -c logic.c - ar rvs mylib.a logic.o - nim c --passL:mylib.a -r calculator.nim + ```cmd + gcc -c logic.c + ar rvs mylib.a logic.o + nim c --passL:mylib.a -r calculator.nim + ``` Just like in this example we pass the path to the ``mylib.a`` library (and we could as well pass ``logic.o``) we could be passing switches to link any other @@ -212,12 +213,12 @@ Create a ``host.html`` file with the following content: Create a ``calculator.nim`` file with the following content (or reuse the one from the previous section): -.. code-block:: nim - + ```nim proc addTwoIntegers(a, b: int): int {.importc.} when isMainModule: echo addTwoIntegers(3, 7) + ``` Compile the Nim code to JavaScript with `nim js -o:calculator.js calculator.nim`:cmd: and open ``host.html`` in a browser. If the browser supports @@ -253,18 +254,17 @@ Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`. Create a ``fib.nim`` file with the following content: -.. code-block:: nim - + ```nim proc fib(a: cint): cint {.exportc.} = if a <= 2: result = 1 else: result = fib(a - 1) + fib(a - 2) + ``` Create a ``maths.c`` file with the following content: -.. code-block:: c - + ```c #include int fib(int a); @@ -277,15 +277,16 @@ Create a ``maths.c`` file with the following content: printf("Fib of %d is %d\n", f, fib(f)); return 0; } + ``` Now you can run the following Unix like commands to first generate C sources from the Nim code, then link them into a static binary along your main C program: -.. code:: cmd - + ```cmd nim c --noMain --noLinking fib.nim gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c + ``` The first command runs the Nim compiler with three special options to avoid generating a `main()`:c: function in the generated files and to avoid linking the @@ -297,10 +298,10 @@ have to tell the C compiler where to find Nim's ``nimbase.h`` header file. Instead of depending on the generation of the individual ``.c`` files you can also ask the Nim compiler to generate a statically linked library: -.. code:: cmd - + ```cmd nim c --app:staticLib --noMain fib.nim gcc -o m -Inimcache -Ipath/to/nim/lib maths.c libfib.nim.a + ``` The Nim compiler will handle linking the source files generated in the ``nimcache`` directory into the ``libfib.nim.a`` static library, which you can @@ -313,25 +314,25 @@ use `-ldl`:option: too to link in required dlopen functionality. Create a ``mhost.html`` file with the following content: -.. code-block:: - + ``` + ``` Create a ``fib.nim`` file with the following content (or reuse the one from the previous section): -.. code-block:: nim - + ```nim proc fib(a: cint): cint {.exportc.} = if a <= 2: result = 1 else: result = fib(a - 1) + fib(a - 2) + ``` Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim`:cmd: and open ``mhost.html`` in a browser. If the browser supports javascript, you @@ -378,10 +379,10 @@ from being freed with `GC_ref `_ and `GC_unref A similar thing happens with C code invoking Nim code which returns a `cstring`. Consider the following proc: -.. code-block:: nim - + ```nim proc gimme(): cstring {.exportc.} = result = "Hey there C code! " & $rand(100) + ``` Since Nim's reference counting mechanism is not aware of the C code, once the `gimme` proc has finished it can reclaim the memory of the `cstring`. diff --git a/doc/contributing.md b/doc/contributing.md index 51d1d5065a..4295623df4 100644 --- a/doc/contributing.md +++ b/doc/contributing.md @@ -59,8 +59,7 @@ things like `echo "done"`. Don't use `unittest.suite` and `unittest.test`. Sample test: -.. code-block:: nim - + ```nim block: # foo doAssert foo(1) == 10 @@ -76,6 +75,7 @@ Sample test: @[false, false], @[false, false]] # doAssert with `not` can now be done as follows: doAssert not (1 == 2) + ``` Always refer to a GitHub issue using the following exact syntax: ``bug #1234`` as shown above, so that it's consistent and easier to search or for tooling. Some browser @@ -110,8 +110,7 @@ For a full spec, see here: ``testament/specs.nim`` An example of a test: -.. code-block:: nim - + ```nim discard """ errormsg: "type mismatch: got (PTest)" """ @@ -123,6 +122,7 @@ An example of a test: var buf: PTest buf.test() + ``` Running tests @@ -130,9 +130,9 @@ Running tests You can run the tests with -.. code-block:: cmd - + ```cmd ./koch tests + ``` which will run a good subset of tests. Some tests may fail. If you only want to see the output of failing tests, go for @@ -145,17 +145,17 @@ You can also run only a single category of tests. A category is a subdirectory in the ``tests/`` directory. There are a couple of special categories; for a list of these, see ``testament/categories.nim``, at the bottom. -.. code:: cmd - + ```cmd ./koch tests c lib # compiles / runs stdlib modules, including `isMainModule` tests ./koch tests c megatest # runs a set of tests that can be combined into 1 + ``` To run a single test: -.. code:: cmd - + ```cmd ./koch test run / # e.g.: tuples/ttuples_issues ./koch test run tests/stdlib/tos.nim # can also provide relative path + ``` For reproducible tests (to reproduce an environment more similar to the one run by Continuous Integration on github actions/azure pipelines), you may want to disable your @@ -174,25 +174,25 @@ The tester can compare two test runs. First, you need to create a reference test. You'll also need to the commit id, because that's what the tester needs to know in order to compare the two. -.. code:: cmd - + ```cmd git checkout devel DEVEL_COMMIT=$(git rev-parse HEAD) ./koch tests + ``` Then switch over to your changes and run the tester again. -.. code:: cmd - + ```cmd git checkout your-changes ./koch tests + ``` Then you can ask the tester to create a ``testresults.html`` which will tell you if any new tests passed/failed. -.. code:: cmd - + ```cmd ./koch tests --print html $DEVEL_COMMIT + ``` Deprecation @@ -201,8 +201,7 @@ Deprecation Backward compatibility is important, so instead of a rename you need to deprecate the old name and introduce a new name: -.. code-block:: nim - + ```nim # for routines (proc/template/macro/iterator) and types: proc oldProc(a: int, b: float): bool {.deprecated: "deprecated since v1.2.3; use `newImpl: string -> int` instead".} = discard @@ -214,6 +213,7 @@ the old name and introduce a new name: # (likewise with object types and their fields): type Bar {.deprecated.} = enum bar0, bar1 type Barz = enum baz0, baz1 {.deprecated.}, baz2 + ``` See also `Deprecated `_ @@ -234,12 +234,13 @@ test cases (typically 1 to 3 `assert` statements, depending on complexity). These `runnableExamples` are automatically run by `nim doc mymodule.nim`:cmd: as well as `testament`:cmd: and guarantee they stay in sync. -.. code-block:: nim + ```nim proc addBar*(a: string): string = ## Adds "Bar" to `a`. runnableExamples: assert "baz".addBar == "bazBar" result = a & "Bar" + ``` See `parentDir `_ example. @@ -247,47 +248,49 @@ The RestructuredText Nim uses has a special syntax for including code snippets embedded in documentation; these are not run by `nim doc`:cmd: and therefore are not guaranteed to stay in sync, so `runnableExamples` is almost always preferred: -.. code-block:: nim - + ````nim proc someProc*(): string = ## Returns "something" ## - ## .. code-block:: - ## echo someProc() # "something" + ## ``` + ## echo someProc() # "something" + ## ``` result = "something" # single-hash comments do not produce documentation + ```` -The ``.. code-block:: nim`` followed by a newline and an indentation instructs the +The \`\`\` followed by a newline and an indentation instructs the `nim doc`:cmd: command to produce syntax-highlighted example code with the -documentation (``.. code-block::`` is sufficient from inside a nim module). +documentation (\`\`\` is sufficient inside a ``.nim`` module, while from +a ``.md`` one needs to set the language explicitly as \`\`\`nim). When forward declaration is used, the documentation should be included with the first appearance of the proc. -.. code-block:: nim - + ```nim proc hello*(): string ## Put documentation here proc nothing() = discard proc hello*(): string = ## ignore this echo "hello" + ``` The preferred documentation style is to begin with a capital letter and use the third-person singular. That is, between: -.. code-block:: nim - + ```nim proc hello*(): string = ## Returns "hello" result = "hello" + ``` or -.. code-block:: nim - + ```nim proc hello*(): string = ## say hello result = "hello" + ``` the first is preferred. @@ -296,8 +299,9 @@ in the postfix form for uniformity, that is after \`text in backticks\`. For example an ``:idx:`` role for referencing a topic ("SQLite" in the example below) from `Nim Index`_ can be used in doc comment this way: -.. code-block:: nim + ```nim ## A higher level `SQLite`:idx: database wrapper. + ``` .. _`Nim Index`: https://nim-lang.org/docs/theindex.html @@ -355,50 +359,50 @@ New `defined(foo)` symbols need to be prefixed by the nimble package name, or by `nim` for symbols in nim sources (e.g. compiler, standard library). This is to avoid name conflicts across packages. -.. code-block:: nim - + ```nim # if in nim sources when defined(allocStats): discard # bad, can cause conflicts when defined(nimAllocStats): discard # preferred # if in a package `cligen`: when defined(debug): discard # bad, can cause conflicts when defined(cligenDebug): discard # preferred + ``` .. _noimplicitbool: Take advantage of no implicit bool conversion -.. code-block:: nim - + ```nim doAssert isValid() == true doAssert isValid() # preferred + ``` .. _design_for_mcs: Design with method call syntax chaining in mind -.. code-block:: nim - + ```nim proc foo(cond: bool, lines: seq[string]) # bad proc foo(lines: seq[string], cond: bool) # preferred # can be called as: `getLines().foo(false)` + ``` .. _avoid_quit: Use exceptions (including `assert` / `doAssert`) instead of `quit` rationale: https://forum.nim-lang.org/t/4089 -.. code-block:: nim - + ```nim quit() # bad in almost all cases doAssert() # preferred + ``` .. _tests_use_doAssert: Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all tests so they'll be enabled even with `--assertions:off`:option:. -.. code-block:: nim - + ```nim block: # foo assert foo() # bad doAssert foo() # preferred + ``` .. _runnableExamples_use_assert: An exception to the above rule is `runnableExamples` and ``code-block`` rst blocks @@ -407,33 +411,33 @@ instead of `doAssert`. Note that `nim doc -d:danger main`:cmd: won't pass `-d:da `runnableExamples`, but `nim doc --doccmd:-d:danger main`:cmd: would, and so would the second example below: -.. code-block:: nim - + ```nim runnableExamples: doAssert foo() # bad assert foo() # preferred runnableExamples("-d:danger"): doAssert foo() # `assert` would be disabled here, so `doAssert` makes more sense + ``` .. _delegate_printing: Delegate printing to caller: return `string` instead of calling `echo` rationale: it's more flexible (e.g. allows the caller to call custom printing, including prepending location info, writing to log files, etc). -.. code-block:: nim - + ```nim proc foo() = echo "bar" # bad proc foo(): string = "bar" # preferred (usually) + ``` .. _use_Option: [Ongoing debate] Consider using Option instead of return bool + var argument, unless stack allocation is needed (e.g. for efficiency). -.. code-block:: nim - + ```nim proc foo(a: var Bar): bool proc foo(): Option[Bar] + ``` .. _use_doAssert_not_echo: Tests (including in testament) should always prefer assertions over `echo`, @@ -441,10 +445,10 @@ except when that's not possible. It's more precise, easier for readers and maintainers to where expected values refer to. See for example https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089 -.. code-block:: nim - + ```nim echo foo() # adds a line for testament in `output:` block inside `discard`. doAssert foo() == [1, 2] # preferred, except when not possible to do so. + ``` The `git`:cmd: stuff @@ -480,10 +484,10 @@ General commit rules Always check your changes for whitespace errors using `git diff --check`:cmd: or add the following ``pre-commit`` hook: - .. code:: cmd - - #!/bin/sh - git diff --check --cached || exit $? + ```cmd + #!/bin/sh + git diff --check --cached || exit $? + ``` 5. Describe your commit and use your common sense. Example commit message:: @@ -565,10 +569,10 @@ Code reviews doesn't help much as it doesn't highlight moves. Instead, you can use something like this, see visual results `here `_: - .. code:: cmd - - git fetch origin pull/10431/head && git checkout FETCH_HEAD - git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^ + ```cmd + git fetch origin pull/10431/head && git checkout FETCH_HEAD + git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^ + ``` 3. In addition, you can view GitHub-like diffs locally to identify what was changed within a code block using `diff-highlight`:cmd: or `diff-so-fancy`:cmd:, e.g.: diff --git a/doc/destructors.md b/doc/destructors.md index c98e94536a..612c479269 100644 --- a/doc/destructors.md +++ b/doc/destructors.md @@ -30,8 +30,7 @@ Motivating example With the language mechanisms described here, a custom seq could be written as: -.. code-block:: nim - + ```nim type myseq*[T] = object len, cap: int @@ -91,7 +90,7 @@ written as: for i in 0..`_ @@ -2186,7 +2186,7 @@ Unfortunately, `d + 12.Dollar` is not allowed either, because `+` is defined for `int` (among others), not for `Dollar`. So a `+` for dollars needs to be defined: - ``` + ```nim proc `+` (x, y: Dollar): Dollar = result = Dollar(int(x) + int(y)) ``` @@ -2194,7 +2194,7 @@ a `+` for dollars needs to be defined: It does not make sense to multiply a dollar with a dollar, but with a number without unit; and the same holds for division: - ``` + ```nim proc `*` (x: Dollar, y: int): Dollar = result = Dollar(int(x) * y) From 2f3980f491a7d94facff6e0f7d413818a86267a1 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 4 Aug 2022 06:15:22 -0300 Subject: [PATCH 26/33] Add bug form (#19913) * Add Bug Form * Add Bug Form * Add Bug Form * Add Bug Form * https://github.com/nim-lang/Nim/pull/19913#issuecomment-1160663243 * https://github.com/nim-lang/Nim/pull/19913#issuecomment-1160663243 * Update .github/ISSUE_TEMPLATE/bug_report.yml Co-authored-by: Yardanico * Update .github/ISSUE_TEMPLATE/bug_report.yml Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update .github/ISSUE_TEMPLATE/bug_report.yml Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update .github/ISSUE_TEMPLATE/bug_report.yml Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update .github/ISSUE_TEMPLATE/feature_request.yml Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update .github/ISSUE_TEMPLATE/feature_request.yml Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Do not Star Nim on Github * No backwards compat problems * Typo Co-authored-by: Yardanico Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.md | 53 ----- .github/ISSUE_TEMPLATE/bug_report.yml | 214 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 35 ---- .github/ISSUE_TEMPLATE/feature_request.yml | 73 +++++++ 4 files changed, 287 insertions(+), 88 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 807e50d35c..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: Bug report -about: Have you found an unexpected behavior? Use this template. -title: Think about the title, twice -labels: '' -assignees: '' - ---- - -(Consider writing a PR targetting devel branch after filing this, see [contributing.html](https://nim-lang.github.io/Nim/contributing.html)). - -Function `echo` outputs the wrong string. - -### Example -```nim -echo "Hello World!" -# This code should be a minimum reproducible example: -# try to simplify and minimize as much as possible. If it's a compiler -# issue, try to minimize further by removing any imports if possible. -``` - -### Current Output -please check whether the problem still exists in git head before posting, -see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler). -``` -Hola mundo! -``` - -### Expected Output -``` -Hello World! -``` - -### Possible Solution - -* In file xyz there is a call that might be the cause of it. - -### Additional Information -If it's a regression, you can help us by identifying which version introduced -the bug, see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions), -or at least try known past releases (eg `choosenim 1.2.0`). - -If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) -which should give more context on a compiler crash. - -* Issue #abc is related, but different because of ... -* This issue is blocking my project xyz - -``` -$ nim -v -Nim Compiler Version 0.1.2 -# make sure to include the git hash if not using a tagged release -``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..5b078131fc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,214 @@ +name: "Bug Report" +description: "Create a new bug report. Have you found an unexpected behavior? Use this form." +title: "Think about the title, twice." +labels: ["unconfirmed"] +body: + +- type: markdown + attributes: + value: | + - **Please provide a minimal code example that reproduces the Bug!** :bug: + Reports with a reproducible example and descriptive detailed information will likely receive fixes faster. + +- type: dropdown + id: architecture + attributes: + label: Architecture + description: What is your Hardware Architecture?. + options: + - x86_64 (Default) + - x86_32 (32Bit) + - ARM_64 (64Bit) + - ARM_32 (32Bit) + - AVR, Arduino, ESP32 + - RISC (RISC-V) + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: os + attributes: + label: Operating System + description: What is your Operating System?. + options: + - Linux + - Windows + - Mac OSX + - Android + - BSD + - FreeDOS + - ReactOS + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: disk + attributes: + label: Disk + description: What is your main Disk Storage?. + options: + - SSD (Solid, M2, MSATA, NVME) + - HDD (SATA, IDE, SCSI, Mechanical) + - USB (Flash, USB2, USB3) + - Diskless (Netboot, run from RAM) + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: ram + attributes: + label: Memory + description: What is your total RAM Memory capacity?. + options: + - 1 Gigabyte + - 2 Gigabytes + - 4 Gigabytes + - 8 Gigabytes + - 16 Gigabytes + - 32 Gigabytes + - 64 Gigabytes + - 128 Gigabytes + - 256 Gigabytes + - 512 Gigabytes + - Less than 1 Gigabyte + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: cores + attributes: + label: CPU Cores + description: What is your total CPU Cores count?. + options: + - 1 CPU Cores + - 2 CPU Cores + - 4 CPU Cores + - 8 CPU Cores + - 16 CPU Cores + - 32 CPU Cores + - 64 CPU Cores + - 128 CPU Cores + - 256 CPU Cores + - 512 CPU Cores + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: internet + attributes: + label: Internet Connection + description: What is your Internet connection?. + options: + - Optical Fiber (very fast) + - DSL (aDSL, DSL, etc) + - Wifi (WLAN, Wireless) + - LAN (RJ45, Local, etc) + - Satellite (StarLink, etc) + - Mobile (4G, 3G, Edge, etc) + - Offline (No Internet) + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: browser + attributes: + label: What is your web browser? + options: + - Chrome/Chromium + - Firefox/Firefox Fork + - Apple Safari + - Microsoft Edge + - KDE (Konqueror, Falkon, QtWebkit, etc) + - Microsoft Internet Explorer (Deprecated) + - Others (Unknown) + validations: + required: false + +- type: dropdown + id: device + attributes: + label: Device + description: What kind of computer is it?. + options: + - Desktop PC + - Server PC + - Mobile device (Smartphone, Smartwatch, Tablet) + - Docker/Qemu (Container) + - VirtualBox/Vagrant (Virtual Machine) + - Embedded/IOT + - Arduino Kit/ESP32 Kit + - Game Console (Playstation, XBOX, SteamDeck, Switch) + - SmartTV/SmartDisplay/Smartprojector + - Drone/Robot/Exoskeleton + - ASIC/FPGA/Crypto-mining hardware + - PLC/Industrial/heavy machine + - Point Of Sale/Kiosk/ATM + - Car/Self-Driving/On-Board Computer + - Electric scooter/Electric bike + - Satellite/MicroSatellite + - Military machine + - Others (Unknown) + validations: + required: false + +- type: textarea + id: what-happened + attributes: + label: What happened? + description: | + Use DETAILED DESCRIPTIVE information about the problem. + Here, you go into more details about your Bug report. This section can be a few paragraphs long. + placeholder: Bug reports with full repro code and detailed information will be fixed faster. + validations: + required: true + +- type: textarea + id: current-logs + attributes: + label: Current Standard Output Logs + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + placeholder: Bug reports with full repro code and detailed information will be fixed faster. + render: shell + +- type: textarea + id: expected-logs + attributes: + label: Expected Standard Output Logs + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + placeholder: Bug reports with full repro code and detailed information will be fixed faster. + render: shell + +- type: textarea + id: possible-solution + attributes: + label: Possible Solution + description: Propose a possible solution. + validations: + required: false + +- type: textarea + id: extra-info + attributes: + label: Additional Information + description: Any additional relevant information. + validations: + required: false + +- type: markdown + attributes: + value: | + - Thanks for your contributions!, your Bug report will receive feedback from the community soon... + - Please check whether the problem still exists in the devel branch, see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler). + - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). + - If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) + which should give more context on a compiler crash. + - If it's a regression, you can help us by identifying which version introduced the bug, + see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions), + or at least try known past releases (eg `choosenim 1.2.0`). + - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 6a9afe0713..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Feature request -about: Do you want to suggest a new feature? Use this template. -title: '' -labels: ["Feature"] -assignees: '' - ---- - - - - -### Summary - - - -### Description - - - -### Alternatives - - - -### Additional Information - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000..55b4836fd3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,73 @@ +name: "Feature request" +description: "Create a new Feature Request. Do you want to suggest a new feature? Use this form." +title: "Think about the title, twice." +labels: ["unconfirmed"] +body: + +- type: markdown + attributes: + value: | + - Please provide a minimal code example that illustrates the basic idea behind your feature request. + Reports with full repro code and descriptive detailed information will likely receive feedback faster. + - There is a separate repository for the detailed RFCs and proposals: https://github.com/nim-lang/RFCs. + If you have a simple feature request, you can post it here using this form, + but bear in mind that adding new features to the language is currently a low priority. + +- type: textarea + id: summary + attributes: + label: Summary + description: | + Use DETAILED DESCRIPTIVE information about the feature request. + Here, you go into more details about your ideas. This section can be a few paragraphs long. + placeholder: Short summary of your proposed feature. + validations: + required: true + +- type: textarea + id: description + attributes: + label: Description + description: Describe your solution, what problem does it fix? + validations: + required: true + +- type: textarea + id: alternatives + attributes: + label: Alternatives + description: Are there any alternatives you've considered? + validations: + required: false + +- type: textarea + id: Examples + attributes: + label: Standard Output Examples + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + placeholder: Example code here. + render: shell + +- type: textarea + id: incompatibility + attributes: + label: Backwards Compatibility + description: If your Feature Request introduces backward-incompatible changes, describe them and propose how to deal with them. + validations: + required: false + +- type: textarea + id: links + attributes: + label: Links + description: Please copy and paste any relevant links to projects, issues, discussions, technical documentations, code samples, etc. + validations: + required: false + +- type: markdown + attributes: + value: | + - Thanks for your contributions!, your ideas will receive feedback from the community soon... + - **Remember to :star: Star the Nim project on GitHub!.** + - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). + - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) From 0641df33aabe25d0c83b00a334cc157a8ca50607 Mon Sep 17 00:00:00 2001 From: Sojin <77185816+SojinSamuel@users.noreply.github.com> Date: Thu, 4 Aug 2022 22:23:42 +0530 Subject: [PATCH 27/33] Two broken links found (#20121) Updated the two broken internal links: rebuilding the compiler, reproducible builds --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 39ddca17a6..8f5d278b55 100644 --- a/readme.md +++ b/readme.md @@ -88,9 +88,9 @@ Next, run the appropriate build shell script for your platform: Finally, once you have finished the build steps (on Windows, Mac, or Linux) you should add the ``bin`` directory to your PATH. -See also [rebuilding the compiler](doc/intern.rst#rebuilding-the-compiler). +See also [rebuilding the compiler](doc/intern.md#rebuilding-the-compiler). -See also [reproducible builds](doc/intern.rst#reproducible-builds). +See also [reproducible builds](doc/intern.md#reproducible-builds). ## Koch From 714eb658666de5b28ee3116a150bc0e59634dfc9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 5 Aug 2022 02:56:08 +0800 Subject: [PATCH 28/33] remove annoying dropdowns from the bug form (#20154) * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 155 ++------------------------ 1 file changed, 8 insertions(+), 147 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 5b078131fc..30b3d33510 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,153 +10,6 @@ body: - **Please provide a minimal code example that reproduces the Bug!** :bug: Reports with a reproducible example and descriptive detailed information will likely receive fixes faster. -- type: dropdown - id: architecture - attributes: - label: Architecture - description: What is your Hardware Architecture?. - options: - - x86_64 (Default) - - x86_32 (32Bit) - - ARM_64 (64Bit) - - ARM_32 (32Bit) - - AVR, Arduino, ESP32 - - RISC (RISC-V) - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: os - attributes: - label: Operating System - description: What is your Operating System?. - options: - - Linux - - Windows - - Mac OSX - - Android - - BSD - - FreeDOS - - ReactOS - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: disk - attributes: - label: Disk - description: What is your main Disk Storage?. - options: - - SSD (Solid, M2, MSATA, NVME) - - HDD (SATA, IDE, SCSI, Mechanical) - - USB (Flash, USB2, USB3) - - Diskless (Netboot, run from RAM) - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: ram - attributes: - label: Memory - description: What is your total RAM Memory capacity?. - options: - - 1 Gigabyte - - 2 Gigabytes - - 4 Gigabytes - - 8 Gigabytes - - 16 Gigabytes - - 32 Gigabytes - - 64 Gigabytes - - 128 Gigabytes - - 256 Gigabytes - - 512 Gigabytes - - Less than 1 Gigabyte - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: cores - attributes: - label: CPU Cores - description: What is your total CPU Cores count?. - options: - - 1 CPU Cores - - 2 CPU Cores - - 4 CPU Cores - - 8 CPU Cores - - 16 CPU Cores - - 32 CPU Cores - - 64 CPU Cores - - 128 CPU Cores - - 256 CPU Cores - - 512 CPU Cores - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: internet - attributes: - label: Internet Connection - description: What is your Internet connection?. - options: - - Optical Fiber (very fast) - - DSL (aDSL, DSL, etc) - - Wifi (WLAN, Wireless) - - LAN (RJ45, Local, etc) - - Satellite (StarLink, etc) - - Mobile (4G, 3G, Edge, etc) - - Offline (No Internet) - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: browser - attributes: - label: What is your web browser? - options: - - Chrome/Chromium - - Firefox/Firefox Fork - - Apple Safari - - Microsoft Edge - - KDE (Konqueror, Falkon, QtWebkit, etc) - - Microsoft Internet Explorer (Deprecated) - - Others (Unknown) - validations: - required: false - -- type: dropdown - id: device - attributes: - label: Device - description: What kind of computer is it?. - options: - - Desktop PC - - Server PC - - Mobile device (Smartphone, Smartwatch, Tablet) - - Docker/Qemu (Container) - - VirtualBox/Vagrant (Virtual Machine) - - Embedded/IOT - - Arduino Kit/ESP32 Kit - - Game Console (Playstation, XBOX, SteamDeck, Switch) - - SmartTV/SmartDisplay/Smartprojector - - Drone/Robot/Exoskeleton - - ASIC/FPGA/Crypto-mining hardware - - PLC/Industrial/heavy machine - - Point Of Sale/Kiosk/ATM - - Car/Self-Driving/On-Board Computer - - Electric scooter/Electric bike - - Satellite/MicroSatellite - - Military machine - - Others (Unknown) - validations: - required: false - - type: textarea id: what-happened attributes: @@ -167,6 +20,14 @@ body: placeholder: Bug reports with full repro code and detailed information will be fixed faster. validations: required: true + +- type: textarea + id: nim-version + attributes: + label: Nim Version + description: Please run `nim -v` on the command line. + validations: + required: true - type: textarea id: current-logs From 3fef2fd52c86ba922187ca03026b09ceb70b5d3d Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Fri, 5 Aug 2022 19:44:21 +0200 Subject: [PATCH 29/33] Improve error message for `strutils.addf` (#20157) Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/pure/strutils.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0585b64804..3b315e564a 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2698,8 +2698,8 @@ func findNormalized(x: string, inArray: openArray[string]): int = # security hole... return -1 -func invalidFormatString() {.noinline.} = - raise newException(ValueError, "invalid format string") +func invalidFormatString(formatstr: string) {.noinline.} = + raise newException(ValueError, "invalid format string: " & formatstr) func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, extern: "nsuAddf".} = @@ -2711,7 +2711,7 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, if formatstr[i] == '$' and i+1 < len(formatstr): case formatstr[i+1] of '#': - if num > a.high: invalidFormatString() + if num > a.high: invalidFormatString(formatstr) add s, a[num] inc i, 2 inc num @@ -2727,7 +2727,7 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, j = j * 10 + ord(formatstr[i]) - ord('0') inc(i) let idx = if not negative: j-1 else: a.len-j - if idx < 0 or idx > a.high: invalidFormatString() + if idx < 0 or idx > a.high: invalidFormatString(formatstr) add s, a[idx] of '{': var j = i+2 @@ -2744,22 +2744,22 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, inc(j) if isNumber == 1: let idx = if not negative: k-1 else: a.len-k - if idx < 0 or idx > a.high: invalidFormatString() + if idx < 0 or idx > a.high: invalidFormatString(formatstr) add s, a[idx] else: var x = findNormalized(substr(formatstr, i+2, j-1), a) if x >= 0 and x < high(a): add s, a[x+1] - else: invalidFormatString() + else: invalidFormatString(formatstr) i = j+1 of 'a'..'z', 'A'..'Z', '\128'..'\255', '_': var j = i+1 while j < formatstr.len and formatstr[j] in PatternChars: inc(j) var x = findNormalized(substr(formatstr, i+1, j-1), a) if x >= 0 and x < high(a): add s, a[x+1] - else: invalidFormatString() + else: invalidFormatString(formatstr) i = j else: - invalidFormatString() + invalidFormatString(formatstr) else: add s, formatstr[i] inc(i) From 3bd935f33139646431957e3e14d4ce252a9f60c6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 6 Aug 2022 05:15:58 +0800 Subject: [PATCH 30/33] fixes #20153; do not escape `_` for mysql [backport] (#20164) * fixes #20153; do not escape `_` for mysql * add a test * Update db_mysql.nim * Update tdb_mysql.nim Co-authored-by: Clay Sweetser --- lib/impure/db_mysql.nim | 3 +-- tests/stdlib/tdb_mysql.nim | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 tests/stdlib/tdb_mysql.nim diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index df878e25af..562847e6b0 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -117,7 +117,7 @@ when false: discard mysql_stmt_close(stmt) proc dbQuote*(s: string): string = - ## DB quotes the string. + ## DB quotes the string. Note that this doesn't escape `%` and `_`. result = newStringOfCap(s.len + 2) result.add "'" for c in items(s): @@ -132,7 +132,6 @@ proc dbQuote*(s: string): string = of '"': result.add "\\\"" of '\'': result.add "\\'" of '\\': result.add "\\\\" - of '_': result.add "\\_" else: result.add c add(result, '\'') diff --git a/tests/stdlib/tdb_mysql.nim b/tests/stdlib/tdb_mysql.nim new file mode 100644 index 0000000000..21a7afd4f0 --- /dev/null +++ b/tests/stdlib/tdb_mysql.nim @@ -0,0 +1,4 @@ +import std/db_mysql + +doAssert dbQuote("SELECT * FROM foo WHERE col1 = 'bar_baz'") == "'SELECT * FROM foo WHERE col1 = \\'bar_baz\\''" +doAssert dbQuote("SELECT * FROM foo WHERE col1 LIKE '%bar_baz%'") == "'SELECT * FROM foo WHERE col1 LIKE \\'%bar_baz%\\''" From fd6640fcda29bf56c7a5079c4a9bf286eee6615c Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 Aug 2022 23:50:26 +0800 Subject: [PATCH 31/33] [minor] don't find `"Hint: gc"` for action (#20170) --- ci/action.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ci/action.nim b/ci/action.nim index 8c32600961..5d3a50fda2 100644 --- a/ci/action.nim +++ b/ci/action.nim @@ -9,9 +9,7 @@ proc main() = doAssert exitCode == 0, output - var start = rfind(output, "Hint: gc") - if start < 0: - start = rfind(output, "Hint: mm") + let start = rfind(output, "Hint: mm") doAssert parseUntil(output, msg, "; proj", start) > 0, output let (commitHash, _) = execCmdEx("""git log --format="%H" -n 1""") @@ -25,4 +23,4 @@ The lines below are statistics of the Nim compiler built from {commitHash} writeFile "ci/nimcache/results.txt", welcomeMessage when isMainModule: - main() \ No newline at end of file + main() From 4f4501abbc3f59c52e978f02b115d2bb45869566 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 Aug 2022 23:50:55 +0800 Subject: [PATCH 32/33] fixes links in the readme (#20167) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 8f5d278b55..fef139bced 100644 --- a/readme.md +++ b/readme.md @@ -88,9 +88,9 @@ Next, run the appropriate build shell script for your platform: Finally, once you have finished the build steps (on Windows, Mac, or Linux) you should add the ``bin`` directory to your PATH. -See also [rebuilding the compiler](doc/intern.md#rebuilding-the-compiler). +See also [bootstrapping the compiler](https://nim-lang.github.io/Nim/intern.html#bootstrapping-the-compiler). -See also [reproducible builds](doc/intern.md#reproducible-builds). +See also [reproducible builds](https://nim-lang.github.io/Nim/intern.html#bootstrapping-the-compiler-reproducible-builds). ## Koch From 80a0dc295bab6d7699c0da13b6bc90f7243572e4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 8 Aug 2022 16:56:37 +0800 Subject: [PATCH 33/33] update the docs of arc following up #19749 (#19752) Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- lib/system/arc.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 17142b2770..ccf9d44e27 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -28,8 +28,8 @@ ObjectA's ``name`` is "|ObjectA|RootObj|". ObjectB's ``name`` is "|ObjectB|ObjectA|RootObj|". Now to check for ``x of ObjectB`` we need to check -for ``x.typ.name.hasSubstring("|ObjectB|")``. In the actual implementation, -however, we could also use a +for ``x.typ.name.endsWith("|ObjectB|ObjectA|RootObj|")``. +In the actual implementation, however, we could also use a hash of ``package & "." & module & "." & name`` to save space. ]#