Compare commits

..

203 Commits

Author SHA1 Message Date
ringabout
6c34f62785 fixes #24666; Compilation error when formatting a complex number (#24667)
fixes #24666

ref https://github.com/nim-lang/Nim/pull/22924

(cherry picked from commit 485b414fce)
2025-02-05 21:04:43 +01:00
narimiran
46e1322d29 bump NimVersion to 2.2.2 2025-02-04 20:03:53 +01:00
ringabout
27b54fdc76 fixes #24658; cpp compilation failure on Nim 2.2.x (#24663)
fixes #24658

(cherry picked from commit 7695d51fc4)
2025-02-04 20:03:39 +01:00
lit
d594e70d57 doc(tempfiles): update link of getTempDir (#24661)
- tempfiles: update `getTempDir` link... from os.html to appdirs.html
<https://nim-lang.org/docs/appdirs.html#getTempDir>

- ~~nims.md: rm three `std/`, which are out of place~~ (ref
https://github.com/nim-lang/Nim/pull/24661#discussion_r1937293833)

(cherry picked from commit e2bed72b72)
2025-02-04 20:03:30 +01:00
metagn
6bf9265d24 add ambiguous identifier message to generic instantiations (#24646)
fixes #24644

Another option is to include the symbol names and owners in the type
listing as in #24645 but this is a bit verbose.

(cherry picked from commit 0861dabfa7)
2025-01-31 09:37:46 +01:00
metagn
a627c9ba9c don't mark captured field sym in template as fully used (#24660)
fixes #24657

(cherry picked from commit 647c6687f1)
2025-01-31 09:37:31 +01:00
lit
7cec03eb1b fix doc format: testament.md (#24654)
- **doc(format): testament: fix `Commands` not regarded as table**

![image](https://github.com/user-attachments/assets/85238dd5-e199-41ca-a8cb-05849415097a)

- **doc(format): testament: row `--target` not splited as columns**

![image](https://github.com/user-attachments/assets/230ec693-c459-4fee-bc57-f3ab6c34a9b6)

(cherry picked from commit af5fd3fea3)
2025-01-31 09:37:26 +01:00
Peter Munch-Ellingsen
123a7ff29f Fix check for Nintendo Switch target (#24652)
This should fix ringabouts comment here:
https://github.com/nim-lang/Nim/pull/24639#issuecomment-2615107496

I wasn't aware that `nintendoswitch` and `posix` would be active at the
same time, so I falsely inverted a check.

(cherry picked from commit cab3342a2d)
2025-01-27 16:58:20 +01:00
Leon Lysak
c0d50ddc26 Update dom.nim (removeEventListener function) (#24650)
Essentially just an update for the `removeEventListener` function as per
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener

(cherry picked from commit 8c3e62e6de)
2025-01-27 08:50:13 +01:00
Tomohiro
2193c3fb70 Fix parseBiggestUInt to detect overflow (#24649)
With some inputs larger than `BiggestUInt.high`, `parseBiggestUInt` proc
in `parseutils.nim` fails to detect overflow and returns random value.
This is because `rawParseUInt` try to detects overflow with `if prev >
res:` but it doesn't detects the overflow from multiplication.
It is possible that `x *= 10` causes overflow and resulting value is
larger than original value.
Here is example values larger than `BiggestUInt.high` but
`parseBiggestUInt` returns without detecting overflow:
```
22751622367522324480000000
41404969074137497600000000
20701551093035827200000000000000000
22546225502460313600000000000000000
204963831854661632000000000000000000
```

Following code search for values larger than `BiggestUInt.high` and
`parseBiggestUInt` cannot detect overflow:
```nim
import std/[strutils]

const
  # Increase this to extend search range
  NBits = 34'u
  NBitsMax1 = 1'u shl NBits
  NBitsMax = NBitsMax1 - 1'u

  # Increase this when there are too many results and want to see only larger result.
  MinMultiply10 = 14

var nfound = 0
for i in (NBitsMax div 10'u + 1'u) .. NBitsMax:
  var
    x = i
    n10 = 0
  for j in 0 ..< NBits:
    let px = x
    x = (x * 10'u) and NBitsMax
    if x < px:
      break
    inc n10
  if n10 >= MinMultiply10:
    echo "i =   ", i
    echo "uint: ", (i shl (64'u - NBits)), '0'.repeat n10
    inc nfound
    if nfound > 15:
      break

echo "found: ", nfound
```

(cherry picked from commit 95b1dda1db)
2025-01-27 08:50:04 +01:00
Peter Munch-Ellingsen
c2b825713c Enable macros to use certain things from the OS module when the target OS is not supported (#24639)
Essentially this PR removes the `{.error.}` pragmas littered around in
the OS module and submodules which prevents them from being imported if
the target OS is not supported. This made it impossible to use certain
supported features of the OS module in macros from a supported host OS.
Instead of the `{.error.}` pragmas the `oscommon` module now has a
constant `supportedSystem` which is false in the cases where the
`{.error.}` pragmas where generated. All procedures which can't be run
by macros is also not declared when `supportedSystem` is false.

It would be possible to create dummy versions of the omitted functions
with an `{.error.}` pragma that would trigger upon their use, but this
is currently not done.

This properly fixes #19414

(cherry picked from commit 1f9cac1f5c)
2025-01-27 08:49:58 +01:00
ringabout
ae011eaeea fixes #21923; nimsuggest "outline" output does not list templates (#24643)
fixes #21923

---------

Co-authored-by: Louis Berube <louis.p.berube@gmail.com>
(cherry picked from commit 67f9bc2f4b)
2025-01-27 08:49:33 +01:00
ringabout
8fe518ed47 fixes #24623; fixes #23692; size pragma only allowed for imported types and enum types (#24640)
fixes #24623
fixes #23692

ref
https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-size-pragma

confines `size` pragma to `enums` and imported `objects` for now

The `typeDefLeftSidePass` carries out the check for pragmas, but the
type is not complete yet. So the `size` pragma checking is postponed at
the final pass.

(cherry picked from commit d6d28a9c79)
2025-01-24 05:10:42 +01:00
metagn
64927c6ae7 don't try to transform objconstr/cast type nodes (#24636)
fixes #24631

[Object
constructors](793baf34ff/compiler/semobjconstr.nim (L462)),
[casts](793baf34ff/compiler/semexprs.nim (L494))
and [type
conversions](793baf34ff/compiler/semexprs.nim (L419))
copy their type nodes verbatim instead of producing semchecked type
nodes. This causes a crash in transf when an untyped expression in the
type node has `nil` type. To deal with this, don't try to transform the
type node in these expressions at all. I couldn't reproduce the problem
with type conversion nodes though so those are unchanged in transf.

(cherry picked from commit 6d59680217)
2025-01-24 05:10:36 +01:00
ringabout
21c0564573 fixes #24630; static openArray backed by seq cannot be passed to another function (#24638)
fixes #24630

(cherry picked from commit 2f402fcb82)
2025-01-24 05:10:28 +01:00
metagn
12347eae74 generate destructor in nodestroy proc for explicit destructor call (#24627)
fixes #24626

`createTypeboundOps` in sempass2 is called when generating destructors
for types including for explicit destructor calls, however it blocks
destructors from getting generated in a `nodestroy` proc. This causes
issues when a destructor is explicitly called in a `nodestroy` proc. To
fix this, allow destructors to get generated only for explicit
destructor calls in nodestroy procs.

(cherry picked from commit 793baf34ff)
2025-01-20 18:46:41 +01:00
Antonis Geralis
52cadfc3d7 Optimize storing into uninit locations for arrays and seqs. (#24619)
(cherry picked from commit 6481482e0e)
2025-01-20 12:48:37 +01:00
ringabout
528e2b2271 fixes compile crashes with one parameter (#24618)
`{.compile("foo.c").}` makes Nim compiler crash

(cherry picked from commit 70d057fcc6)
2025-01-20 12:48:17 +01:00
metagn
0c0df28619 ignore match errors to expected types of tuple constructor elements (#24611)
fixes #24609

A tuple may have an incompatible expected type if there is a converter
match to it. So the compiler should not error when trying to match the
individual elements in the constructor to the elements of the expected
tuple type, this will be checked when the tuple is entirely constructed
anyway.

(cherry picked from commit 8d0e853e0a)
2025-01-20 12:48:10 +01:00
ringabout
a2a1c2b7f1 ci: update to ubuntu 22.04 (#24608)
(cherry picked from commit 41c447b5f4)
2025-01-15 15:31:59 +01:00
Bilog WEB3
41c4ed8dca Update changelog_1_2_0.md (#24607)
(cherry picked from commit 26ed469996)
2025-01-15 15:31:45 +01:00
Loïc Bartoletti
f6167cb0c8 math: Add cumprod and cumproded (#23416)
This pull request adds the `cumproded` function along with its in-place
equivalent, `cumprod`, to the math library. These functions provide
functionality similar to `cumsum` and `cumsummed`, allowing users to
calculate the cumulative sum of elements.

The `cumprod` function computes the cumulative product of elements
in-place, while `cumproded` additionally returns the prod seq.

(cherry picked from commit 4aff12408c)
2025-01-15 15:31:25 +01:00
planetBoy
72ce16990b docs fix spelling issues (#24597)
Hey !
I fixed several spelling issues.Glad I could help .
Br, Guayaba221.

(cherry picked from commit 8ed0a63973)
2025-01-15 15:31:20 +01:00
ringabout
ea3a4203fa fixes #24599; misleading error message with large array bounds (#24601)
fixes #24599

(cherry picked from commit aeeccee50a)
2025-01-15 15:31:13 +01:00
Jacek Sieka
24b24c17b1 fix c_memchr, c_strstr definitions (#24587)
One correct definition is enough

(cherry picked from commit e8bf6af0da)
2025-01-15 15:31:04 +01:00
Jacek Sieka
e80884665d varints: no need for emit (#24585)
(cherry picked from commit 78835562b1)
2025-01-15 15:30:58 +01:00
ringabout
f4009f0957 Update copyright year 2025 (#24593)
(cherry picked from commit 3dda60a8ce)
2025-01-15 10:22:25 +01:00
Skylar Ray
728a99d5cd chore: docs fix spelling issues (#24581)
**handle - handles**
**sensitiviy - sensitivity**

(cherry picked from commit dcc4e07e54)
2025-01-15 10:22:18 +01:00
futreall
019a3180f8 chore: correct typos docs (#24580)
(cherry picked from commit 0df351bf50)
2025-01-15 10:22:07 +01:00
Antonis Geralis
fb13e3608b Consider iterator types (#24577)
According to the macros doc nnkIteratorTy trees use the same structure
as nnkProcTy

(cherry picked from commit d3b6dba616)
2025-01-15 10:21:53 +01:00
Antonis Geralis
f5804a36b9 Support tuple parameter types (#24576)
(cherry picked from commit e1be29942e)
2025-01-15 10:21:37 +01:00
chloefeal
a83c535ed4 docs: fix typos (#24573)
Signed-off-by: chloefeal <188809157+chloefeal@users.noreply.github.com>
(cherry picked from commit cd220fe3e1)
2025-01-15 10:21:20 +01:00
Jake Leahy
3c71429eca Doc search improvements (#24567)
- `/` is now a hotkey to jump to the search
- Search results now are in line with the page (previously on small
screens it would be off centre)
- Jumping to a search result inside the page or via TOC will now hide
the search results (previously the results got in the way)

Example site here: https://tranquil-scone-c159b6.netlify.app/main.html

(cherry picked from commit 86d6f71f5a)
2025-01-15 10:21:11 +01:00
Jake Leahy
9e1b199e78 Minor std/strscans improvements (#24566)
#### Removes UnInit warnings when using `scanTuple`

e.g. this would emit a warning
```nim
import std/strscans

proc main() =
  let (ok, number) = "123".scanTuple()
```

![image](https://github.com/user-attachments/assets/68170ac6-402d-48b0-b8b6-69e71f4b70ae)

#### Error for wrong type now points to the passed in variable

```nim
import std/strscans

var str: string
discard "123".scanf("$i", str)
```

it gave this warning before

![image](https://github.com/user-attachments/assets/096e56d2-0eb5-4c67-9725-25caa97afebd)
now it returns

![image](https://github.com/user-attachments/assets/736a4292-2f56-4cf3-a27a-677045377171)

(cherry picked from commit 5b9ff963c5)
2025-01-15 10:21:00 +01:00
ringabout
b2f2b34fe5 adds a test case (#24565)
closes #19531

(cherry picked from commit 65b26401bc)
2025-01-15 10:20:50 +01:00
Esteban C Borsani
7be1bb572e Improve async stacktraces (#24563)
This makes await point to the caller line instead of asyncmacro. It also
reworks the "Async traceback:" section of the traceback. Follow up PR
#21091 (issue #19931) so it works if there is asynchronous work done.

(cherry picked from commit 2f127bf99f)
2025-01-15 10:20:29 +01:00
ringabout
40476fa24f fixes #23114; Nim v2 regression emit / asm var param dereference inconsistency (#24547)
fixes #23114

As in https://github.com/nim-lang/Nim/pull/22074, expressions in
bracketed emit are strictly typechecked, this PR applies the same check
for symbols in asm statements in order to keep them consistent.

(cherry picked from commit 3c4246dd24)
2025-01-15 10:20:18 +01:00
Tomohiro
3054cbe422 Add inline assembler tests for i386, arm, arm64, riscv32 and riscv64 (#24564)
This fixes one error in https://github.com/nim-lang/Nim/issues/24544 .
I tested this on Raspberry Pi Pico (arm) and Raspberry Pi 3(arm64).
It is not tested on i386, riscv32 and riscv64 CPU.

(cherry picked from commit fc806710cb)
2025-01-15 10:20:08 +01:00
ringabout
b31aed01f1 adds a test case (#24561)
closes #18616

(cherry picked from commit e2a306355c)
2025-01-15 10:19:57 +01:00
metagn
9c7f04dacb fix jsonutils with generic sandwiches, don't use strformat (#24560)
fixes #24559

The strformat macros have the problem that they don't capture symbols,
so don't use them in the generic `fromJson` proc here. Also `fromJson`
refers to `jsonTo` before it is declared which doesn't capture it, so
it's now forward declared.

(cherry picked from commit 5c71fbab30)
2025-01-15 10:19:51 +01:00
Jake Leahy
c5ee216c42 Make 'field is not accessible' and 'field initialized twice' errors point to the field inside the obj construction (#24557)
Fixes two line infos to make the error's clearer inside editors

- 'field is not accessible' would point to the whole object construction
instead of just the field inside the construction
- 'field initialized twice' would point to the colon instead of the
field

(cherry picked from commit 6bc52737b3)
2025-01-15 10:19:40 +01:00
Esteban C Borsani
ede6540c55 fixes #23212; Asyncdispatch leaks under --mm:arc (#24556)
Fixes #23212

Inspired by [this chronos
PR](https://github.com/status-im/nim-chronos/pull/243)

(cherry picked from commit f29234b40f)
2025-01-15 10:19:26 +01:00
ringabout
0c14372a8c remove zippy data from tarballs (#24551)
fixes https://github.com/nim-lang/nightlies/issues/95

(cherry picked from commit 63c884038d)
2025-01-15 10:19:04 +01:00
metagn
6deb3a90ae check if unused import warning is enabled before adding import to stack (#24554)
fixes #24552

Could also implement `{.used.}` for imports but this wouldn't be
backwards compatible. The same problem as #24552 also exists for
`{.hint[XDeclaredButNotUsed].}` but this isn't as much of a problem
since `{.used.}`/`{.push used.}` exist.

(cherry picked from commit 986ca7dcd4)
2025-01-15 10:18:58 +01:00
Daniel Stuart
e0e1061562 Use long int builtins for risc-v 32-bit targets (#24553)
Solves compilation using riscv32-unknown-elf-gcc, compiler defines
int32_t as long int.

(cherry picked from commit 50ed43df42)
2025-01-15 10:18:00 +01:00
ringabout
d96c5b2396 fixes strictdefs warnings (#24550)
(cherry picked from commit ce4304ce97)
2025-01-15 10:17:51 +01:00
Jake Leahy
09835a1d9e Make expandMacro show private fields (#24522)
Was debugging with `--expandMacro` and noticed that private fields
weren't exported.
Passes extra flags to the renderer to make them be shown

(cherry picked from commit f80ce139d5)
2025-01-15 10:17:43 +01:00
ringabout
0823b9d177 fixes #17681; enforce codegen for exportc consts (#24546)
fixes #17681

(cherry picked from commit d5c7abe3d2)
2025-01-15 10:17:37 +01:00
Juan M Gómez
b5068f427a Adds skipParentCfg back. Bump nimble to a commit where it doesnt rely in the parent config (#24545)
(cherry picked from commit 8ce58fab26)
2025-01-15 10:17:27 +01:00
ringabout
1cee3c7f18 fixes #24536; fixes nightlies regression caused by nimble update (#24542)
follow up #24537

Because `nimble` is a bundled repo so it is bundled in the tarballs

i.e.
82421fd705/.github/workflows/nightlies.yml (L264)
has bundled `dist/nimble`, but it only copies the data without `.git`.
So in this PR, we ignore bundled nimble repo.

(cherry picked from commit 70b3232d3a)
2025-01-15 10:17:17 +01:00
ringabout
844ba2168b fixes #20908; Unknown warnings and hints now give a warning (#24543)
fixes #20908

This PR unifies the treatment of unknown warnings and hints, which now
gives an `warnUnknownNotes` instead of an error.

(cherry picked from commit 81d8c0fc17)
2025-01-15 10:17:07 +01:00
ringabout
d5437b7a4a fixes #24538 (#24541)
fixes #24538

(cherry picked from commit 91d1933ea2)
2025-01-15 10:16:20 +01:00
metagn
faa9ae08b0 proper error for const defines with unsupported types (#24540)
fixes #24539

(cherry picked from commit b9c593404c)
2025-01-15 10:16:12 +01:00
Juan M Gómez
7b596b4e1f #Fixes #24536 building nimble 0.16.4 fails when running build_all.sh (#24537)
(cherry picked from commit 556f217b4c)
2025-01-14 13:24:21 +01:00
ringabout
cd06f0769f more strictdef fixes for stdlibs (#24535)
(cherry picked from commit d31cce557b)
2025-01-14 13:23:44 +01:00
Juan M Gómez
0cce145dac Bumps nimble v0.16.4 (#24437)
(cherry picked from commit be4d19e562)
2025-01-14 13:23:38 +01:00
Ryan McConnell
43f7e160ba couple cases of valid concept bindings (#24513)
see tests

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit e0197a8380)
2025-01-14 13:23:26 +01:00
ringabout
5a71c36d25 fixes strictdefs warnings continue (#24520)
(cherry picked from commit d2d810585c)
2025-01-14 13:23:18 +01:00
ringabout
1299dd4651 adds a test case (#24534)
closes #16845

(cherry picked from commit 80af252025)
2025-01-14 13:23:12 +01:00
bptato
51a0f3de6e Fix exitnow signature, mark as .noreturn (#24533)
Like quit, this function never returns.

Also, "code" was marked as "int", even though POSIX _exit takes a C int.

(cherry picked from commit f485973459)
2025-01-14 13:23:06 +01:00
ringabout
e2b6021630 fixes #22101; std/pegs with nim cpp --mm:orc --exceptions:goto creates invalid C++ (#24531)
fixes #22101

The old implementation generates

`auto T = value;` for the cpp backend which causes problems for goto
exceptions. This PR puts the declaration of `T` to the cpsLocals parts
and makes it compatible with goto exceptions.

(cherry picked from commit f7a461a30c)
2025-01-14 13:22:32 +01:00
ringabout
428b64251f adds a test case (#24532)
closes #18070

(cherry picked from commit f796c01e3c)
2025-01-14 13:20:04 +01:00
ringabout
5b0b90fb49 fixes #22153; UB calling allocCStringArray([""]) with --mm:refc (#24529)
fixes #22153

It's a problem for refc because you cannot index a nil string: i.e.
`[""]` is `{((NimStringDesc*) NIM_NIL)}` which cannot be indexed

(cherry picked from commit 9bb7e53e7f)
2025-01-14 13:19:56 +01:00
Jake Leahy
2f5481ce88 Make error appear in user code with invalid format string in strformat (#24528)
With this example
```nim
import std/strformat

echo fmt"{invalid, code}"
```

We get the error message
```
stack trace: (most recent call last)
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(750, 16) fmt
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(714, 16) strformatImpl
/home/jake/Documents/projects/Nim/temp.nim(3, 9) template/generic instantiation of `fmt` from here
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(714, 16) Error: could not parse `invalid, code` in `{invalid, code}`.
(1, 8) Error: invalid indentation
```
After PR it now shortens it to just appear in user code
```
/home/jake/Documents/projects/Nim/lib/pure/strformat.nim(750, 16) fmt
/home/jake/Documents/projects/Nim/lib/pure/strformat.nim(714, 16) strformatImpl
/home/jake/Documents/projects/Nim/temp.nim(3, 9) Error: could not parse `invalid, code` in `{invalid, code}`.
(1, 8) Error: invalid indentation
```

(cherry picked from commit da9f7f671b)
2025-01-14 13:19:50 +01:00
Jake Leahy
9aeb5c254c Fix line info for import (#24523)
Refs #24158

Fixes the line info of the module symbol (cases like `import as` and
grouped imports had wrong line info). Since that symbol's line info is
now used for the warnings, there isn't a separate line info stored for
`unusedImports`

Examples of fixed cases
```nim
import strutils as test #[
                ^ before
                   ^ after ]#

# This case was fixed by #24158, but only for unused imports
import std/[strutils, strutils] #[
        ^ before
                      ^ after ]#

from strutils import split #[
^ before
     ^ after ]#
```

(cherry picked from commit 69e0cdb6c0)
2025-01-14 13:17:34 +01:00
metagn
4e1bc4216a fix nil node in sym ast of exported ref objects [backport:2.2] (#24527)
fixes #24526, follows up #23101

The `shallowCopy` calls do not keep the original node's children, they
just make a new seq with the same length, so the `Ident "*"` node from
the original postfix nodes was not carried over, making it `nil` and
causing the segfault.

(cherry picked from commit b529f69518)
2025-01-14 13:17:24 +01:00
metagn
316141162b test case haul to prevent pileup (#24525)
closes #6013, closes #7009, closes #9190, closes #12487, closes #12831,
closes #13184, closes #13252, closes #14860, closes #14877, closes
#14894, closes #14917, closes #16153, closes #16439, closes #17779,
closes #18074, closes #18202, closes #18314, closes #18648, closes
#19063, closes #19446, closes #20065, closes #20367, closes #22126,
closes #22820, closes #22888, closes #23020, closes #23287, closes
#23510

(cherry picked from commit aeb3fe9505)
2025-01-14 13:17:11 +01:00
ringabout
8d8a90e079 fixes nightlies regression (#24519)
follows up https://github.com/nim-lang/Nim/pull/24507

(cherry picked from commit d408b94063)
2025-01-14 13:17:04 +01:00
ringabout
105e134c3f adds a test case (#24518)
closes #19698

(cherry picked from commit 801733f286)
2025-01-14 13:16:38 +01:00
metagn
85c8b5b304 track call depth separately from loop count in VM (#24512)
refs #24503

Infinite recursions currently are not tracked separately from infinite
loops, because they also increase the loop counter. However the max
infinite loop count is very high by default (10 million) and does not
reliably catch infinite recursions before consuming a lot of memory. So
to protect against infinite recursions, we separately track call depth,
and add a separate option for the maximum call depth, much lower than
the maximum iteration count by default (2000, the same as
`nimCallDepthLimit`).

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 6f4106bf5d)
2025-01-14 13:16:21 +01:00
ringabout
2d470c9afd fixes strictdefs warnings for stdlibs [part two] (#24514)
After some cleanups for stdlibs, then we should enable warningaserror
for all tests

(cherry picked from commit c0861142f8)
2025-01-14 13:15:55 +01:00
ringabout
94a6b85538 fixes #24504; fixes ensureMove for refs (#24505)
fixes #24504

(cherry picked from commit d0288d3b57)
2025-01-14 13:15:46 +01:00
ringabout
90c5dfc32c adds a test case (#24515)
closes #17733

(cherry picked from commit 02fb0476ce)
2025-01-14 13:15:39 +01:00
ringabout
a7b671dad5 don't track result initialization if it is marked noinit (#24499)
We don't track `noinit` for variables introduced in
https://github.com/nim-lang/Nim/pull/10566. It should be applied to
`result` if the function is marked `noinit`

(cherry picked from commit 2e9e7f13ee)
2025-01-14 13:15:25 +01:00
Tomohiro
fb11c4404e fixes #24506; calculate timeout correctly (#24507)
`curTimeout` is calculated incorrectly. So this PR fixes it.
This PR also replaces `now()` with `getMonoTime()`.

(cherry picked from commit bbf6a62c90)
2025-01-14 13:13:35 +01:00
ringabout
1adcab885b remove unnecessary await (#24501)
There is already a when condition, so `await` is not needed to split the
function

(cherry picked from commit 6bbf9c3117)
2025-01-14 13:13:10 +01:00
ringabout
5ddbf2372e fixes some strictdefs warnings (#24502)
(cherry picked from commit 8f4bfda5f4)
2025-01-14 13:12:39 +01:00
ringabout
8f668c2373 adds a test case (#24500)
closes #24040

(cherry picked from commit c3120b6121)
2025-01-14 13:12:29 +01:00
metagn
3daf7dd2ac remove inserted derefs for ref object fields when transforming to dot call (#24498)
fixes #24492

Kind of a goofy way of doing this, but we count how many derefs were
used for the first parameter before calling `builtinFieldAccess`, then
count after, and if there are more now than before, we remove the added
derefs. I thought maybe getting rid of #18298 would simplify it but
maybe this would still be the best way.

For better encapsulation we could make `dotTransformation` take an
`nOrig` param instead but this would be less efficient since it would
need a copy, though `semAsgn` already makes one.

(cherry picked from commit 2529f33760)
2025-01-14 13:12:22 +01:00
ringabout
4b4b97018b prefix NimDestroyGlobals with nimMainPrefix (#24493)
ref https://github.com/nim-lang/Nim/issues/24471

---------

Co-authored-by: metagn <metagngn@gmail.com>
(cherry picked from commit 3bee04d9f3)
2025-01-14 13:11:55 +01:00
metagn
aa5fc4af58 install older version of nimcuda for arraymancer (#24496)
Attempt to fix CI failure, refs
https://github.com/nim-lang/Nim/pull/24495#issuecomment-2511299112,
alternative is to use a commit version like
bc65375ff5

(cherry picked from commit 33dc2367e7)
2025-01-14 13:11:44 +01:00
ringabout
062e77bce0 adds a test case (#24486)
closes #23680

(cherry picked from commit ddf5a9f6c5)
2025-01-14 13:11:16 +01:00
metagn
d04f9c426e fix crash with undeclared proc type pragma macro in generics (#24490)
fixes #24489

(cherry picked from commit 05bba15623)
2025-01-14 12:24:22 +01:00
ringabout
52809cd3dd fixes #24476; remove proc type cast if they are same types for backends (#24480)
fixes #24476

closes https://github.com/nim-lang/Nim/pull/24479

(cherry picked from commit 5340005869)
2025-01-14 12:24:00 +01:00
Andreas Rumpf
05a8b65eea stdlib: minor refactorings and updates (#24482)
(cherry picked from commit 8881017c80)
2025-01-14 12:16:21 +01:00
ringabout
b1a555dd52 Add support for parsing parameterised sql types (#24483)
Co-authored-by: Cletus Igwe <me@cletusigwe.com>
(cherry picked from commit dcd0793f2b)
2025-01-14 12:16:07 +01:00
Ryan McConnell
f5453e453e Fixes 3 small issues with concepts (#24481)
issue 1 - statics in the type:
This probably only handles simple cases. It's probably too accepting
only comparing the base, but that should only affect candidate selection
I think.
issue 2 - `tyArray` of length 3:
This is just a work around since I couldn't get the fix right in
previous PR
issue 3 - shadowing:
The part in `concepts.nim` that iterates candidates does not consider
imported idents if at least once module level ident matches. It does not
have to match in any other way then name.

EDIT: 2 more
issue 4 - composite typeclasses:
when declared in both the concept and the `proc` can cause problems
issue 5 - recursion:
simple recursion and scenarios where more than one concepts recurse
together (only tested two)

(cherry picked from commit e479151473)
2025-01-14 12:15:59 +01:00
ringabout
7d425e712e fixes #24472; let symbol created by template is reused in nimvm branch (#24473)
fixes #24472

Excluding variables which are initialized in the nimvm branch so that
they won't interfere the other branch

(cherry picked from commit e7f48cdd5c)
2025-01-14 12:15:51 +01:00
ringabout
e6f5e49184 minor fix for the command line helper (#24475)
(cherry picked from commit 1a901bd94e)
2025-01-14 12:15:21 +01:00
Judd
cd370e4725 Fix highlite.nim (#24457)
When parsing `a = 1` with `langPython`, Eof is reported unexpectedly.

Fix: allow other languages to fallback to "Identifier" when it is not a
keyword.

This patch is useful as this is a highlighter. `Eof` as annoying.

(cherry picked from commit 6112c51e78)
2025-01-14 12:15:09 +01:00
ringabout
42184227aa fix #19600; No error checking on fclose (#24468)
fix #19600

(cherry picked from commit 555191a3f0)
2025-01-14 12:11:57 +01:00
metagn
14ce1a91ce fix crash with tyBuiltInTypeClass matching itself (#24462)
fixes #24449

The standalone `seq` type is a `tyBuiltInTypeClass` with a single child
of kind `tySequence`, which itself has no children. This is also the
case for most other `tyBuiltInTypeClass` kinds. However this can cause a
crash in sigmatch when calling `isEmptyContainer` on this child type,
which expects the sequence type to have children. This check was added
in #5557 to prevent empty collections like `@[]` from matching their
respective typeclass, but it's not useful when matching against another
typeclass (which is done here to resolve an ambiguity). So to avoid the
crash, this empty container check is disabled when matching against
another typeclass.

(cherry picked from commit 96043bdbb7)
2025-01-14 09:11:14 +01:00
ringabout
ff7b83f266 adds a test case (#24469)
closes #13945

(cherry picked from commit af3181e75b)
2025-01-14 09:11:07 +01:00
metagn
522b184d5a retry thttpclient_ssl twice (#24467)
Flaky on linux_amd64

(cherry picked from commit 652edb229a)
2025-01-14 09:11:01 +01:00
Ryan McConnell
d339c58628 fixes #24451; concept matching generic body (#24458)
I think this might not be a comprehensive solution to dealing with
`tyGenericBody` but we take a step forward
#24451

(cherry picked from commit 08c2a1741d)
2025-01-14 09:10:45 +01:00
metagn
01b6c5d0d1 fix unix stdlib install location after #21328 (#24460)
closes #22369, closes #23197, closes #24385, refs #21328

According to #21328 the standard library on Unix should be installed in
`/usr/lib/nim/lib`, however the installer was not updated for this
change, hence the problem as described in
https://github.com/nim-lang/Nim/issues/23197#issuecomment-2031386896.

Have not tested if this fixes the problem but the comment heavily
implies it does. The problem is also in 2.0 so it could be backported
but I can't say for sure that it works and doesn't break anything.

(cherry picked from commit 33e455c986)
2025-01-14 09:10:40 +01:00
ringabout
1bc501f8ce adds a test case (#24466)
closes https://github.com/nim-lang/Nim/issues/23770 ref
https://github.com/nim-lang/Nim/pull/24442

(cherry picked from commit 9fcc3b0599)
2025-01-14 09:08:50 +01:00
ringabout
aa8d62f89c remove unnecessary imports (#24465)
ref https://github.com/nim-lang/Nim/issues/24272

(cherry picked from commit a788bae318)
2025-01-14 09:08:40 +01:00
ringabout
60a8eaaaa5 adds a test case (#24464)
closes #7784

(cherry picked from commit 3eddb64909)
2025-01-14 09:08:32 +01:00
metagn
f3da96d880 include new concepts in typeclasses, makes containsGenericType work (#24453)
fixes #24450

The new concepts were previously not included in
[containsGenericType][1] which prevents them from being instantiated.
Here they are included by being added to `tyTypeClasses` though this
doesn't have to be done, they can also be added manually to
`containsGenericTypeIter`, but this might be too specific.

[1]:
a2031ec6cf/compiler/types.nim (L1507-L1517)

(cherry picked from commit e28d2f42e9)
2025-01-14 09:08:13 +01:00
metagn
87c306061b disable weird type inference for object constructors (#24455)
closes #24372, refs #20091

This was added in #20091 for some reason but doesn't actually work and
only makes error messages more obscure. So for now, it's disabled.

Can also be backported to 2.0 if necessary.

(cherry picked from commit a610f23060)
2025-01-14 09:08:06 +01:00
metagn
2b1885a0fa remove structural equality check for objects and distinct types (#24448)
follows up #24425, fixes #18861, fixes #22445

Since #24425 generic object and distinct types now accurately link back
to their generic instantiations. To work around this issue previously,
type matching checked if generic objects/distinct types were
*structurally* equal, which caused false positives with types that
didn't use generic parameters in their structures. This structural check
is now removed, in cases where generic objects/distinct types require a
nontrivial equality check, the generic parameters of the `typeInst`
fields are checked for equality instead.

The check is copied from `tyGenericInst`, but the check in
`tyGenericInst` is not always sufficient as this type can be skipped or
unreachable in the case of `ref object`s.

(cherry picked from commit a2031ec6cf)
2025-01-14 09:07:30 +01:00
metagn
9c87f2cb4b always reinstantiate nominal values of generic instantiations (#24425)
fixes #22479, fixes #24374, depends on #24429 and #24430

When instantiating generic types which directly have nominal types
(object, distinct, ref/ptr object but not enums[^1]) as their values,
the nominal type is now copied (in the case of ref objects, its child as
well) so that it receives a fresh ID and `typeInst` field. Previously
this only happened if it contained any generic types in its structure,
as is the case for all other types.

This solves #22479 and #24374 by virtue of the IDs being unique, which
is what destructors check for. Technically types containing generic
param fields work for the same reason. There is also the benefit that
the `typeInst` field is correct. However issues like #22445 aren't
solved because the compiler still uses structural object equality checks
for inheritance etc. which could be removed in a later PR.

Also fixes a pre-existing issue where destructors bound to object types
with generic fields would not error when attempting to define a user
destructor after the fact, but the error message doesn't show where the
implicit destructor was created now since it was only created for
another instance. To do this, a type flag is used that marks the generic
type symbol when a generic instance has a destructor created. Reusing
`tfCheckedForDestructor` for this doesn't work.

Maybe there is a nicer design that isn't an overreliance on the ID
mechanism, but the shortcomings of `tyGenericInst` are too ingrained in
the compiler to use for this. I thought about maybe adding something
like `tyNominalGenericInst`, but it's really much easier if the nominal
type itself directly contains the information of its generic parameters,
or at least its "symbol", which the design is heading towards.

[^1]: See [this
test](21420d8b09/lib/std/enumutils.nim (L102))
in enumutils. The field symbols `b0`/`b1` always have the uninstantiated
type `B` because enum fields don't expect to be generic, so no generic
instance of `B` matches its own symbols. Wouldn't expect anyone to use
generic enums but maybe someone does.

(cherry picked from commit 05c74d6844)
2025-01-14 09:07:03 +01:00
metagn
03b6999499 prevent codegen of inactive case fields in VM object constructor nodes (#24442)
fixes #17571

Objects in the VM are represented as object constructor nodes that
contain every single field, including ones in different case branches.
This is so that every field has a unique invariant index in the object
constructor that can be written to and read from. However when
converting this node back into semantic code, fields from inactive case
branches can remain in the constructor which causes bad codegen,
generating assignments to fields from other case branches.

To fix this, fields from inactive branches are now detected in
`semmacrosanity.annotateType` (called in `fixupTypeAfterEval`) and
marked to prevent the codegen of their assignments. In #24441 these
fields were excluded from the resulting node, but this causes issues
when the node is directly supposed to go back into the VM, for example
as `const` values. I don't know if this is the only case where this
happens, so I wasn't sure about how to keep that implementation working.

(cherry picked from commit 75b512bc6a)
2025-01-14 09:06:58 +01:00
metagn
2690ab01c0 fix wrong error for iterators with no body and pragma macro (#24440)
fixes #16413

`semIterator` checks if the original iterator passed to it has no body,
but it should check the processed node created by `semProcAux`.

(cherry picked from commit e239968b80)
2025-01-14 09:06:49 +01:00
ringabout
c79fb859f1 adds some test cases (#24436)
closes #24043
closes #24045

(cherry picked from commit cc696f18c0)
2025-01-14 09:05:48 +01:00
ringabout
2d658e8de5 fixes #24402; Memory leak under Arc/Orc on inline iterators with nested seq (#24419)
fixes #24402

```nim
iterator myPairsInline*[T](twoDarray: seq[seq[T]]): (int, seq[T]) {.inline.} =
  for indexValuePair in twoDarray.pairs:
    yield indexValuePair

proc innerTestTotalMem() =
  var my2dArray: seq[seq[int32]] = @[]

  # fill with some data...
  for i in 0'i32..100:
    var z = @[i, i+1]
    my2dArray.add z

  for oneDindex, innerArray in myPairsInline(my2dArray):
    discard

innerTestTotalMem()
```

In `for oneDindex, innerArray in myPairsInline(my2dArray)`, `oneDindex`
and `innerArray` becomes `cursors` because they satisfy the criterion of
`isSimpleIteratorVar`. On the one hand, it is not correct to have them
point to the temporary generated by tuple unpacking, which left the
memory of the temporary uncleaned up. On the other hand, we don't need
to generate a temporary for a symbol node when unpacking the tuple.

(cherry picked from commit 21420d8b09)
2025-01-14 09:05:36 +01:00
metagn
0036bb976b fix subtype match of generic object types (#24430)
split from #24425

Matching `tyGenericBody` performs a match on the last child of the
generic body, in this case the uninstantied `tyObject` type. If the
object contains no generic fields, this ends up being the same type as
all instantiated ones, but if it does, a new type is created. This fails
the `sameObjectTypes` check that subtype matching for object types uses.
To fix this, also consider that the pattern type could be the generic
uninstantiated object type of the matched type in subtype matching.

(cherry picked from commit 511ab72342)
2025-01-14 09:05:28 +01:00
metagn
b0f3d1e874 fix jsonutils macro with generic case object (#24429)
split from #24425

The added test did not work previously. The result of `getTypeImpl` is
the uninstantiated AST of the original type symbol, and the macro
attempts to use this type for the result. To fix the issue, the provided
`typedesc` argument is used instead.

(cherry picked from commit 45e21ce8f1)
2025-01-14 09:05:24 +01:00
metagn
9f03b98de5 stricter skip for conversions in array indices in transf (#24424)
fixes #17958

In `transf`, conversions in subscript expressions are skipped (with
`skipConv`'s rules). This is because array indexing can produce
conversions to the range type that is the array's index type, which
causes a `RangeDefect` rather than an `IndexDefect` (and also
`--rangeChecks` and `--indexChecks` are both considered). However this
causes problems when explicit conversions are used, between types of
different bitsizes, because those also get skipped.

To fix this, we only skip the conversion if:

* it's a hidden (implicit) conversion
* it's a range check conversion (produces `nkChckRange`)
* the subscript is on an array type and the result type of the
conversion has the same bounds as the array index type

And `skipConv` rules also still apply (int/float classification).

Another idea would be to prevent the implicit conversion to the array
index type from being generated. But there is no good way to do this:
matching to the base type instead prevents types like `uint32` from
implicitly converting (i.e. it can convert to `range[0..3]` but not
`int`), and analyzing whether this is an array bound check is easier in
`transf`, since `sigmatch` just produces a type conversion.

The rules for skipping the conversion could also receive some other
tweaks: We could add a rule that changing bitsizes also doesn't skip the
conversion, but this breaks the `uint32` case. We could simplify it to
only removing implicit skips to specifically fix #17958, but this is
wrong in general.

We could also add something like `nkChckIndex` that generates index
errors instead but this is weird when it doesn't have access to the
collection type and it might be overkill.

(cherry picked from commit 76c5f16ac5)
2025-01-14 09:05:18 +01:00
Sam
0b7e22635e Fixes #24369 (#24370)
Hope this fixes #24369, happy for any feedback on the PR.

(cherry picked from commit 1fddb61b3b)
2025-01-14 09:05:07 +01:00
metagn
3642f4d375 gensym anonymous proc symbols (#24422)
fixes #14067, fixes #15004, fixes #19019

Anonymous procs are [added to
scope](8091d76306/compiler/semstmts.nim (L2466))
with the name `:anonymous`. This means that if they have the same
signature in a scope, they can consider each other as redefinitions. To
prevent this, mark their symbols as `sfGenSym` so they do not get added
to scope or cause any name conflicts. The commented out `and not isAnon`
check wouldn't work because `isAnon` would not be true if the proc is
being resemmed, in which case the name field in the proc AST would have
the symbol of the anonymous proc rather than being empty.

There is a separate problem of default values in generic/normal procs
not opening new scopes which is partially responsible for #19019.

(cherry picked from commit 3e47725c08)
2025-01-14 09:05:01 +01:00
metagn
f292393816 skip tyAlias in generic alias checks [backport:2.0] (#24417)
fixes #24415

Since #23978 (which is in 2.0), all generic types that alias to another
type now insert a `tyAlias` layer in their value. However the
`skipGenericAlias` etc code which `sigmatch` uses is not updated for
this, so `tyAlias` is now skipped in these.

The relevant code in sigmatch is:
67ad1ae159/compiler/sigmatch.nim (L1668-L1673)

This behavior is also suspicious IMO, not skipping a structural
`tyGenericInst` alias can be useful for code like #10220, but this is
currently arbitrarily decided based on "depth" and whether the alias is
to another `tyGenericInst` type or not. Maybe in the future we could
enforce the use of a nominal type.

(cherry picked from commit 45b8434c7d)
2025-01-14 09:04:54 +01:00
metagn
6ec663f7bc fix standalone explicit generic procs with unresolved arguments (#24404)
fixes issue described in https://forum.nim-lang.org/t/12579

In #24065 explicit generic parameter matching was made to fail matches
on arguments with unresolved types in generic contexts (the sigmatch
diff, following #24010), similar to what is done for regular calls since
#22029. However unlike regular calls, a failed match in a generic
context for a standalone explicit generic instantiation did not convert
the expression into one with `tyFromExpr` type, which means it would
error immediately given any unresolved parameter. This is now done to
fix the issue.

For explicit generic instantiations on single non-overloaded symbols, a
successful match is still instantiated. For multiple overloads (i.e.
symchoice), if any of the overloads fail the match, the entire
expression is considered untyped and any instantiations are not used, so
as to not void overloads that would match later. This means even
symchoices without unresolved arguments aren't instantiated, which may
be too restrictive, but it could also be too lenient and we might need
to make symchoice instantiations always untyped. The behavior for
symchoice is not sound anyway given it causes #9997 so this is something
to consider for a redesign.

Diff follows #24276.

(cherry picked from commit 67ad1ae159)
2025-01-14 09:04:44 +01:00
ringabout
6d02ac1ba0 fixes strictdefs with when nimvm (#24409)
ref https://github.com/nim-lang/Nim/pull/24225
related https://github.com/nim-lang/Nim/pull/24306

> Code in branches must not affect semantics of the code that follows
the
`when nimvm` statement. E.g. it must not define symbols that are used in
  the following code.

The test shouldn't have passed when
https://github.com/nim-lang/Nim/pull/24306
would be implemented somehow. Some third packages have already misused
`when nimvm` by defining symbols in the other branch of `when nimvm`.

e.g. in https://github.com/status-im/nim-unittest2/pull/34

```nim
when nimvm:
  discard
else:
  let suiteName {.inject.} = nameParam

use(suiteName)
```

(cherry picked from commit c71de10608)
2025-01-14 09:04:35 +01:00
metagn
ce1fa86095 disable sfml test on osx (#24615)
Tried installing sfml 2 in #24614 but didn't work

(cherry picked from commit d83ff81695)
2025-01-14 08:40:02 +01:00
metagn
4900550e9c disable all badssl tests indefinitely (#24403)
Flaky not just due to recent ubuntu 24/GCC 14 upgrades, windows fails as
well, assuming the issue is with badssl or it's just not worth testing
here.

(cherry picked from commit 5f056f87b2)
2025-01-14 07:53:56 +01:00
Phil Krylov
9fe2356e74 std/parsesql: Fix JOIN parsing (#22890)
This commit fixes/adds tests for and fixes several issues with `JOIN`
operator parsing:

- For OUTER joins, LEFT | RIGHT | FULL specifier is not optional
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
OUTER JOIN b
ON a.id = b.id
""")
```

- For NATURAL JOIN and CROSS JOIN, ON and USING clauses are forbidden
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
CROSS JOIN b
ON a.id = b.id
""")
```

- JOIN should parse as part of FROM, not after WHERE
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
WHERE a.id IS NOT NULL
INNER JOIN b
ON a.id = b.id
""")
```

- LEFT JOIN should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
LEFT JOIN b
ON a.id = b.id
""") == "select id from a left join b on a.id = b.id;"
```

- NATURAL JOIN should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
NATURAL JOIN b
""") == "select id from a natural join b;"
```

- USING should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
JOIN b
USING (id)
""") == "select id from a join b using (id );"
```

- Multiple JOINs should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
JOIN b
ON a.id = b.id
LEFT JOIN c
USING (id)
""") == "select id from a join b on a.id = b.id left join c using (id );"
```

(cherry picked from commit 46bb47a444)
2025-01-14 07:53:44 +01:00
ringabout
37ab27bd99 improve httpclient docuementation (#24398)
ref https://github.com/nim-lang/Nim/issues/24394

(cherry picked from commit 08b82c90f5)
2025-01-14 07:53:36 +01:00
ringabout
5e22d8bc3c fixes #24395; remove ndi (#24396)
fixes  #24395

(cherry picked from commit 8b88b5fdd8)
2025-01-14 07:53:29 +01:00
ringabout
6b102d5c13 azure-pipelines update to ubuntu 24.04 gcc 14 (#24386)
(cherry picked from commit 7b47987341)
2025-01-14 07:53:23 +01:00
ringabout
51f8649e36 trigger package CI for version-2-2 (#24393)
(cherry picked from commit d55cd40642)
2025-01-14 07:53:11 +01:00
ringabout
df27b427af fixes #24378; supportsCopyMem can fail from macro context with tuples (#24383)
fixes #24378

```nim
type Win = typeof(`body`)
doAssert not supportsCopyMem((int, Win))
```

`semAfterMacroCall` doesn't skip the children aliases types in the tuple
typedesc construction while the normal program seem to skip the aliases
types somewhere

`(int, Win)` is kept as `(int, alias string)` instead of expected `(int,
string)`

(cherry picked from commit 5e56f0a356)
2025-01-14 07:52:42 +01:00
ringabout
e57f755b78 fixes #24371; incorrect importc wrapper incompatible with gcc 14 on Windows (#24388)
fixes #24371

(cherry picked from commit 74df699ff1)
2025-01-14 07:52:35 +01:00
ringabout
d78c7aa697 disable Test on aarch64 (#24389)
ref https://github.com/nim-lang/Nim/issues/24287

(cherry picked from commit 1576563775)
2025-01-14 07:52:28 +01:00
metagn
435a152c66 implement generic default values for object fields (#24384)
fixes #21941, fixes #23594

(cherry picked from commit 4091576ab7)
2025-01-14 07:52:18 +01:00
ringabout
6c2de9b294 fixes #24379; better error messages for ill-formed type symbols from macros (#24380)
fixes #24379

(cherry picked from commit d61897459d)
2025-01-14 07:52:09 +01:00
ringabout
babc7d8c16 fixes #23545; C compiler error when default initializing an object field function (#24375)
fixes #23545

(cherry picked from commit 815bbf0e73)
2025-01-14 07:52:02 +01:00
ringabout
022bd12e82 improve passes.nim (#24376)
(cherry picked from commit 3fc87259bd)
2025-01-14 07:51:55 +01:00
ringabout
3c528c987c fixes #24359; VM problem: dest register is not set with const-bound proc (#24364)
fixes #24359

follow up https://github.com/nim-lang/Nim/pull/11076

It should not try to evaluate the const proc if the proc doesn't have a
return value.

(cherry picked from commit 031ad957ba)
2025-01-14 07:51:44 +01:00
metagn
52d94c1c86 include static types in type bound ops (#24366)
refs https://github.com/nim-lang/Nim/pull/24315#discussion_r1816332587

(cherry picked from commit 40fc2d0e76)
2025-01-14 07:51:38 +01:00
metagn
87de7f9193 don't cascade vmgen errors in nim check without error outputs (#24365)
refs #23625, refs #24289

Encountered in #24360 but could not reproduce minimally: overloading on
static parameters can work with the normal compile commands but crash
`nim check`. Static overloading relies on `tryConstExpr` which recovers
from things like `globalError` and fails softly, in this case this can
happen when a variable etc. is not available to evaluate in the VM. But
with `nim check`, the compiler does not throw an exception in this case,
and instead tries to keep generating the entire expression in the VM,
which can cause crashes.

To fix this, when the compiler has no error outputs even on `nim check`,
we raise a global error so that the VM code generation stops early. This
fixes both `tryConstExpr` and speeds up `nim check`, because no error
outputs means we don't need cascading errors.

(cherry picked from commit efd603eb28)
2025-01-14 07:51:32 +01:00
Jake Leahy
520b16b81e Fix links for succ/pred/inc/dec in system docs (#24363)
Links for succ/pred/inc/dec were incorrect since they link to a symbol
with `int` as their second type.
Uses local referencing instead so that it links to the correct symbol.

Doesn't change the other links since they worked and doing the same
local referencing for `high`/`low` would've make them link to the group
of procs instead of the specific ones for ordinals

(cherry picked from commit 79ce3fe6b7)
2025-01-14 07:51:26 +01:00
ringabout
98403a06e7 fixes #18081; fixes #18079; fixes #18080; nested ref/deref'd types (#24335)
fixes #18081;
fixes https://github.com/nim-lang/Nim/issues/18080
fixes #18079

reverts https://github.com/nim-lang/Nim/pull/20738

It is probably more reasonable to use the type node from `nkObjConstr`
since it is barely changed unlike the external type, which is
susceptible to code transformation e.g. `addr(deref objconstr)`.

(cherry picked from commit aa90d00caf)
2025-01-14 07:50:41 +01:00
ringabout
4bdeddcac5 deprecate NewFinalize with the ref T finalizer (#24354)
pre-existing issues:

```nim
block:
  type
    FooObj = object
      data: int
    Foo = ref ref FooObj

  proc delete(self: Foo) =
    echo self.data

  var s: Foo
  new(s, delete)
```
it crashed with arc/orc in 1.6.x and 2.x.x

```nim
block:
  type
    Foo = ref int

  proc delete(self: Foo) =
    echo self[]

  var s: Foo
  new(s, delete)
```

The simple fix is to add a type restriction for the type `T` for arc/orc
versions
```nim
  proc new*[T: object](a: var ref T, finalizer: proc (x: T) {.nimcall.})
```

(cherry picked from commit 2af602a5c8)
2025-01-14 07:50:33 +01:00
metagn
9be3559ed2 consider calls as complex openarray assignment to iterator params (#24333)
fixes #13417, fixes #19703

When passing an expression to an `openarray` iterator parameter: If the
expression is a statement list (considered "complex"), it's assigned in
a non-deep-copying way to a temporary variable first, then this variable
is used as a parameter. If it's not a statement list, i.e. a call or a
symbol, the parameter is substituted directly with the given expression.
In the case of calls, this results in the call potentially being
executed more than once, or can cause redefined variables in the
codegen.

To fix this, calls are also considered as "complex" assignments to
openarrays, as long as the return type of the call is not `openarray` as
the generated assignment in that case has issues/is unimplemented
(caused a segfault [here in
datamancer](47ba4d81bf/src/datamancer/dataframe.nim (L1580))).

As for why creating a temporary isn't the default only with exceptions
for things like `nkSym`, the "non-deep-copying" way of assignment
apparently still causes arrays to be copied according to a comment in
the code. I'm not sure to what extent this is true: if it still happens
on ARC/ORC, if it happens for every array length, or if we can fix it by
passing arrays by reference. Otherwise, a more general way to assign to
openarrays might be needed, but I'm not sure if the compiler can easily
do this.

(cherry picked from commit d303c289fa)
2025-01-14 07:50:24 +01:00
ringabout
f2a9765014 fixes #23952; Size/Signedness issues with unordered enums (#24356)
fixes #23952

It reorders `type Foo = enum A, B = -1` to `type Foo = enum B = -1, A`
so that `firstOrd` etc. continue to work.

(cherry picked from commit 294b1566e7)
2025-01-14 07:50:17 +01:00
metagn
ac8c44e08d implement type bound operation RFC (#24315)
closes https://github.com/nim-lang/RFCs/issues/380, fixes #4773, fixes
#14729, fixes #16755, fixes #18150, fixes #22984, refs #11167 (only some
comments fixed), refs #12620 (needs tiny workaround)

The compiler gains a concept of root "nominal" types (i.e. objects,
enums, distincts, direct `Foo = ref object`s, generic versions of all of
these). Exported top-level routines in the same module as the nominal
types that their parameter types derive from (i.e. with
`var`/`sink`/`typedesc`/generic constraints) are considered attached to
the respective type, as the RFC states. This happens for every argument
regardless of placement.

When a call is overloaded and overload matching starts, for all
arguments in the call that already have a type, we add any operation
with the same name in the scope of the root nominal type of each
argument (if it exists) to the overload match. This also happens as
arguments gradually get typed after every overload match. This restricts
the considered overloads to ones attached to the given arguments, as
well as preventing `untyped` arguments from being forcefully typed due
to unrelated overloads. There are some caveats:

* If no overloads with a name are in scope, type bound ops are not
triggered, i.e. if `foo` is not declared, `foo(x)` will not consider a
type bound op for `x`.
* If overloads in scope do not have enough parameters up to the argument
which needs its type bound op considered, then type bound ops are also
not added. For example, if only `foo()` is in scope, `foo(x)` will not
consider a type bound op for `x`.

In the cases of "generic interfaces" like `hash`, `$`, `items` etc. this
is not really a problem since any code using it will have at least one
typed overload imported. For arbitrary versions of these though, as in
the test case for #12620, a workaround is to declare a temporary
"template" overload that never matches:

```nim
# neither have to be exported, just needed for any use of `foo`:
type Placeholder = object
proc foo(_: Placeholder) = discard
```

I don't know what a "proper" version of this could be, maybe something
to do with the new concepts.

Possible directions:

A limitation with the proposal is that parameters like `a: ref Foo` are
not attached to any type, even if `Foo` is nominal. Fixing this for just
`ptr`/`ref` would be a special case, parameters like `seq[Foo]` would
still not be attached to `Foo`. We could also skip any *structural* type
but this could produce more than one nominal type, i.e. `(Foo, Bar)`
(not that this is hard to implement, it just might be unexpected).

Converters do not use type bound ops, they still need to be in scope to
implicitly convert. But maybe they could also participate in the nominal
type consideration: if `Generic[T] = distinct T` has a converter to `T`,
both `Generic` and `T` can be considered as nominal roots.

The other restriction in the proposal, being in the same scope as the
nominal type, could maybe be worked around by explicitly attaching to
the type, i.e.: `proc foo(x: T) {.attach: T.}`, similar to class
extensions in newer OOP languages. The given type `T` needs to be
obtainable from the type of the given argument `x` however, i.e.
something like `proc foo(x: ref T) {.attach: T.}` doesn't work to fix
the `ref` issue since the compiler never obtains `T` from a given `ref
T` argument. Edit: Since the module is queried now, this is likely not
possible.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 2864830941)
2025-01-14 07:50:04 +01:00
metagn
850132d37c define flexible array without size for tcc & all C99 (#24355)
fixes #24236

Locally tested to generate a 100 KB file for TCC. Empty flexible array
size is standard in C99 but maybe some compilers still don't support it.
At the very least an array size of 1000000 should be rare.

(cherry picked from commit dd3a4b2aba)
2025-01-14 07:49:52 +01:00
ringabout
a1ee2ee566 adds noise to important_packages (#24352)
ref https://github.com/jangko/nim-noise

(cherry picked from commit b534f34e95)
2025-01-14 07:49:45 +01:00
ringabout
9306b5e917 std/nre now uses destructors instead of finializer (#24353)
Similar to changes in
bafb4f119c

(cherry picked from commit 3aaaed1acf)
2025-01-14 07:49:23 +01:00
ringabout
67a636bec8 closes #19984; adds a test case (#24349)
closes #19984

(cherry picked from commit baf3695c76)
2025-01-14 07:48:09 +01:00
metagn
9a6230ee5a wrap fields iterations in if true scope [backport] (#24343)
fixes #24338

When unrolling each iteration of a `fields` iterator, the compiler only
opens a new scope for semchecking, but doesn't generate a node that
signals to the codegen that a new scope should be created. This causes
issues for reused template instantiations that reuse variable symbols
between each iteration, which causes the codegen to generate multiple
declarations for them in the same scope (regardless of `inject` or
`gensym`). To fix this, we wrap the unrolled iterations in an `if true:
body` node, which both opens a new scope and doesn't interfere with
`break`.

(cherry picked from commit ca5df9ab25)
2025-01-14 07:48:01 +01:00
bptato
7e840e0164 Fix broken poll and nfds_t bindings (#24331)
This fixes several cases of the Nim binding of nfds_t being inconsistent
with the target platform signedness and/or size.

Additionally, it fixes poll's third argument (timeout) being set to Nim
"int" when it should have been "cint".

The former is the same issue that #23045 had attempted to fix, but
failed because it only considered Linux. (Also, it was only applied to
version 2.0, so the two branches now have incompatible versions of the
same bug.)

Notes:

* SVR4's original "unsigned long" definition is cloned by Linux and
Haiku. Nim got this right for Haiku and Linux-amd64, but it was wrong on
non-amd64 Linux.
* Zephyr does not have nfds_t, but simply uses (signed) "int". This was
already correctly reflected by Nim.
* OpenBSD poll.h uses "unsigned int", and other BSD derivatives follow
suit. This being the most commonly copied definition, the fallback case
now returns cuint. (This also seems to be correct for the OS X headers I
could find on the web.)
* This changes Nintendo Switch nfds_t to cuint from culong. It is
purportedly a FreeBSD derivative, so I *think* this is correct, but I
can't tell because I don't have access to the Nintendo Switch headers.

I have also moved the platform-specific Tnfds to posix.nim so that we
can reuse the fallback logic on all platforms. (e.g. specifying the size
in posix_linux_amd64 only to then use when defined(linux) in posix_other
seems redundant.)

(cherry picked from commit 67442471ae)
2025-01-14 07:47:40 +01:00
metagn
cd760b00c2 clean up stdlib with --jsbigint64 (#24255)
refs #6978, refs #6752, refs #21613, refs #24234

The `jsNoInt64`, `whenHasBigInt64`, `whenJsNoBigInt64` templates are
replaced with bool constants to use with `when`. Weird that I didn't do
this in the first place.

The `whenJsNoBigInt64` template was also slightly misleading. The first
branch was compiled for both no bigint64 on JS as well as on C/C++. It
seems only `trandom` depended on this by mistake.

The workaround for #6752 added in #6978 to `times` is also removed with
`--jsbigint64:on`, but #24233 was also encountered with this, so this PR
depends on #24234.

(cherry picked from commit 041098e882)
2025-01-14 07:47:30 +01:00
Jake Leahy
0cce80071b Fix quoted idents in ctags (#24317)
Running `ctags` on files with quoted symbols (e.g. `$`) would list \`
instead of the full ident. Issue was the result getting reassigned at
the end to a \` instead of appending

(cherry picked from commit 93c24fe1c5)
2025-01-14 07:47:19 +01:00
metagn
5aeabdac8f symmetric difference operation for sets via xor (#24286)
closes https://github.com/nim-lang/RFCs/issues/554

Adds a symmetric difference operation to the language bitset type. This
maps to a simple `xor` operation on the backend and thus is likely
faster than the current alternatives, namely `(a - b) + (b - a)` or `a +
b - a * b`. The compiler VM implementation of bitsets already
implemented this via `symdiffSets` but it was never used.

The standalone binary operation is added to `setutils`, named
`symmetricDifference` in line with [hash
sets](https://nim-lang.org/docs/sets.html#symmetricDifference%2CHashSet%5BA%5D%2CHashSet%5BA%5D).
An operator version `-+-` and an in-place version like `toggle` as
described in the RFC are also added, implemented as trivial sugar.

(cherry picked from commit ae9287c4f3)
2025-01-14 07:47:13 +01:00
metagn
2d678fa45c better errors for standalone explicit generic instantiations (#24276)
refs #8064, refs #24010

Error messages for standalone explicit generic instantiations are
revamped. Failing standalone explicit generic instantiations now only
error after overloading has finished and resolved to the default `[]`
magic (this means `[]` can now be overloaded for procs but this isn't
necessarily intentional, in #24010 it was documented that it isn't
possible). The error messages for failed instantiations are also no
longer a simple `cannot instantiate: foo` message, instead they now give
the same type mismatch error message as overloads with mismatching
explicit generic parameters.

This is now possible due to the changes in #24010 that delegate all
explicit generic proc instantiations to overload resolution. Old code
that worked around this is now removed. `maybeInstantiateGeneric` could
maybe also be removed in favor of just `explicitGenericSym`, the `result
== n` case is due to `explicitGenericInstError` which is only for niche
cases.

Also, to cause "ambiguous identifier" error messages when the explicit
instantiation is a symchoice and the expression context doesn't allow
symchoices, we semcheck the sym/symchoice created by
`explicitGenericSym` with the given expression flags.

#8064 isn't entirely fixed because the error message is still misleading
for the original case which does `values[1]`, as a consequence of
#12664.

(cherry picked from commit 0a058a6b8f)
2025-01-14 07:47:08 +01:00
ringabout
ee1c4de48a build documentation for repr_v2 (#24325)
(cherry picked from commit 0806fb0b6f)
2025-01-14 07:47:01 +01:00
ringabout
b3e02ef0c3 make PNode.typ a private field (#24326)
(cherry picked from commit 68b2e9eb6a)
2025-01-14 07:46:40 +01:00
Yuriy Glukhov
893c638485 Fixes #3824, fixes #19154, and hopefully #24094. Re-applies #23787. (#24316)
The first commit reverts the revert of #23787.
The second fixes lambdalifting in convolutedly nested
closures/closureiters. This is considered to be the reason of #24094,
though I can't tell for sure, as I was not able to reproduce #24094 for
complicated but irrelevant reasons. Therefore I ask @jmgomez, @metagn or
anyone who could reproduce it to try it again with this PR.

I would suggest this PR to not be squashed if possible, as the history
is already messy enough.

Some theory behind the lambdalifting fix:
- A closureiter that captures anything outside its body will always have
`:up` in its env. This property is now used as a trigger to lift any
proc that captures such a closureiter.
- Instantiating a closureiter involves filling out its `:up`, which was
previously done incorrectly. The fixed algorithm is to use "current" env
if it is the owner of the iter declaration, or traverse through `:up`s
of env param until the common ancestor is found.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 5fa96ef270)
2025-01-14 07:46:30 +01:00
Tomohiro
9f51b52f5f Document about noinline calling convention and exportcpp pragma in Nim manual (#24323)
It seems exportcpp was implemented in v1.0 but there is no documentation
about it excepts changelog.
`noinline` is used in many procedures in Nim code but there is also no
documentation about it.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit b8f6088ac0)
2025-01-14 07:46:21 +01:00
metagn
bcfb30a8be shallow fold prevention for addr, nkHiddenAddr (#24322)
fixes #24305, refs #23807

Since #23014 `nkHiddenAddr` is produced to fast assign array elements in
iterators. However the array access inside this `nkHiddenAddr` can get
folded at compile time, generating invalid code. In #23807, compile time
folding of regular `addr` expressions was changed to be prevented in
`transf` but `nkHiddenAddr` was not updated alongside it.

The method for preventing folding in `addr` in #23807 was also faulty,
it should only trigger on the immediate child node of the address rather
than all nodes nested inside it. This caused a regression as outlined in
[this
comment](https://github.com/nim-lang/Nim/pull/24322#issuecomment-2419560182).

To fix both issues, `addr` and `nkHiddenAddr` now both shallowly prevent
constant folding for their immediate children.

(cherry picked from commit 52cf7dfde0)
2025-01-14 07:46:13 +01:00
ringabout
7948e2f2c2 fixes #24319; move doesn't work well with (deref (var array)) (#24321)
fixes #24319

`byRefLoc` (`mapType`) requires the Loc `a` to have the right type.
Without `lfEnforceDeref`, it produces the wrong type for `deref (var
array)`, which may come from `mitems`.

(cherry picked from commit 0347536ff2)
2025-01-14 07:46:07 +01:00
ringabout
6b31400ade adds a getter/setter for owner (#24318)
(cherry picked from commit d0b6b9346e)
2025-01-14 07:45:59 +01:00
ringabout
a713aee682 fixes #18896; fixes #20886; importc types alias doesn't work with distinct (#24313)
fixes #18896
fixes #20886

```nim
type
  PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
    # import C's FILE* type; Nim will treat it as a new pointer type
```
This is an excerpt from the Nim manual. In the old Nim versions, it
produces a void pointer type instead of the `FILE*` type that should
have been generated. Because these C types tend to be opaque and adapt
to changes on different platforms. It might affect the portability of
Nim on various OS, i.e. `csource_v2` cannot build on the apline platform
because of `Time` relies on Nim types instead of the `time_t` type.

ref https://github.com/nim-lang/Nim/pull/18851

(cherry picked from commit 8be82c36c9)
2025-01-14 07:45:50 +01:00
ringabout
aa7e7f5f63 make owner a private field of PType (#24314)
follow up https://github.com/nim-lang/Nim/pull/24311

(cherry picked from commit a3aea224c9)
2025-01-14 07:45:39 +01:00
ringabout
8d7b3baf9f make owner a private field of PSym (#24311)
(cherry picked from commit 53460f312c)
2025-01-14 07:45:34 +01:00
ringabout
274cdba334 closes #19585; adds a test case for #21648 (#24310)
closes #19585
follow up #21648

(cherry picked from commit 922f7dfd71)
2025-01-14 07:45:25 +01:00
ringabout
a04dada93d fixes ci_generate produces unnecessary spaces on Windows (#24309)
follow up https://github.com/nim-lang/Nim/pull/17899

(cherry picked from commit 3e8f44b232)
2025-01-14 07:45:19 +01:00
ringabout
4d170ac586 fixes #24258; compiler crash on len of varargs[untyped] (#24307)
fixes #24258

It uses conditionals to guard against ill formed AST to produce better
error messages, rather than crashing

(cherry picked from commit 8b39b2df7d)
2025-01-14 07:39:32 +01:00
ringabout
e3a8d98626 define -d:nimHasDefaultFloatRoundtrip and enable datamancer (#24300)
ref https://github.com/SciNim/Datamancer/pull/73
ref https://github.com/SciNim/Datamancer/issues/72

(cherry picked from commit d4b9c147ab)
2025-01-14 07:37:18 +01:00
ringabout
41145210a8 templates/macros use no expected types when return types are specified (#24298)
fixes #24296
fixes #24295

Templates use `expectedType` for type inference. It's justified that
when templates don't have an actual return type, i.e., `untyped` etc.

When the return type of templates is specified, we should not infer the
type

```nim
template g(): string = ""

let c: cstring = g()
```
In this example, it is not reasonable to annotate the templates
expression with the `cstring` type before the `fitNode` check with its
specified return type.

(cherry picked from commit 80e6b35721)
2025-01-14 07:36:48 +01:00
Aryo
3c2b32aebe Expand enum example tut1.md (#24268)
I couldn't understand why there is "x" declaration. Comparison make it
easier to understand to people not familiar to enums.

(cherry picked from commit 1dbf614858)
2025-01-14 07:36:05 +01:00
metagn
613f1e94ae clean up testament retries, add some comments (#24294)
follows up #24279

`discard finishTest` was wrong if the test still had a `retries` option:
it would just ignore the result of the test. This is an unlikely mistake
but we safeguard against it by splitting `finishTest` into two, one that
completely ignores the retries option and `finishTestRetryable` which
has to be checked for a retry. This also makes the code look slightly
better.

(cherry picked from commit 2f7586c066)
2025-01-14 07:35:59 +01:00
metagn
660a9cecf0 add retries to testament, use it for GC tests (#24279)
Testament now retries a test by a specified amount if it fails in any
way other than an invalid spec. This is to deal with the flaky GC tests
on Windows CI that fail in many different ways, from the linker randomly
erroring, segfaults, etc.

Unfortunately I couldn't do this cleanly in testament's current code.
The proc `addResult`, which is the "final" proc called in a test run's
lifetime, is now wrapped in a proc `finishTest` that returns a bool
`true` if the test failed and has to be retried. This result is
propagated up from `cmpMsgs` and `compilerOutputTests` until it reaches
`testSpecHelper`, which handles these results by recursing if the test
has to be retried. Since calling `testSpecHelper` means "run this test
with one given configuration", this means every single matrix
option/target etc. receive an equal amount of retries each.

The result of `finishTest` is ignored in cases where it's known that it
won't be retried due to passing, being skipped, having an invalid spec
etc. It's also ignored in `testNimblePackages` because it's not
necessary for those specific tests yet and similar retry behavior is
already implemented for part of it.

This was a last resort for the flaky GC tests but they've been a problem
for years at this point, they give us more work to do and turn off
contributors. Ideally GC tests failing should mark as "needs review" in
the CI rather than "failed" but I don't know if Github supports
something like this.

(cherry picked from commit 720d0aee5c)
2025-01-14 07:35:50 +01:00
metagn
bffd2e0330 don't evaluate "cannot eval" errors with nim check (#24289)
fixes #24288, refs #23625

Since #23625 "cannot evaluate" errors during VM code generation are
"soft" errors with `nim check`, i.e. the code generation isn't halted
(except for the current proc which `return`s which can cause wrong
codegen) and the expression is still attempted to be evaluated. Now,
these errors signal to the VM that the current generated VM code cannot
be evaluated, and so instead of evaluating, an error node is returned.
This keeps the benefit of the "soft" errors without potentially crashing
the compiler on improperly generated VM code. Although maybe the
compiler might not be able to handle the generated error node in some
cases.

This fixes the chame example in #24288 but this is not tested in CI.
Presumably it or the compiler was doing something like `compiles()` on
code that can't run in the VM.

I would accept nicer ways of tracking non-evaluability than
`c.cannotEval = true` but I tried to keep it as harmless as possible.

(cherry picked from commit def1fea43a)
2025-01-14 07:35:43 +01:00
Andreas Rumpf
d357a2e9a5 modulegraphs: added a flag useful for gear2 (#24293)
(cherry picked from commit 25c068c070)
2025-01-14 07:35:36 +01:00
metagn
fca3504105 fix type of reconstructed kind field node in field checking analysis [backport] (#24290)
fixes #24021

The field checking for case object branches at some point generates a
negated set `contains` check for the object discriminator. For enum
types, this tries to generate a complement set and convert to a
`contains` check in that instead. It obtains this type from the type of
the element node in the `contains` check.

`buildProperFieldCheck` creates the element node by changing a field
access expression like `foo.z` into `foo.kind`. In order to do this, it
copies the node `foo.z` and sets the field name in the node to the
symbol `kind`. But when copying the node, the type of the original
`foo.z` is retained. This means that the complement is performed on the
type of the accessed field rather than the type of the discriminator,
which causes problems when the accessed field is also an enum.

To fix this, we properly set the type of the copied node to the type of
the kind field. An alternative is just to make a new node instead.

A lot of text for a single line change, I know, but this part of the
codebase could use more explanation.

(cherry picked from commit 1bebc236bd)
2025-01-14 07:35:24 +01:00
metagn
bf45efb1ea use /link before each library linker option on MSVC (#24291)
fixes #24087, refs https://forum.nim-lang.org/t/341, refs #14222, refs
#14221

The Nim compiler calls `cl` for linking as well as compilation. This
means that options to the linker have to be passed after a `/link`
argument. But the Nim compiler doesn't include this option normally,
because users may still want to pass non-linker options to `cl` at link
time.

To deal with this, a workaround is used: every single library link
option adds `/link` before it. The linker simply ignores extraneous
`/link` arguments and gives a warning instead, since it's an
unrecognized option to the linker. This is really hacky but otherwise we
need to separate linker arguments into arguments passed either to the
compiler or to the linker at link time, and this behavior wouldn't be
meaningful outside of MSVC.

I can't really test this manually but I did test that the linker ignores
`/link`. I also can't really do more than this, I don't really use MSVC
so I wouldn't know how to navigate it, or how people use it. Ideally
someone who knows more about/uses MSVC can give their input or take
over.

(cherry picked from commit 449106a5a4)
2025-01-14 07:35:19 +01:00
metagn
517a2fc275 add tables.getOrDefault param name change to changelog (#24271)
refs
https://github.com/nim-lang/Nim/issues/23587#issuecomment-2404406187

(cherry picked from commit bb0006598d)
2025-01-14 07:35:11 +01:00
Miran
4c56f9d675 make package testing faster (#24284)
There's no need to run benchmarks for cow- and sso-strings: they take 15
minutes each to run.

(cherry picked from commit f5cb39289b)
2025-01-14 07:34:56 +01:00
Juan M Gómez
de93f82d6e Bumps nimble to v0.16.2 (#24283)
(cherry picked from commit af23bc2941)
2025-01-14 07:34:39 +01:00
metagn
fa1819eb2d make linter use lineinfo to check originating package (#24270)
fixes #24269, refs #20095

Instead of checking the package of the *used sym* to determine whether a
stylecheck should trigger, we check the package of the lineinfo instead.
Before #20095 this checked for the current compilation context module
instead which caused issues with generic procs, but the lineinfo should
more closely match the AST.

I figured this might cause issues with includes etc but the foreign
package test specifically tests for an include and passes, so maybe the
package determining logic accounts for this already. This still might
not be the correct logic, I'm not too familiar with the package handling
in the compiler.

Package PRs, both merged:

- json_rpc: https://github.com/status-im/nim-json-rpc/pull/226
- json_serialization:
https://github.com/status-im/nim-json-serialization/pull/99

(cherry picked from commit aaf6c408c6)
2025-01-14 07:34:32 +01:00
metagn
0fde5a0cc2 use case instead of set of int in osproc (#24277)
As said in the warning after #21659, a set of ints defaults to
`set[range[0..65535]]` which is very large. So in osproc, a `case`
statement is used instead of an int set to check for an int being one of
2 values.

Also tested all of CI with the warning from #21659 as an error, this
seems to be the only remaining case in CI.

(cherry picked from commit 706985997e)
2025-01-14 07:34:23 +01:00
metagn
090139eb6f fix deref/addr pair deleting assignment location in C++ (#24280)
fixes #24274

The code in the `if` branch replaces the current destination `d` with a
new one. But the location `d` can be an assignment location, in which
case the provided expression isn't generated. To fix this, don't trigger
this code for when the location already exists. An alternative would be
to call `putIntoDest` in this case as is done below.

(cherry picked from commit 9c85f4fd07)
2025-01-14 07:34:03 +01:00
Miran
ee4bf757ea test more Status' packages, refs #24266 (#24275)
This adds several new Status packages to the CIs:

- confutils
- eth
- metrics
- nat_traversal
- toml_serialization

Other packages mentioned in https://github.com/nim-lang/Nim/issues/24266
are currently not ready to test with `devel` for various reasons.

----

This also enables `criterion`, and removes other packages that had been
in the `allowFailure` category — even without them we have plenty of
packages (145) that we test, there's no point in spending CI time on
them just to see them fail every time.
If/when the authors of those packages make them work with Nim devel, we
can re-introduce them then.

(cherry picked from commit 274762638f)
2025-01-14 07:33:52 +01:00
dlesnoff
b0b4b498c8 std/math: Add ^ overload for float32 and float64 (#20898)
I have added a new overload of `^` for float exponents.
Is two overloads for `float32` and `float64` better than just one
overload with `SomeFloat` type ?
I guess this would not work with `SomeFloat`, as `pow` is not defined
for `float`.

Another remark. Maybe we should catch exponents with 0.5 and call `sqrt`
instead ?

---------

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
Co-authored-by: metagn <metagngn@gmail.com>
(cherry picked from commit e9a4d096ab)
2025-01-14 07:33:42 +01:00
metagn
d102571d78 don't allow instantiations resolving to generic body types (#24273)
fixes #24091, refs #24092

Any instantiations resolving to a generic body type now gives an error.
Due to #24092, this does not error in cases like matching against `type
M` in generics because generic body type symbols are just not
instantiated. But this prevents parameters with type `type M` from being
used, although there doesn't seem to be any code which does this. Just
in case such code exists, we still allow `typedesc` types resolving to
generic body types.

(cherry picked from commit 2f904535d0)
2025-01-14 07:33:27 +01:00
metagn
1f418de2cc fix workaround for protobuf not installing combparser fork in CI (#24267)
fixes CI after #24265, the CI passed in the original PR somehow

(cherry picked from commit 96d6eee9bc)
2025-01-14 07:33:20 +01:00
metagn
21bdc8ff0f remove conflicting default call in tables.getOrDefault (#24265)
fixes #23587

As explained in the issue, `getOrDefault` has a parameter named
`default` that can be a proc after generic instantiation. But the
parameter having a proc type [overrides all other
overloads](f73e03b132/compiler/semexprs.nim (L1203))
including the magic `system.default` overload and causes a compile error
if the proc doesn't match the normal use of `default`. To fix this, the
`result = default(B)` initializer call is removed because it's not
needed, `result` is always set in `getOrDefaultImpl` when a default
value is provided.

This is still a suspicious behavior of the compiler but `tables` working
has a higher priority.

(cherry picked from commit 67ea754b7f)
2025-01-14 07:33:10 +01:00
ringabout
9f7b664836 documentation and comments use HTTPS when possible (#24264)
(cherry picked from commit 95a7695810)
2025-01-14 07:33:01 +01:00
ringabout
b24f58183d fixes obsolete documentations about the JS backend (#24263)
ref https://github.com/nim-lang/Nim/pull/21849
ref https://github.com/nim-lang/Nim/pull/21613

(cherry picked from commit f73e03b132)
2025-01-14 07:32:55 +01:00
metagn
b8efee444c process non-language pragma nodes in generics (#24254)
fixes #18649, refs #24183

Same as in #24183 for templates, we now process pragma nodes in generics
so that macro symbols are captured and the pragma arguments are checked,
but ignoring language pragma keywords.

A difference is that we cannot process call nodes as is, we have to
process their children individually so that the early untyped
macro/template instantiation in generics does not kick in.

(cherry picked from commit d72b848d17)
2025-01-14 07:32:47 +01:00
Tomohiro
336549c49d Change how to multiply 1.5 to ints to reduce overflow (#24257)
(cherry picked from commit d6633ae1da)
2025-01-14 07:32:40 +01:00
ringabout
2d4e1f981e improves the 2.2.0 changelog (#24256)
(cherry picked from commit 30e552e3d3)
2025-01-14 07:32:27 +01:00
metagn
13110fc5d3 give int literals matched type on generic match (#24234)
fixes #24233

Integer literals with type `int` can match `int64` with a generic match.
Normally this would generate an conversion via `isFromIntLit`, but when
it matches with a generic match (`isGeneric`) the node is left alone and
continues to have type `int` (related to #4858, but separate; since
`isFromIntLit > isGeneric` it doesn't propagate). This did not cause
problems on the C backend up to this point because either the compiler
generated a cast when generating the C code or it was implicitly casted
in the C code itself. On the JS backend however, we need to generate
`int64` and `int` values differently, so we copy the integer literal and
give it the matched type now instead.

This is somewhat risky even if CI passes but it's required to make the
times module work without [this
workaround](7dfadb8b4e/lib/pure/times.nim (L219-L238))
on `--jsbigint64:on` (the default).

CI exposed an issue: When matching an int literal to a generic parameter
in a generic instantiation, the literal is only treated like a value if
it has `int literal` type, but if it has the type `int`, it gets
transformed into literally the type `int` (#12664, #13906), which breaks
the tests t14193 and t12938. To deal with this, we don't give it the
type `int` if we are in a generic instantiation and preserve the `int
literal` type.

(cherry picked from commit c73eedfe6e)
2025-01-14 07:32:18 +01:00
metagn
700ca2eb60 process non-language pragma nodes in templates (#24183)
fixes #24186

When encountering pragma nodes in templates, if it's a language pragma,
we don't process the name, and only any values if they exist. If it's
not a language pragma, we process the full node. Previously only the
values of colon expressions were processed.

To make this simpler, `whichPragma` is patched to consider bracketed
hint/warning etc pragmas like `{.hint[HintName]: off.}` as being a
pragma of kind `wHint` rather than an invalid pragma which would have to
be checked separately. From looking at the uses of `whichPragma` this
doesn't seem like it would cause problems.

Generics have [the same
problem](a27542195c/compiler/semgnrc.nim (L619))
(causing #18649), but to make it work we need to make sure the
templates/macros don't get evaluated or get evaluated correctly (i.e.
passing the proc node as the final argument), either with #23094 or by
completely disabling template/macro evaluation when processing the
pragma node, which would also cover `{.pragma.}` templates.

(cherry picked from commit 911cef1621)
2025-01-14 07:32:12 +01:00
metagn
5945ad41a1 reset inTypeofContext in generic instantiations (#24229)
fixes #24228, refs #22022

As described in
https://github.com/nim-lang/Nim/issues/24228#issuecomment-2392462221,
instantiating generic routines inside `typeof` causes all code inside to
be treated as being in a typeof context, and thus preventing compile
time proc folding, causing issues when code is generated for the
instantiated routine. Now, instantiated generic procs are treated as
never being inside a `typeof` context.

This is probably an arbitrary special case and more issues with the
`typeof` behavior from #22022 are likely. Ideally this behavior would be
removed but it's necessary to accomodate the current [proc `declval` in
the package `stew`](https://github.com/status-im/nim-stew/pull/190), at
least without changes to `compileTime` that would either break other
code (making it not eagerly fold by default) or still require a change
in stew (adding an option to disable the eager folding).

Alternatively we could also make the eager folding opt-in only for
generic compileTime procs so that #22022 breaks nothing whatsoever, but
a universal solution would be better. Edit: Done in #24230 via
experimental switch

(cherry picked from commit ea9811a4d2)
2025-01-14 07:31:57 +01:00
Andreas Rumpf
7f113dc875 exports more helpers that are needed by nif-gear2 (#24247)
(cherry picked from commit 7f2e6a1359)
2025-01-14 07:31:51 +01:00
ringabout
e13f86a596 enable nimExperimentalLinenoiseExtra (#24227)
follow up https://github.com/nim-lang/Nim/pull/16977

it was added in 1.6.0

(cherry picked from commit a65501325c)
2025-01-14 07:31:40 +01:00
metagn
6c96892d5e refactor to make sigmatch use LayeredIdTable for bindings (#24216)
split from #24198

This is a required refactor for the only good solution I've been able to
think of for #4858 etc. Explanation:

---

`sigmatch` currently [disables
bindings](d6a71a1067/compiler/sigmatch.nim (L1956))
(except for binding to other generic parameters) when matching against
constraints of generic parameters. This is so when the constraint is a
general metatype like `seq`, the type matching will not treat all
following uses of `seq` as the type matched against that generic
parameter.

However to solve #4858 etc we need to bind `or` types with a conversion
match to the type they are supposed to be converted to (i.e. matching
`int literal(123)` against `int8 | int16` should bind `int8`[^1], not
`int`). The generic parameter constraint binding needs some way to keep
track of this so that matching `int literal(123)` against `T: int8 |
int16` also binds `T` to `int8`[^1].

The only good way to do this IMO is to generate a new "binding context"
when matching against constraints, then binding the generic param to
what the constraint was bound to in that context (in #24198 this is
restricted to just `or` types & concrete types with convertible matches,
it doesn't work in general).

---

`semtypinst` already does something similar for bindings of generic
invocations using `LayeredIdTable`, so `LayeredIdTable` is now split
into its own module and used in `sigmatch` for type bindings as well,
rather than a single-layer `TypeMapping`. Other modules which act on
`sigmatch`'s binding map are also updated to use this type instead.

The type is also made into an `object` type rather than a `ref object`
to reduce the pointer indirection when embedding it inside
`TCandidate`/`TReplTypeVars`, but only on arc/orc since there are some
weird aliasing bugs on refc/markAndSweep that cause a segfault when
setting a layer to its previous layer. If we want we can also just
remove the conditional compilation altogether and always use `ref
object` at the cost of some performance.

[^1]: `int8` binding here and not `int16` might seem weird, since they
match equally well. But we need to resolve the ambiguity here, in #24012
I tested disallowing ambiguities like this and it broke many packages
that tries to match int literals to things like `int16 | uint16` or
`int8 | int16`. Instead of making these packages stop working I think
it's better we resolve the ambiguity with a rule like "the earliest `or`
branch with the best match, matches". This is the rule used in #24198.

(cherry picked from commit cad8726907)
2025-01-14 07:31:33 +01:00
ringabout
dd0cc389bb -d:nimPreviewFloatRoundtrip becomes the default (#24217)
(cherry picked from commit aa605da92a)
2025-01-14 07:31:27 +01:00
metagn
75e50f804a delay markUsed for converters until call is resolved (#24243)
fixes #24241

(cherry picked from commit 09043f409f)
2025-01-14 07:31:22 +01:00
metagn
599f1ad6b3 make new concepts match themselves (#24244)
fixes #22839

(cherry picked from commit 9e30b39412)
2025-01-14 07:31:14 +01:00
metagn
d991600a00 update CI to macos 13 (#24157)
Followup to #24154, packages aren't ready for macos 14 (M1/ARM CPU) yet
and it seems to be preview on azure, so upgrade to macos 13 for now.

Macos 12 gives a warning:

```
You are using macOS 12.
We (and Apple) do not provide support for this old version.
It is expected behaviour that some formulae will fail to build in this old version.
It is expected behaviour that Homebrew will be buggy and slow.
Do not create any issues about this on Homebrew's GitHub repositories.
Do not create any issues even if you think this message is unrelated.
Any opened issues will be immediately closed without response.
Do not ask for help from Homebrew or its maintainers on social media.
You may ask for help in Homebrew's discussions but are unlikely to receive a response.
Try to figure out the problem yourself and submit a fix as a pull request.
We will review it but may or may not accept it.
```

(cherry picked from commit 4a63186cda)
2025-01-14 07:30:58 +01:00
tersec
b873eaedf5 update minimum recommended gcc version and fix manual typos (#24240)
ref https://github.com/nim-lang/Nim/issues/24235

(cherry picked from commit 782b75cc08)
2025-01-14 07:30:43 +01:00
Alex
39a6106e8b Update sequtils.nim authors (#24238)
Hello, I am the original developer credited in this file.

I no longer wish to be credited for the it so I've updated it to say
"Nim Contributors".

This is a quick edit from the GitHub Web UI so let me know if I need to
make any changes to get this merged.

Thank you.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit f420a5a273)
2025-01-14 07:30:33 +01:00
metagn
e262d9506d stricter set type match, implicit conversion for literals (#24176)
fixes #18396, fixes #20142

Set types with base types matching less than a generic match (so
subrange matches, conversion matches, int conversion matches) are now
considered mismatching, as their representation is different on the
backends (except VM and JS), causing codegen issues. An exception is
granted for set literal types, which now implicitly convert each element
to the matched base type, so things like `s == {'a', 'b'}` are still
possible where `s` is `set[range['a'..'z']]`. Also every conversion
match in this case is unified under the normal "conversion" match, so a
literal doesn't match one set type better than the other, unless it's
equal.

However `{'a', 'b'} == s` or `{'a', 'b'} - s` etc is now not possible.
when it used to work in the VM. So this is somewhat breaking, and needs
a changelog entry.

(cherry picked from commit 7dfadb8b4e)
2025-01-14 07:30:25 +01:00
metagn
ddc7f35e05 don't typecheck untyped + allow void typed template param default values (#24219)
Previously, the compiler never differentiated between `untyped`/`typed`
argument default values and other types, it considered any parameter
with a type as typed and called `semExprWithType`, which both
typechecked it and disallowed `void` expressions. Now, we perform no
typechecking at all on `untyped` template param default values, and call
`semExpr` instead for `typed` params, which allows expressions with
`void` type.

(cherry picked from commit 4eed341ba5)
2025-01-14 07:30:19 +01:00
metagn
f70a17f885 don't construct array type for already typed nkBracket node (#24224)
fixes #23010, split from #24195

When resemming bracket nodes, the compiler currently unconditionally
makes a new node with an array type based on the node. However the VM
can generate bracket nodes with `seq` types, which this erases. To fix
this, if a bracket node already has a type, we still resem the bracket
node, but don't construct a new type for it, instead using the type of
the original node.

A version of this was rejected that didn't resem the node at all if it
was typed, but I can't find it. The difference with this one is that the
individual elements are still resemmed.

This should fix the break caused by #24184 so we could redo it after
this PR but it might still have issues, not to mention the related
pre-existing issues like #22793, #12559 etc.

(cherry picked from commit d98ef312f0)
2025-01-14 07:30:06 +01:00
Miran
7a79f465fa bump NimVersion to 2.2.1 (#24215)
(cherry picked from commit d6a71a1067)
2025-01-14 07:28:14 +01:00
ringabout
b6450a98ea improve error messages for illegalCapture (#24214)
ref https://forum.nim-lang.org/t/12536

Use a general recommendation to avoid some weird error messages like
`<ref ref var Test>` etc.

(cherry picked from commit f7cb0322c2)
2025-01-14 07:28:10 +01:00
123 changed files with 3157 additions and 6040 deletions

121
compiler/cbuilder.nim Normal file
View File

@@ -0,0 +1,121 @@
type
Snippet = string
Builder = string
template newBuilder(s: string): Builder =
s
proc addField(obj: var Builder; name, typ: Snippet) =
obj.add('\t')
obj.add(typ)
obj.add(" ")
obj.add(name)
obj.add(";\n")
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) =
obj.add('\t')
if field.alignment > 0:
obj.add("NIM_ALIGN(")
obj.addInt(field.alignment)
obj.add(") ")
obj.add(typ)
if sfNoalias in field.flags:
obj.add(" NIM_NOALIAS")
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if field.bitsize != 0:
obj.add(":")
obj.addInt(field.bitsize)
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc structOrUnion(t: PType): Snippet =
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
proc ptrType(t: Snippet): Snippet =
t & "*"
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) =
if tfPacked in typ.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add(structOrUnion(typ))
obj.add(" __attribute__((__packed__))")
else:
obj.add("#pragma pack(push, 1)\n")
obj.add(structOrUnion(typ))
else:
obj.add(structOrUnion(typ))
obj.add(" ")
obj.add(name)
type BaseClassKind = enum
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
var baseKind = bcNone
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
baseKind = bcNone
elif optTinyRtti in m.config.globalOptions:
baseKind = bcNoneTinyRtti
else:
baseKind = bcNoneRtti
elif m.compileToCpp:
baseKind = bcCppInherit
else:
baseKind = bcSupField
if baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
let currLen = obj.len
case baseKind
of bcNone:
# rest of the options add a field or don't need it due to inheritance,
# we need to add the dummy field for uncheckedarray ahead of time
# so that it remains trailing
if typ.itemId notin m.g.graph.memberProcsPerType and
typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and
typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
# only consists of flexible array field, add *initial* dummy field
obj.addField(name = "dummy", typ = "char")
of bcCppInherit: discard
of bcNoneRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
of bcNoneTinyRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
of bcSupField:
obj.addField(name = "Sup", typ = baseType)
body
if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")
obj.add("};\n")
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add("#pragma pack(pop)\n")
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
## adds a field with a `struct { ... }` type, building it according to `body`
obj.add('\t')
if tfPacked in parentTyp.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add("struct __attribute__((__packed__)) {\n")
else:
obj.add("#pragma pack(push, 1)\nstruct {")
else:
obj.add("struct {\n")
body
obj.add("} ")
obj.add(fieldName)
obj.add(";\n")
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add("#pragma pack(pop)\n")
template addAnonUnion(obj: var Builder; body: typed) =
obj.add "union{\n"
body
obj.add("};\n")

View File

@@ -1,164 +0,0 @@
import ropes, int128
type
Snippet* = string
Builder* = object
buf*: string
indents*: int
template newBuilder*(s: string): Builder =
Builder(buf: s)
proc extract*(builder: Builder): Snippet =
builder.buf
proc add*(builder: var Builder, s: string) =
builder.buf.add(s)
proc add*(builder: var Builder, s: char) =
builder.buf.add(s)
proc addNewline*(builder: var Builder) =
builder.add('\n')
for i in 0 ..< builder.indents:
builder.add('\t')
proc addLineEnd*(builder: var Builder, s: string) =
builder.add(s)
builder.addNewline()
proc addLineEndIndent*(builder: var Builder, s: string) =
inc builder.indents
builder.add(s)
builder.addNewline()
proc addDedent*(builder: var Builder, s: string) =
if builder.buf.len > 0 and builder.buf[^1] == '\t':
builder.buf.setLen(builder.buf.len - 1)
builder.add(s)
dec builder.indents
proc addLineEndDedent*(builder: var Builder, s: string) =
builder.addDedent(s)
builder.addNewline()
proc addLineComment*(builder: var Builder, comment: string) =
# probably no-op on nifc
builder.add("// ")
builder.add(comment)
builder.addNewline()
proc addIntValue*(builder: var Builder, val: int) =
builder.buf.addInt(val)
proc addIntValue*(builder: var Builder, val: int64) =
builder.buf.addInt(val)
proc addIntValue*(builder: var Builder, val: uint64) =
builder.buf.addInt(val)
proc addIntValue*(builder: var Builder, val: Int128) =
builder.buf.addInt128(val)
template cIntValue*(val: int): Snippet = $val
template cIntValue*(val: int64): Snippet = $val
template cIntValue*(val: uint64): Snippet = $val
template cIntValue*(val: Int128): Snippet = $val
template cUintValue*(val: uint): Snippet = $val & "U"
import std/formatfloat
proc addFloatValue*(builder: var Builder, val: float) =
builder.buf.addFloat(val)
template cFloatValue*(val: float): Snippet = $val
proc addInt64Literal*(result: var Builder; i: BiggestInt) =
if i > low(int64):
result.add "IL64($1)" % [rope(i)]
else:
result.add "(IL64(-9223372036854775807) - IL64(1))"
proc addUint64Literal*(result: var Builder; i: uint64) =
result.add rope($i & "ULL")
proc addIntLiteral*(result: var Builder; i: BiggestInt) =
if i > low(int32) and i <= high(int32):
result.addIntValue(i)
elif i == low(int32):
# Nim has the same bug for the same reasons :-)
result.add "(-2147483647 -1)"
elif i > low(int64):
result.add "IL64($1)" % [rope(i)]
else:
result.add "(IL64(-9223372036854775807) - IL64(1))"
proc addIntLiteral*(result: var Builder; i: Int128) =
addIntLiteral(result, toInt64(i))
proc cInt64Literal*(i: BiggestInt): Snippet =
if i > low(int64):
result = "IL64($1)" % [rope(i)]
else:
result = "(IL64(-9223372036854775807) - IL64(1))"
proc cUint64Literal*(i: uint64): Snippet =
result = $i & "ULL"
proc cIntLiteral*(i: BiggestInt): Snippet =
if i > low(int32) and i <= high(int32):
result = rope(i)
elif i == low(int32):
# Nim has the same bug for the same reasons :-)
result = "(-2147483647 -1)"
elif i > low(int64):
result = "IL64($1)" % [rope(i)]
else:
result = "(IL64(-9223372036854775807) - IL64(1))"
proc cIntLiteral*(i: Int128): Snippet =
result = cIntLiteral(toInt64(i))
const
NimInt* = "NI"
NimInt8* = "NI8"
NimInt16* = "NI16"
NimInt32* = "NI32"
NimInt64* = "NI64"
CInt* = "int"
NimUint* = "NU"
NimUint8* = "NU8"
NimUint16* = "NU16"
NimUint32* = "NU32"
NimUint64* = "NU64"
NimFloat* = "NF"
NimFloat32* = "NF32"
NimFloat64* = "NF64"
NimFloat128* = "NF128" # not actually defined
NimNan* = "NAN"
NimInf* = "INF"
NimBool* = "NIM_BOOL"
NimTrue* = "NIM_TRUE"
NimFalse* = "NIM_FALSE"
NimChar* = "NIM_CHAR"
CChar* = "char"
NimCstring* = "NCSTRING"
NimNil* = "NIM_NIL"
CNil* = "NULL"
NimStrlitFlag* = "NIM_STRLIT_FLAG"
CVoid* = "void"
CPointer* = "void*"
CConstPointer* = "NIM_CONST void*"
proc cIntType*(bits: BiggestInt): Snippet =
"NI" & $bits
proc cUintType*(bits: BiggestInt): Snippet =
"NU" & $bits
type
IfBuilderState* = enum
WaitingIf, WaitingElseIf, InBlock
IfBuilder* = object
state*: IfBuilderState

View File

@@ -1,668 +0,0 @@
type VarKind = enum
Local
Global
Threadvar
Const
AlwaysConst ## const even on C++
proc addVarHeader(builder: var Builder, kind: VarKind) =
## adds modifiers for given var kind:
## Local has no modifier
## Global has `static` modifier
## Const has `static NIM_CONST` modifier
## AlwaysConst has `static const` modifier (NIM_CONST is no-op on C++)
## Threadvar is unimplemented
case kind
of Local: discard
of Global:
builder.add("static ")
of Const:
builder.add("static NIM_CONST ")
of AlwaysConst:
builder.add("static const ")
of Threadvar:
doAssert false, "unimplemented"
proc addVar(builder: var Builder, kind: VarKind = Local, name: string, typ: Snippet, initializer: Snippet = "") =
## adds a variable declaration to the builder
builder.addVarHeader(kind)
builder.add(typ)
builder.add(" ")
builder.add(name)
if initializer.len != 0:
builder.add(" = ")
builder.add(initializer)
builder.addLineEnd(";")
template addVarWithType(builder: var Builder, kind: VarKind = Local, name: string, body: typed) =
## adds a variable declaration to the builder, with the `body` building the type
builder.addVarHeader(kind)
body
builder.add(" ")
builder.add(name)
builder.addLineEnd(";")
template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
typ: Snippet, initializerBody: typed) =
## adds a variable declaration to the builder, with
## `initializerBody` building the initializer. initializer must be provided
builder.addVarHeader(kind)
builder.add(typ)
builder.add(" ")
builder.add(name)
builder.add(" = ")
initializerBody
builder.addLineEnd(";")
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
typeBody, initializerBody: typed) =
## adds a variable declaration to the builder, with `typeBody` building the type, and
## `initializerBody` building the initializer. initializer must be provided
builder.addVarHeader(kind)
typeBody
builder.add(" ")
builder.add(name)
builder.add(" = ")
initializerBody
builder.addLineEnd(";")
proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, initializer: Snippet = "") =
## adds an array variable declaration to the builder
builder.addVarHeader(kind)
builder.add(elementType)
builder.add(" ")
builder.add(name)
builder.add("[")
builder.addIntValue(len)
builder.add("]")
if initializer.len != 0:
builder.add(" = ")
builder.add(initializer)
builder.addLineEnd(";")
template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, body: typed) =
## adds an array variable declaration to the builder with the initializer built according to `body`
builder.addVarHeader(kind)
builder.add(elementType)
builder.add(" ")
builder.add(name)
builder.add("[")
builder.addIntValue(len)
builder.add("] = ")
body
builder.addLineEnd(";")
template addTypedef(builder: var Builder, name: string, typeBody: typed) =
## adds a typedef declaration to the builder with name `name` and type as
## built in `typeBody`
builder.add("typedef ")
typeBody
builder.add(" ")
builder.add(name)
builder.addLineEnd(";")
proc addProcTypedef(builder: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
builder.add("typedef ")
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)
builder.addLineEnd(";")
template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, typeBody: typed) =
## adds an array typedef declaration to the builder with name `name`,
## length `len`, and element type as built in `typeBody`
builder.add("typedef ")
typeBody
builder.add(" ")
builder.add(name)
builder.add("[")
builder.addIntValue(len)
builder.addLineEnd("];")
type
StructInitializerKind = enum
siOrderedStruct ## struct constructor, but without named fields on C
siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer
siArray ## array constructor
siWrapper ## wrapper for a single field, generates it verbatim
StructInitializer = object
## context for building struct initializers, i.e. `{ field1, field2 }`
kind: StructInitializerKind
## if true, fields will not be named, instead values are placed in order
needsComma: bool
proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer =
## starts building a struct initializer, i.e. braced initializer list
result = StructInitializer(kind: kind, needsComma: false)
if kind != siWrapper:
builder.add("{")
template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) =
## adds a field to a struct initializer, with the value built in `valueBody`
if constr.needsComma:
assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields"
builder.add(", ")
else:
constr.needsComma = true
case constr.kind
of siArray, siWrapper:
# no name, can just add value
valueBody
of siOrderedStruct:
# no name, can just add value on C
assert name.len != 0, "name has to be given for struct initializer field"
valueBody
of siNamedStruct:
assert name.len != 0, "name has to be given for struct initializer field"
builder.add(".")
builder.add(name)
builder.add(" = ")
valueBody
proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =
## finishes building a struct initializer
if constr.kind != siWrapper:
builder.add("}")
template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) =
## builds a struct initializer, i.e. `{ field1, field2 }`
## a `var StructInitializer` must be declared and passed as a parameter so
## that it can be used with `addField`
constr = builder.initStructInitializer(kind)
body
builder.finishStructInitializer(constr)
proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
## adds a field inside a struct/union type
obj.add('\t')
obj.add(typ)
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initializer: Snippet = "") =
## adds an array field inside a struct/union type
obj.add('\t')
obj.add(elementType)
obj.add(" ")
obj.add(name)
obj.add("[")
obj.addIntValue(len)
obj.add("]")
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
## adds an field inside a struct/union type, based on an `skField` symbol
obj.add('\t')
if field.alignment > 0:
obj.add("NIM_ALIGN(")
obj.addIntValue(field.alignment)
obj.add(") ")
obj.add(typ)
if sfNoalias in field.flags:
obj.add(" NIM_NOALIAS")
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if field.bitsize != 0:
obj.add(":")
obj.addIntValue(field.bitsize)
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc addProcField(obj: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
obj.add(CallingConvToStr[callConv])
obj.add("_PTR(")
obj.add(rettype)
obj.add(", ")
obj.add(name)
obj.add(")")
obj.add(params)
obj.add(";\n")
type
BaseClassKind = enum
## denotes how and whether or not the base class/RTTI should be stored
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
StructBuilderInfo = object
## context for building `struct` types
baseKind: BaseClassKind
named: bool
preFieldsLen: int
proc structOrUnion(t: PType): Snippet =
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
obj.add("struct")
if result.named:
obj.add(" ")
obj.add(name)
if baseType.len != 0:
if m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
if result.baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.buf.len
if result.baseKind == bcSupField:
obj.addField(name = "Sup", typ = baseType)
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = CChar)
if info.named:
obj.add("};\n")
else:
obj.add("}")
template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
## builds a struct type not based on a Nim type with fields according to `body`,
## `name` can be empty to build as a type expression and not a statement
let info = startSimpleStruct(obj, m, name, baseType)
body
finishSimpleStruct(obj, m, info)
proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
if tfPacked in t.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add(structOrUnion(t))
obj.add(" __attribute__((__packed__))")
else:
obj.add("#pragma pack(push, 1)\n")
obj.add(structOrUnion(t))
else:
obj.add(structOrUnion(t))
if result.named:
obj.add(" ")
obj.add(name)
if t.kind == tyObject:
if t.baseClass == nil:
if lacksMTypeField(t):
result.baseKind = bcNone
elif optTinyRtti in m.config.globalOptions:
result.baseKind = bcNoneTinyRtti
else:
result.baseKind = bcNoneRtti
elif m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
elif baseType.len != 0:
if m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
if result.baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.buf.len
case result.baseKind
of bcNone:
# rest of the options add a field or don't need it due to inheritance,
# we need to add the dummy field for uncheckedarray ahead of time
# so that it remains trailing
if t.itemId notin m.g.graph.memberProcsPerType and
t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
# only consists of flexible array field, add *initial* dummy field
obj.addField(name = "dummy", typ = CChar)
of bcCppInherit: discard
of bcNoneRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
of bcNoneTinyRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
of bcSupField:
obj.addField(name = "Sup", typ = baseType)
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
t.itemId notin m.g.graph.memberProcsPerType:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = CChar)
if info.named:
obj.add("};\n")
else:
obj.add("}")
if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
obj.add("#pragma pack(pop)\n")
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
## builds a struct type directly based on `typ` with fields according to `body`,
## `name` can be empty to build as a type expression and not a statement
let info = startStruct(obj, m, typ, name, baseType)
body
finishStruct(obj, m, typ, info)
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
## adds a field with a `struct { ... }` type, building the fields according to `body`
obj.add('\t')
if tfPacked in parentTyp.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add("struct __attribute__((__packed__)) {\n")
else:
obj.add("#pragma pack(push, 1)\nstruct {")
else:
obj.add("struct {\n")
body
obj.add("} ")
obj.add(fieldName)
obj.add(";\n")
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
obj.add("#pragma pack(pop)\n")
template addAnonUnion(obj: var Builder; body: typed) =
## adds an anonymous union i.e. `union { ... };` with fields according to `body`
obj.add "union{\n"
body
obj.add("};\n")
template addUnionType(obj: var Builder; body: typed) =
## adds a union type i.e. `union { ... }` with fields according to `body`
obj.add "union{\n"
body
obj.add("}")
type DeclVisibility = enum
None
Extern
ExternC
ImportLib
ExportLib
ExportLibVar
Private
StaticProc
proc addVisibilityPrefix(builder: var Builder, visibility: DeclVisibility) =
# internal proc
case visibility
of None: discard
of Extern:
builder.add("extern ")
of ExternC:
builder.add("NIM_EXTERNC ")
of ImportLib:
builder.add("N_LIB_IMPORT ")
of ExportLib:
builder.add("N_LIB_EXPORT ")
of ExportLibVar:
builder.add("N_LIB_EXPORT_VAR ")
of Private:
builder.add("N_LIB_PRIVATE ")
of StaticProc:
builder.add("static ")
template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
## adds a declaration as in `declBody` with the given visibility
builder.addVisibilityPrefix(visibility)
declBody
type ProcParamBuilder = object
needsComma: bool
proc initProcParamBuilder(builder: var Builder): ProcParamBuilder =
result = ProcParamBuilder(needsComma: false)
builder.add("(")
proc finishProcParamBuilder(builder: var Builder, params: ProcParamBuilder) =
if params.needsComma:
builder.add(")")
else:
builder.add("void)")
template cgDeclFrmt*(s: PSym): string =
s.constraint.strVal
proc addParam(builder: var Builder, params: var ProcParamBuilder, name: string, typ: Snippet) =
if params.needsComma:
builder.add(", ")
else:
params.needsComma = true
builder.add(typ)
builder.add(" ")
builder.add(name)
proc addParam(builder: var Builder, params: var ProcParamBuilder, param: PSym, typ: Snippet) =
if params.needsComma:
builder.add(", ")
else:
params.needsComma = true
var modifiedTyp = typ
if sfNoalias in param.flags:
modifiedTyp.add(" NIM_NOALIAS")
if sfCodegenDecl notin param.flags:
builder.add(modifiedTyp)
builder.add(" ")
builder.add(param.loc.snippet)
else:
builder.add runtimeFormat(param.cgDeclFrmt, [modifiedTyp, param.loc.snippet])
proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Snippet) =
if params.needsComma:
builder.add(", ")
else:
params.needsComma = true
builder.add(typ)
proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
if paramBuilder.needsComma:
builder.add(", ")
else:
paramBuilder.needsComma = true
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)
proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
# does not exist in NIFC, needs to be proc pragma
if params.needsComma:
builder.add(", ")
else:
params.needsComma = true
builder.add("...")
template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: typed) =
params = initProcParamBuilder(builder)
body
finishProcParamBuilder(builder, params)
type SimpleProcParam = tuple
name, typ: string
proc cProcParams(params: varargs[SimpleProcParam]): Snippet =
if params.len == 0: return "(void)"
result = "("
for i in 0 ..< params.len:
if i != 0: result.add(", ")
result.add(params[i].typ)
if params[i].name.len != 0:
result.add(" ")
result.add(params[i].name)
result.add(")")
template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
name: string, rettype: Snippet, paramBuilder: typed) =
# on nifc should build something like (proc name params type pragmas
# with no body given
# or enforce this with secondary builder object
builder.add(CallingConvToStr[callConv])
builder.add("(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
paramBuilder
proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
name: string, rettype, params: Snippet) =
# on nifc should build something like (proc name params type pragmas
# with no body given
# or enforce this with secondary builder object
addProcHeaderWithParams(builder, callConv, name, rettype):
builder.add(params)
proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) =
# no callconv
builder.add(rettype)
builder.add(" ")
if isConstructor:
builder.add("__attribute__((constructor)) ")
builder.add(name)
builder.add(params)
proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
# on nifc should build something like (proc name params type pragmas
# with no body given
# or enforce this with secondary builder object
let noreturn = isNoReturn(m, prc)
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
builder.add("__declspec(naked) ")
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
builder.add("__declspec(noreturn) ")
builder.add(CallingConvToStr[prc.typ.callConv])
builder.add("(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)
if addAttributes:
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
builder.add(" __attribute__((naked))")
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
builder.add(" __attribute__((noreturn))")
proc finishProcHeaderAsProto(builder: var Builder) =
builder.addLineEnd(";")
template finishProcHeaderWithBody(builder: var Builder, body: typed) =
builder.addLineEndIndent(" {")
body
builder.addLineEndDedent("}")
builder.addNewline
proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet,
isStatic = false, ignoreAttributes = false) =
# on nifc, builds full variable
if isStatic:
builder.add("static ")
let noreturn = isNoReturn(m, prc)
if not ignoreAttributes:
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
builder.add("__declspec(naked) ")
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
builder.add("__declspec(noreturn) ")
builder.add(CallingConvToStr[prc.typ.callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)
if not ignoreAttributes:
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
builder.add(" __attribute__((naked))")
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
builder.add(" __attribute__((noreturn))")
# ensure we are just adding a variable:
builder.addLineEnd(";")
proc addProcVar(builder: var Builder, callConv: TCallingConvention,
name: string, params, rettype: Snippet,
isStatic = false, isVolatile = false) =
# on nifc, builds full variable
if isStatic:
builder.add("static ")
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
if isVolatile:
builder.add("volatile ")
builder.add(name)
builder.add(")")
builder.add(params)
# ensure we are just adding a variable:
builder.addLineEnd(";")
proc addProcVar(builder: var Builder,
name: string, params, rettype: Snippet,
isStatic = false, isVolatile = false) =
# no callconv
if isStatic:
builder.add("static ")
builder.add(rettype)
builder.add(" (*")
if isVolatile:
builder.add("volatile ")
builder.add(name)
builder.add(")")
builder.add(params)
# ensure we are just adding a variable:
builder.addLineEnd(";")
type VarInitializerKind = enum
Assignment, CppConstructor
proc addVar(builder: var Builder, m: BModule, s: PSym, name: string, typ: Snippet, kind = Local, visibility: DeclVisibility = None, initializer: Snippet = "", initializerKind: VarInitializerKind = Assignment) =
if sfCodegenDecl in s.flags:
builder.add(runtimeFormat(s.cgDeclFrmt, [typ, name]))
if initializer.len != 0:
if initializerKind == Assignment:
builder.add(" = ")
builder.add(initializer)
builder.addLineEnd(";")
return
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
builder.add("NIM_ALIGN(" & $s.alignment & ") ")
builder.addVisibilityPrefix(visibility)
if kind == Threadvar:
if optThreads in m.config.globalOptions:
let sym = s.typ.sym
if sym != nil and sfCppNonPod in sym.flags:
builder.add("NIM_THREAD_LOCAL ")
else: builder.add("NIM_THREADVAR ")
else:
builder.addVarHeader(kind)
builder.add(typ)
if sfRegister in s.flags: builder.add(" register")
if sfVolatile in s.flags: builder.add(" volatile")
if sfNoalias in s.flags: builder.add(" NIM_NOALIAS")
builder.add(" ")
builder.add(name)
if initializer.len != 0:
if initializerKind == Assignment:
builder.add(" = ")
builder.add(initializer)
builder.addLineEnd(";")
proc addInclude(builder: var Builder, value: Snippet) =
builder.addLineEnd("#include " & value)

View File

@@ -1,259 +0,0 @@
proc constType(t: Snippet): Snippet =
# needs manipulation of `t` in nifc
"NIM_CONST " & t
proc constPtrType(t: Snippet): Snippet =
t & "* NIM_CONST"
proc ptrConstType(t: Snippet): Snippet =
"NIM_CONST " & t & "*"
proc ptrType(t: Snippet): Snippet =
t & "*"
proc cppRefType(t: Snippet): Snippet =
t & "&"
const
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
"N_STDCALL", "N_CDECL", "N_SAFECALL",
"N_SYSCALL", # this is probably not correct for all platforms,
# but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
"N_NOCONV" #ccMember is N_NOCONV
]
proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
rettype & "(*)" & params
proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
rettype & "(N_RAW_NIMCALL*)" & params
proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet =
CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params
type CppCaptureKind = enum None, ByReference, ByCopy
template addCppLambda(builder: var Builder, captures: CppCaptureKind, params: Snippet, body: typed) =
builder.add("[")
case captures
of None: discard
of ByReference: builder.add("&")
of ByCopy: builder.add("=")
builder.add("] ")
builder.add(params)
builder.addLineEndIndent(" {")
body
builder.addLineEndDedent("}")
proc cCast(typ, value: Snippet): Snippet =
"((" & typ & ") " & value & ")"
proc wrapPar(value: Snippet): Snippet =
# used for expression group, no-op on sexp
"(" & value & ")"
proc removeSinglePar(value: Snippet): Snippet =
# removes a single paren layer expected to exist, to silence Wparentheses-equality
assert value[0] == '(' and value[^1] == ')'
value[1..^2]
template addCast(builder: var Builder, typ: Snippet, valueBody: typed) =
## adds a cast to `typ` with value built by `valueBody`
builder.add "(("
builder.add typ
builder.add ") "
valueBody
builder.add ")"
proc cAddr(value: Snippet): Snippet =
"(&" & value & ")"
proc cLabelAddr(value: TLabel): Snippet =
"&&" & value
proc cDeref(value: Snippet): Snippet =
"(*" & value & ")"
proc subscript(a, b: Snippet): Snippet =
a & "[" & b & "]"
proc dotField(a, b: Snippet): Snippet =
a & "." & b
proc derefField(a, b: Snippet): Snippet =
a & "->" & b
type CallBuilder = object
needsComma: bool
proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder =
result = CallBuilder(needsComma: false)
builder.add(callee)
builder.add("(")
const cArgumentSeparator = ", "
proc addArgumentSeparator(builder: var Builder) =
# no-op on NIFC
# used by "single argument" builders
builder.add(cArgumentSeparator)
template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) =
if call.needsComma:
builder.addArgumentSeparator()
else:
call.needsComma = true
valueBody
proc finishCallBuilder(builder: var Builder, call: CallBuilder) =
builder.add(")")
template addCall(builder: var Builder, call: out CallBuilder, callee: Snippet, body: typed) =
call = initCallBuilder(builder, callee)
body
finishCallBuilder(builder, call)
proc addCall(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
builder.add(callee)
builder.add("(")
if args.len != 0:
builder.add(args[0])
for i in 1 ..< args.len:
builder.add(", ")
builder.add(args[i])
builder.add(")")
proc cCall(callee: Snippet, args: varargs[Snippet]): Snippet =
result = callee
result.add("(")
if args.len != 0:
result.add(args[0])
for i in 1 ..< args.len:
result.add(", ")
result.add(args[i])
result.add(")")
proc addSizeof(builder: var Builder, val: Snippet) =
builder.add("sizeof(")
builder.add(val)
builder.add(")")
proc addAlignof(builder: var Builder, val: Snippet) =
builder.add("NIM_ALIGNOF(")
builder.add(val)
builder.add(")")
proc addOffsetof(builder: var Builder, val, member: Snippet) =
builder.add("offsetof(")
builder.add(val)
builder.add(", ")
builder.add(member)
builder.add(")")
template cSizeof(val: Snippet): Snippet =
"sizeof(" & val & ")"
template cAlignof(val: Snippet): Snippet =
"NIM_ALIGNOF(" & val & ")"
template cOffsetof(val, member: Snippet): Snippet =
"offsetof(" & val & ", " & member & ")"
type TypedBinaryOp = enum
Add, Sub, Mul, Div, Mod
Shr, Shl, BitAnd, BitOr, BitXor
const typedBinaryOperators: array[TypedBinaryOp, string] = [
Add: "+",
Sub: "-",
Mul: "*",
Div: "/",
Mod: "%",
Shr: ">>",
Shl: "<<",
BitAnd: "&",
BitOr: "|",
BitXor: "^"
]
type TypedUnaryOp = enum
Neg, BitNot
const typedUnaryOperators: array[TypedUnaryOp, string] = [
Neg: "-",
BitNot: "~",
]
type UntypedBinaryOp = enum
LessEqual, LessThan, GreaterEqual, GreaterThan, Equal, NotEqual
And, Or
const untypedBinaryOperators: array[UntypedBinaryOp, string] = [
LessEqual: "<=",
LessThan: "<",
GreaterEqual: ">=",
GreaterThan: ">",
Equal: "==",
NotEqual: "!=",
And: "&&",
Or: "||"
]
type UntypedUnaryOp = enum
Not
const untypedUnaryOperators: array[UntypedUnaryOp, string] = [
Not: "!"
]
proc addOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
builder.add('(')
builder.add(a)
builder.add(' ')
builder.add(typedBinaryOperators[binOp])
builder.add(' ')
builder.add(b)
builder.add(')')
proc addOp(builder: var Builder, unOp: TypedUnaryOp, t: Snippet, a: Snippet) =
builder.add('(')
builder.add(typedUnaryOperators[unOp])
builder.add('(')
builder.add(a)
builder.add("))")
proc addOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
builder.add('(')
builder.add(a)
builder.add(' ')
builder.add(untypedBinaryOperators[binOp])
builder.add(' ')
builder.add(b)
builder.add(')')
proc addOp(builder: var Builder, unOp: UntypedUnaryOp, a: Snippet) =
builder.add('(')
builder.add(untypedUnaryOperators[unOp])
builder.add('(')
builder.add(a)
builder.add("))")
template cOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
'(' & a & ' ' & typedBinaryOperators[binOp] & ' ' & b & ')'
template cOp(binOp: TypedUnaryOp, t: Snippet, a: Snippet): Snippet =
'(' & typedUnaryOperators[binOp] & '(' & a & "))"
template cOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
'(' & a & ' ' & untypedBinaryOperators[binOp] & ' ' & b & ')'
template cOp(binOp: UntypedUnaryOp, a: Snippet): Snippet =
'(' & untypedUnaryOperators[binOp] & '(' & a & "))"
template cIfExpr(cond, a, b: Snippet): Snippet =
# XXX used for `min` and `max`, maybe add nifc primitives for these
"(" & cond & " ? " & a & " : " & b & ")"
template cUnlikely(val: Snippet): Snippet =
"NIM_UNLIKELY(" & val & ")"

View File

@@ -1,329 +0,0 @@
template addAssignmentWithValue(builder: var Builder, lhs: Snippet, valueBody: typed) =
builder.add(lhs)
builder.add(" = ")
valueBody
builder.addLineEnd(";")
template addFieldAssignmentWithValue(builder: var Builder, lhs: Snippet, name: string, valueBody: typed) =
builder.add(lhs)
builder.add("." & name & " = ")
valueBody
builder.addLineEnd(";")
template addAssignment(builder: var Builder, lhs, rhs: Snippet) =
builder.addAssignmentWithValue(lhs):
builder.add(rhs)
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
builder.addFieldAssignmentWithValue(lhs, name):
builder.add(rhs)
template addMutualFieldAssignment(builder: var Builder, lhs, rhs: Snippet, name: string) =
builder.addFieldAssignmentWithValue(lhs, name):
builder.add(rhs)
builder.add("." & name)
template addAssignment(builder: var Builder, lhs: Snippet, rhs: int | int64 | uint64 | Int128) =
builder.addAssignmentWithValue(lhs):
builder.addIntValue(rhs)
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: int | int64 | uint64 | Int128) =
builder.addFieldAssignmentWithValue(lhs, name):
builder.addIntValue(rhs)
template addDerefFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
builder.add(lhs)
builder.add("->" & name & " = ")
builder.add(rhs)
builder.addLineEnd(";")
template addSubscriptAssignment(builder: var Builder, lhs: Snippet, index: Snippet, rhs: Snippet) =
builder.add(lhs)
builder.add("[" & index & "] = ")
builder.add(rhs)
builder.addLineEnd(";")
template addStmt(builder: var Builder, stmtBody: typed) =
## makes an expression built by `stmtBody` into a statement
stmtBody
builder.addLineEnd(";")
proc addCallStmt(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
builder.addStmt():
builder.addCall(callee, args)
# XXX blocks need indent tracker in `Builder` object
template addSingleIfStmt(builder: var Builder, cond: Snippet, body: typed) =
builder.add("if (")
builder.add(cond)
builder.addLineEndIndent(") {")
body
builder.addLineEndDedent("}")
template addSingleIfStmtWithCond(builder: var Builder, condBody: typed, body: typed) =
builder.add("if (")
condBody
builder.addLineEndIndent(") {")
body
builder.addLineEndDedent("}")
proc initIfStmt(builder: var Builder): IfBuilder =
IfBuilder(state: WaitingIf)
proc finishIfStmt(builder: var Builder, stmt: IfBuilder) =
assert stmt.state != InBlock
builder.addNewline()
template addIfStmt(builder: var Builder, stmt: out IfBuilder, body: typed) =
stmt = initIfStmt(builder)
body
finishIfStmt(builder, stmt)
proc initElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet) =
case stmt.state
of WaitingIf:
builder.add("if (")
of WaitingElseIf:
builder.add(" else if (")
else: assert false, $stmt.state
builder.add(cond)
builder.addLineEndIndent(") {")
stmt.state = InBlock
proc initElseBranch(builder: var Builder, stmt: var IfBuilder) =
assert stmt.state == WaitingElseIf, $stmt.state
builder.addLineEndIndent(" else {")
stmt.state = InBlock
proc finishBranch(builder: var Builder, stmt: var IfBuilder) =
builder.addDedent("}")
stmt.state = WaitingElseIf
template addElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet, body: typed) =
initElifBranch(builder, stmt, cond)
body
finishBranch(builder, stmt)
template addElseBranch(builder: var Builder, stmt: var IfBuilder, body: typed) =
initElseBranch(builder, stmt)
body
finishBranch(builder, stmt)
proc initForRange(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
builder.add("for (")
builder.add(i)
builder.add(" = ")
builder.add(start)
builder.add("; ")
builder.add(i)
if inclusive:
builder.add(" <= ")
else:
builder.add(" < ")
builder.add(bound)
builder.add("; ")
builder.add(i)
builder.addLineEndIndent("++) {")
proc initForStep(builder: var Builder, i, start, bound, step: Snippet, inclusive: bool = false) =
builder.add("for (")
builder.add(i)
builder.add(" = ")
builder.add(start)
builder.add("; ")
builder.add(i)
if inclusive:
builder.add(" <= ")
else:
builder.add(" < ")
builder.add(bound)
builder.add("; ")
builder.add(i)
builder.add(" += ")
builder.add(step)
builder.addLineEndIndent(") {")
proc finishFor(builder: var Builder) {.inline.} =
builder.addLineEndDedent("}")
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
initForRange(builder, i, start, bound, false)
body
finishFor(builder)
template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
initForRange(builder, i, start, bound, true)
body
finishFor(builder)
template addSwitchStmt(builder: var Builder, val: Snippet, body: typed) =
builder.add("switch (")
builder.add(val)
builder.addLineEnd(") {") # no indent
body
builder.addLineEnd("}")
template addSingleSwitchCase(builder: var Builder, val: Snippet, body: typed) =
builder.add("case ")
builder.add(val)
builder.addLineEndIndent(":")
body
builder.addLineEndDedent("")
type
SwitchCaseState = enum
None, Of, Else, Finished
SwitchCaseBuilder = object
state: SwitchCaseState
proc addCase(builder: var Builder, info: var SwitchCaseBuilder, val: Snippet) =
if info.state != Of:
assert info.state == None
info.state = Of
builder.add("case ")
builder.add(val)
builder.addLineEndIndent(":")
proc addCaseRange(builder: var Builder, info: var SwitchCaseBuilder, first, last: Snippet) =
if info.state != Of:
assert info.state == None
info.state = Of
builder.add("case ")
builder.add(first)
builder.add(" ... ")
builder.add(last)
builder.addLineEndIndent(":")
proc addCaseElse(builder: var Builder, info: var SwitchCaseBuilder) =
assert info.state == None
info.state = Else
builder.addLineEndIndent("default:")
template addSwitchCase(builder: var Builder, info: out SwitchCaseBuilder, caseBody, body: typed) =
info = SwitchCaseBuilder(state: None)
caseBody
info.state = Finished
body
builder.addLineEndDedent("")
template addSwitchElse(builder: var Builder, body: typed) =
builder.addLineEndIndent("default:")
body
builder.addLineEndDedent("")
proc addBreak(builder: var Builder) =
builder.addLineEnd("break;")
type ScopeBuilder = object
inside: bool
proc initScope(builder: var Builder): ScopeBuilder =
builder.addLineEndIndent("{")
result = ScopeBuilder(inside: true)
proc finishScope(builder: var Builder, scope: var ScopeBuilder) =
assert scope.inside, "scope not inited"
builder.addLineEndDedent("}")
scope.inside = false
template addScope(builder: var Builder, body: typed) =
builder.addLineEndIndent("{")
body
builder.addLineEndDedent("}")
type WhileBuilder = object
inside: bool
proc initWhileStmt(builder: var Builder, cond: Snippet): WhileBuilder =
builder.add("while (")
builder.add(cond)
builder.addLineEndIndent(") {")
result = WhileBuilder(inside: true)
proc finishWhileStmt(builder: var Builder, stmt: var WhileBuilder) =
assert stmt.inside, "while stmt not inited"
builder.addLineEndDedent("}")
stmt.inside = false
template addWhileStmt(builder: var Builder, cond: Snippet, body: typed) =
builder.add("while (")
builder.add(cond)
builder.addLineEndIndent(") {")
body
builder.addLineEndDedent("}")
proc addLabel(builder: var Builder, name: TLabel) =
builder.add(name)
builder.addLineEnd(": ;")
proc addReturn(builder: var Builder) =
builder.addLineEnd("return;")
proc addReturn(builder: var Builder, value: Snippet) =
builder.add("return ")
builder.add(value)
builder.addLineEnd(";")
proc addGoto(builder: var Builder, label: TLabel) =
builder.add("goto ")
builder.add(label)
builder.addLineEnd(";")
proc addComputedGoto(builder: var Builder, value: Snippet) =
builder.add("goto *")
builder.add(value)
builder.addLineEnd(";")
proc addIncr(builder: var Builder, val: Snippet) =
builder.add(val)
builder.addLineEnd("++;")
proc addDecr(builder: var Builder, val: Snippet) =
builder.add(val)
builder.addLineEnd("--;")
proc addInPlaceOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
builder.add(a)
builder.add(' ')
builder.add(typedBinaryOperators[binOp])
builder.add("= ")
builder.add(b)
builder.addLineEnd(";")
proc addInPlaceOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
builder.add(a)
builder.add(' ')
builder.add(untypedBinaryOperators[binOp])
builder.add("= ")
builder.add(b)
builder.addLineEnd(";")
proc cInPlaceOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
result = ""
result.add(a)
result.add(' ')
result.add(typedBinaryOperators[binOp])
result.add("= ")
result.add(b)
result.add(";\n")
proc cInPlaceOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
result = ""
result.add(a)
result.add(' ')
result.add(untypedBinaryOperators[binOp])
result.add("= ")
result.add(b)
result.add(";\n")
template addCPragma(builder: var Builder, val: Snippet) =
builder.addNewline()
builder.add("#pragma ")
builder.add(val)
builder.addNewline()
proc addDiscard(builder: var Builder, val: Snippet) =
builder.add("(void)")
builder.add(val)
builder.addLineEnd(";")

View File

@@ -84,21 +84,20 @@ proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
var op = initLocExpr(p, newSymNode(dtor))
var callee = rdLoc(op)
let destroyArg =
if dtor.typ.firstParamType.kind == tyVar:
cAddr(rdLoc(tmp))
let destroy = if dtor.typ.firstParamType.kind == tyVar:
callee & "(&" & rdLoc(tmp) & ")"
else:
rdLoc(tmp)
let destroy = cCall(callee, destroyArg)
callee & "(" & rdLoc(tmp) & ")"
raiseExitCleanup(p, destroy)
result = true
else:
result = false
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
result: var Builder, call: var CallBuilder) =
callee, params: Rope) =
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
genLineDir(p, ri)
var pl = callee & "(" & params
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ.returnType != nil:
@@ -107,6 +106,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
@@ -114,39 +114,33 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
let rad = addrLoc(p.config, d)
result.addArgument(call):
result.add(rad)
result.finishCallBuilder(call)
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(result))
pl.add(addrLoc(p.config, d))
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
let ratmp = addrLoc(p.config, tmp)
result.addArgument(call):
result.add(ratmp)
result.finishCallBuilder(call)
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(result))
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
result.finishCallBuilder(call)
pl.add(")")
if p.module.compileToCpp:
if lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen
# is free to emit expressions multiple times!
d.k = locCall
d.snippet = extract(result)
d.snippet = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0 and p.config.exc != excGoto:
d = getTempCpp(p, typ.returnType, extract(result))
d = getTempCpp(p, typ.returnType, pl)
else:
if d.k == locNone: d = getTemp(p, typ.returnType)
var list = initLoc(locCall, d.lode, OnUnknown)
list.snippet = extract(result)
list.snippet = pl
genAssignment(p, d, list, {needAssignCall}) # no need for deep copying
if canRaise: raiseExit(p)
@@ -157,7 +151,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
d = getTemp(p, typ.returnType)
assert(d.t != nil) # generate an assignment to d:
var list = initLoc(locCall, d.lode, OnUnknown)
list.snippet = extract(result)
list.snippet = pl
genAssignment(p, d, list, flags+{needAssignCall}) # no need for deep copying
if canRaise:
if not (useTemp and cleanupTemp(p, typ.returnType, d)):
@@ -165,16 +159,15 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
list.snippet = extract(result)
list.snippet = pl
genAssignment(p, tmp, list, flags+{needAssignCall}) # no need for deep copying
if canRaise:
if not cleanupTemp(p, typ.returnType, tmp):
raiseExit(p)
genAssignment(p, d, tmp, {})
else:
finishCallBuilder(result, call)
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(result))
pl.add(");\n")
line(p, cpsStmts, pl)
if canRaise: raiseExit(p)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
@@ -206,49 +199,49 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c, ty)
if prepareForMutation:
let bra = byRefLoc(p, a)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
bra)
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
let dest = getTypeDesc(p.module, destType)
let ra = rdLoc(a)
let rb = rdLoc(b)
let rc = rdLoc(c)
let lengthExpr = cOp(Add, NimInt, cOp(Sub, NimInt, rc, rb), cIntValue(1))
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
case ty.kind
of tyArray:
let first = toInt64(firstOrd(p.config, ty))
if first == 0:
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, rb)), lengthExpr)
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
let lit = cIntLiteral(first)
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, cOp(Sub, NimInt, rb, lit))), lengthExpr)
var lit = newRopeAppender()
intLiteral(first, lit)
result = ("($4*)($1)+(($2)-($3))" %
[rdLoc(a), rdLoc(b), lit, dest],
lengthExpr)
of tyOpenArray, tyVarargs:
let data = if reifiedOpenArray(q[1]): dotField(ra, "Field0") else: ra
result = (cCast(ptrType(dest), cOp(Add, NimInt, data, rb)), lengthExpr)
if reifiedOpenArray(q[1]):
result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
of tyUncheckedArray, tyCstring:
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, rb)), lengthExpr)
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
of tyString, tySequence:
let atyp = skipTypes(a.t, abstractInst)
if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and
optSeqDestructors in p.config.globalOptions:
let bra = byRefLoc(p, a)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
bra)
var val: Snippet
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
val = cDeref(ra)
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
lengthExpr)
else:
val = ra
result = (
cIfExpr(dataFieldAccessor(p, val),
cCast(ptrType(dest), cOp(Add, NimInt, dataField(p, val), rb)),
NimNil),
lengthExpr)
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var q = skipConv(n)
var skipped = false
while q.kind == nkStmtListExpr and q.len > 0:
@@ -263,66 +256,42 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
genStmts(p, q[i])
q = q.lastSon
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ.elementType)
result.add(x)
result.addArgumentSeparator()
result.add(y)
result.add x & ", " & y
else:
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
let ra = rdLoc(a)
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:
result.add(derefField(ra, "Field0"))
result.addArgumentSeparator()
result.add(derefField(ra, "Field1"))
result.add "$1->Field0, $1->Field1" % [rdLoc(a)]
else:
result.add(dotField(ra, "Field0"))
result.addArgumentSeparator()
result.add(dotField(ra, "Field1"))
result.add "$1.Field0, $1.Field1" % [rdLoc(a)]
else:
result.add(ra)
result.addArgumentSeparator()
result.add(ra & "Len_0")
result.add "$1, $1Len_0" % [rdLoc(a)]
of tyString, tySequence:
let ntyp = skipTypes(n.typ, abstractInst)
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
optSeqDestructors in p.config.globalOptions:
let bra = byRefLoc(p, a)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
bra)
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
let ra = a.rdLoc
var t = TLoc(snippet: cDeref(ra))
let lt = lenExpr(p, t)
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), NimNil))
result.addArgumentSeparator()
result.add(lt)
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
else:
let ra = a.rdLoc
let la = lenExpr(p, a)
result.add(cIfExpr(dataFieldAccessor(p, ra), dataField(p, ra), NimNil))
result.addArgumentSeparator()
result.add(la)
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
of tyArray:
let ra = rdLoc(a)
result.add(ra)
result.addArgumentSeparator()
result.addIntValue(lengthOrd(p.config, a.t))
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef:
case elementType(a.t).kind
of tyString, tySequence:
let ra = a.rdLoc
var t = TLoc(snippet: cDeref(ra))
let lt = lenExpr(p, t)
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), NimNil))
result.addArgumentSeparator()
result.add(lt)
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
of tyArray:
let ra = rdLoc(a)
result.add(ra)
result.addArgumentSeparator()
result.addIntValue(lengthOrd(p.config, elementType(a.t)))
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, elementType(a.t)))]
else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
@@ -342,12 +311,11 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Builder; needsTmp: bool) {.inline.} =
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a = initLocExpr(p, n[0])
let ra = withTmpIfNeeded(p, a, needsTmp).rdLoc
result.addCall(cgsymValue(p.module, "nimToCStringConv"), ra)
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; needsTmp = false) =
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
var a: TLoc
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
@@ -388,11 +356,12 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
if param.typ.kind in {tyVar, tyPtr, tyRef, tySink}:
let typ = skipTypes(param.typ, abstractPtrs)
if not sameBackendTypePickyAliases(typ, n.typ.skipTypes(abstractPtrs)):
a.snippet = cCast(getTypeDesc(p.module, param.typ), rdCharLoc(a))
a.snippet = "(($1) ($2))" %
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
proc genArgNoParam(p: BProc, n: PNode; result: var Builder; needsTmp = false) =
proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
var a: TLoc
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
@@ -455,7 +424,7 @@ proc getPotentialReads(n: PNode; result: var seq[PNode]) =
for s in n:
getPotentialReads(s, result)
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
@@ -477,22 +446,21 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder:
# Optimization: don't use a temp, if we would only take the address anyway
needTmp[i - 1] = false
var oldLen = result.len
for i in 1..<ri.len:
if i < typ.n.len:
assert(typ.n[i].kind == nkSym)
let paramType = typ.n[i]
if not paramType.typ.isCompileTimeOnly:
var arg = newBuilder("")
genArg(p, ri[i], paramType.sym, ri, arg, needTmp[i-1])
if arg.buf.len != 0:
result.addArgument(argBuilder):
result.add(extract(arg))
if oldLen != result.len:
result.add(", ")
oldLen = result.len
genArg(p, ri[i], paramType.sym, ri, result, needTmp[i-1])
else:
var arg = newBuilder("")
genArgNoParam(p, ri[i], arg, needTmp[i-1])
if arg.buf.len != 0:
result.addArgument(argBuilder):
result.add(extract(arg))
if oldLen != result.len:
result.add(", ")
oldLen = result.len
genArgNoParam(p, ri[i], result, needTmp[i-1])
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
@@ -506,39 +474,21 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
var params = newRopeAppender()
genParams(p, ri, typ, params)
var callee = rdLoc(op)
if p.hcrOn and ri[0].kind == nkSym:
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
var res = newBuilder("")
var call = initCallBuilder(res, callee)
genParams(p, ri, typ, res, call)
fixupCall(p, le, ri, d, res, call)
fixupCall(p, le, ri, d, callee, params)
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
template callProc(rp, params, pTyp: Snippet): Snippet =
let e = dotField(rp, "ClE_0")
let p = dotField(rp, "ClP_0")
let eCall =
# note `params` here is actually multiple params
if params.len == 0:
cCall(p, e)
else:
cCall(p, params, e)
cIfExpr(e,
eCall,
cCall(cCast(pTyp, p), params))
proc addComma(r: Rope): Rope =
if r.len == 0: r else: r & ", "
template callIter(rp, params: Snippet): Snippet =
# we know the env exists
let e = dotField(rp, "ClE_0")
let p = dotField(rp, "ClP_0")
# note `params` here is actually multiple params
if params.len == 0:
cCall(p, e)
else:
cCall(p, params, e)
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
var op = initLocExpr(p, ri[0])
@@ -546,23 +496,20 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
var params = newBuilder("")
var argBuilder = default(CallBuilder) # not initCallBuilder, we just want the params
genParams(p, ri, typ, params, argBuilder)
var pl = newRopeAppender()
genParams(p, ri, typ, pl)
template genCallPattern {.dirty.} =
let rp = rdLoc(op)
let pars = extract(params)
p.s(cpsStmts).addStmt():
if tfIterator in typ.flags:
p.s(cpsStmts).add(callIter(rp, pars))
else:
p.s(cpsStmts).add(callProc(rp, pars, rawProc))
if tfIterator in typ.flags:
lineF(p, cpsStmts, PatIter & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
else:
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
let rawProc = getClosureType(p.module, typ, clHalf)
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
if typ.returnType != nil:
if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
@@ -571,14 +518,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
params.addArgument(argBuilder):
params.add(addrLoc(p.config, d))
pl.add(addrLoc(p.config, d))
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
params.addArgument(argBuilder):
params.add(addrLoc(p.config, tmp))
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
@@ -586,24 +531,20 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k == locNone: d = getTemp(p, typ.returnType)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
let rp = rdLoc(op)
let pars = extract(params)
if tfIterator in typ.flags:
list.snippet = callIter(rp, pars)
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
list.snippet = callProc(rp, pars, rawProc)
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
let rp = rdLoc(op)
let pars = extract(params)
if tfIterator in typ.flags:
list.snippet = callIter(rp, pars)
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
list.snippet = callProc(rp, pars, rawProc)
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
genAssignment(p, tmp, list, {})
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
@@ -611,8 +552,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
argBuilder: var CallBuilder) =
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
argsCounter: var int) =
if i < typ.n.len:
# 'var T' is 'T&' in C++. This means we ignore the request of
# any nkHiddenAddr when it's a 'var T'.
@@ -621,17 +562,20 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
if paramType.typ.isCompileTimeOnly:
discard
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
result.addArgument(argBuilder):
genArgNoParam(p, ri[i][0], result)
if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i][0], result)
inc argsCounter
else:
result.addArgument(argBuilder):
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
inc argsCounter
else:
if tfVarargs notin typ.flags:
localError(p.config, ri.info, "wrong argument count")
else:
result.addArgument(argBuilder):
genArgNoParam(p, ri[i], result)
if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i], result)
inc argsCounter
discard """
Dot call syntax in C++
@@ -688,7 +632,7 @@ proc skipAddrDeref(node: PNode): PNode =
else:
result = node
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
# for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience.
@@ -723,15 +667,15 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
genArgNoParam(p, ri, result) #, typ.n[i].sym)
result.add(".")
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Builder) =
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) =
var i = 0
var j = 1
while i < pat.len:
case pat[i]
of '@':
var callBuilder = default(CallBuilder) # not init call builder
var argsCounter = 0
for k in j..<ri.len:
genOtherArg(p, ri, k, typ, result, callBuilder)
genOtherArg(p, ri, k, typ, result, argsCounter)
inc i
of '#':
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
@@ -741,11 +685,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
if pat[i+1] == '+': genArgNoParam(p, ri[0], result)
result.add("(")
if 1 < ri.len:
var callBuilder: CallBuilder = default(CallBuilder)
genOtherArg(p, ri, 1, typ, result, callBuilder)
var argsCounterB = 0
genOtherArg(p, ri, 1, typ, result, argsCounterB)
for k in j+1..<ri.len:
var callBuilder: CallBuilder = default(CallBuilder)
genOtherArg(p, ri, k, typ, result, callBuilder)
var argsCounterB = 0
genOtherArg(p, ri, k, typ, result, argsCounterB)
result.add(")")
else:
localError(p.config, ri.info, "call expression expected for C++ pattern")
@@ -759,15 +703,15 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
genArgNoParam(p, arg, result)
#result.add debugTree(arg, 0, 10)
else:
var callBuilder = default(CallBuilder) # not init call builder
genOtherArg(p, ri, j, typ, result, callBuilder)
var argsCounter = 0
genOtherArg(p, ri, j, typ, result, argsCounter)
inc j
inc i
of '\'':
var idx, stars: int = 0
if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add(CVoid)
if t == nil: result.add("void")
else: result.add(getTypeDesc(p.module, t))
else:
let start = i
@@ -786,7 +730,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
let pat = $ri[0].sym.loc.snippet
internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@', '\''}):
var pl = newBuilder("")
var pl = newRopeAppender()
genPatternCall(p, ri, pat, typ, pl)
# simpler version of 'fixupCall' that works with the pl+params combination:
var typ = skipTypes(ri[0].typ, abstractInst)
@@ -796,32 +740,32 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# with them to prevent undefined behaviour and because the codegen
# is free to emit expressions multiple times!
d.k = locCall
d.snippet = extract(pl)
d.snippet = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: d = getTemp(p, typ.returnType)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
list.snippet = extract(pl)
list.snippet = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(pl))
pl.add(";\n")
line(p, cpsStmts, pl)
else:
var pl = newBuilder("")
var pl = newRopeAppender()
var argsCounter = 0
if 1 < ri.len:
genThisArg(p, ri, 1, typ, pl)
pl.add(op.snippet)
var res = newBuilder("")
var call = initCallBuilder(res, extract(pl))
var params = newRopeAppender()
for i in 2..<ri.len:
genOtherArg(p, ri, i, typ, res, call)
fixupCall(p, le, ri, d, res, call)
genOtherArg(p, ri, i, typ, params, argsCounter)
fixupCall(p, le, ri, d, pl, params)
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op = initLocExpr(p, ri[0])
var pl = newBuilder("[")
var pl = "["
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -863,27 +807,24 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("]")
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(pl))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("]")
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(pl))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: d = getTemp(p, typ.returnType)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, ri, OnUnknown)
list.snippet = extract(pl)
list.snippet = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
pl.add("]")
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(extract(pl))
pl.add("];\n")
line(p, cpsStmts, pl)
proc notYetAlive(n: PNode): bool {.inline.} =
let r = getRoot(n)

File diff suppressed because it is too large Load Diff

View File

@@ -36,84 +36,52 @@ proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
cgsym(m, "TGenericSeq")
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithTypeAndInitializer(AlwaysConst, name = tmp):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "Sup", typ = "TGenericSeq")
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
do:
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "Sup"):
var seqInit: StructInitializer
res.addStructInitializer(seqInit, kind = siOrderedStruct):
res.addField(seqInit, name = "len"):
res.addIntValue(s.len)
res.addField(seqInit, name = "reserved"):
res.add(cCast(NimInt, cOp(BitOr, NimUint, cCast(NimUint, cIntValue(s.len)), NimStrlitFlag)))
res.addField(strInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(extract(res))
m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n",
[tmp, makeCString(s), rope(s.len)])
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
if s.isNil:
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
else:
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var name: string = ""
if id == m.labels:
# string literal not found in the cache:
genStringLiteralDataOnlyV1(m, n.strVal, name)
appcg(m, result, "((#NimStringDesc*) &", [])
genStringLiteralDataOnlyV1(m, n.strVal, result)
result.add ")"
else:
name = m.tmpBase & $id
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), cAddr(name)))
appcg(m, result, "((#NimStringDesc*) &$1$2)",
[m.tmpBase, id])
# ------ Version 2: destructor based strings and seqs -----------------------
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
var res = newBuilder("")
res.addVarWithTypeAndInitializer(
if isConst: AlwaysConst else: Global,
name = result):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "cap", typ = NimInt)
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
do:
var structInit: StructInitializer
res.addStructInitializer(structInit, kind = siOrderedStruct):
res.addField(structInit, name = "cap"):
res.add(cOp(BitOr, NimInt, cIntValue(s.len), NimStrlitFlag))
res.addField(structInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(extract(res))
m.s[cfsStrData].addf("static $4 struct {$n" &
" NI cap; NIM_CHAR data[$2+1];$n" &
"} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
[result, rope(s.len), makeCString(s),
rope(if isConst: "const" else: "")])
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var litName: string
if id == m.labels:
let pureLit = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
let tmp = getTempName(m)
result.add tmp
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
# string literal not found in the cache:
litName = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, litName, isConst)
m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
else:
litName = m.tmpBase & $id
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithInitializer(
if isConst: AlwaysConst else: Global,
name = tmp,
typ = "NimStringV2"):
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "len"):
res.addIntValue(n.strVal.len)
res.addField(strInit, name = "p"):
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
m.s[cfsStrData].add(extract(res))
let tmp = getTempName(m)
result.add tmp
m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[tmp, rope(n.strVal.len), m.tmpBase & rope(id),
rope(if isConst: "const" else: "")])
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
@@ -124,12 +92,7 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Bu
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
else:
pureLit = m.tmpBase & rope(id)
var strInit: StructInitializer
result.addStructInitializer(strInit, kind = siOrderedStruct):
result.addField(strInit, name = "len"):
result.addIntValue(n.strVal.len)
result.addField(strInit, name = "p"):
result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
# ------ Version selector ---------------------------------------------------
@@ -144,10 +107,10 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)

View File

@@ -27,28 +27,25 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
if disc.loc.snippet == "": fillObjectFields(p.module, typ)
if disc.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
let discField = dotField(accessor, disc.loc.snippet)
p.s(cpsStmts).addSwitchStmt(discField):
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
var caseBuilder: SwitchCaseBuilder
p.s(cpsStmts).addSwitchCase(caseBuilder):
if branch.kind == nkOfBranch:
genCaseRange(p, branch, caseBuilder)
else:
p.s(cpsStmts).addCaseElse(caseBuilder)
do:
specializeResetN(p, accessor, lastSon(branch), typ)
p.s(cpsStmts).addBreak()
specializeResetT(p, discField, disc.loc.t)
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
specializeResetN(p, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
specializeResetT(p, "$1.$2" % [accessor, disc.loc.snippet], disc.loc.t)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.snippet == "": fillObjectFields(p.module, typ)
if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, dotField(accessor, field.loc.snippet), field.loc.t)
specializeResetT(p, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
else: internalError(p.config, n.info, "specializeResetN()")
proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
@@ -61,8 +58,10 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of tyArray:
let arraySize = lengthOrd(p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
specializeResetT(p, subscript(accessor, i.snippet), typ.elementType)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
@@ -71,34 +70,28 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
specializeResetT(p, dotField(accessor, "Field" & $i), a)
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), a)
of tyString, tyRef, tySequence:
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
cCast(ptrType(CPointer), cAddr(accessor)),
NimNil)
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])
of tyProc:
if typ.callConv == ccClosure:
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
cCast(ptrType(CPointer), cAddr(dotField(accessor, "ClE_0"))),
NimNil)
p.s(cpsStmts).addFieldAssignment(accessor, "ClP_0", NimNil)
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor])
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
p.s(cpsStmts).addAssignment(accessor, NimNil)
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
p.s(cpsStmts).addAssignment(accessor, NimNil)
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tySet:
case mapSetType(p.config, typ)
of ctArray:
let t = getTypeDesc(p.module, typ)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
accessor,
cSizeof(t))
lineCg(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n",
[accessor, getTypeDesc(p.module, typ)])
of ctInt8, ctInt16, ctInt32, ctInt64:
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
else:
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,

File diff suppressed because it is too large Load Diff

View File

@@ -19,12 +19,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars(p.config) and threadVarAccessed notin p.flags:
p.flags.incl threadVarAccessed
incl p.module.flags, usesThreadVars
p.procSec(cpsLocals).addVar(kind = Local,
name = "NimTV_",
typ = ptrType("NimThreadVars"))
p.procSec(cpsInit).addAssignment("NimTV_",
cCast(ptrType("NimThreadVars"),
cCall(cgsymValue(p.module, "GetThreadLocalVars"))))
p.procSec(cpsLocals).addf("\tNimThreadVars* NimTV_;$n", [])
p.procSec(cpsInit).add(
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n", []))
proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
if emulatedThreadVars(m.config):
@@ -33,32 +30,30 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
# allocator for it :-(
if not containsOrIncl(m.g.nimtvDeclared, s.id):
m.g.nimtvDeps.add(s.loc.t)
m.g.nimtv.addField(name = s.loc.snippet, typ = getTypeDesc(m, s.loc.t))
m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.snippet])
else:
let vis =
if isExtern: Extern
elif lfExportLib in s.loc.flags: ExportLibVar
else: Private
m.s[cfsVars].addVar(m, s,
name = s.loc.snippet,
typ = getTypeDesc(m, s.loc.t),
kind = Threadvar,
visibility = vis)
if isExtern: m.s[cfsVars].add("extern ")
elif lfExportLib in s.loc.flags: m.s[cfsVars].add("N_LIB_EXPORT_VAR ")
else: m.s[cfsVars].add("N_LIB_PRIVATE ")
if optThreads in m.config.globalOptions:
let sym = s.typ.sym
if sym != nil and sfCppNonPod in sym.flags:
m.s[cfsVars].add("NIM_THREAD_LOCAL ")
else: m.s[cfsVars].add("NIM_THREADVAR ")
m.s[cfsVars].add(getTypeDesc(m, s.loc.t))
m.s[cfsVars].addf(" $1;$n", [s.loc.snippet])
proc generateThreadLocalStorage(m: BModule) =
if m.g.nimtv.buf.len != 0 and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
finishTypeDescriptions(m)
m.s[cfsSeqTypes].addTypedef(name = "NimThreadVars"):
m.s[cfsSeqTypes].addSimpleStruct(m, name = "", baseType = ""):
m.s[cfsSeqTypes].add(extract(m.g.nimtv))
m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) =
if m.g.nimtv.buf.len != 0:
if m.g.nimtv != "":
let externc = if m.config.backend == backendCpp or
sfCompileToCpp in m.module.flags: ExternC
else: None
m.s[cfsProcs].addDeclWithVisibility(externc):
m.s[cfsProcs].addProcHeader("NimThreadVarsSize", NimInt, cProcParams())
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].addReturn(cCast(NimInt, cSizeof("NimThreadVars")))
sfCompileToCpp in m.module.flags: "extern \"C\" "
else: ""
m.s[cfsProcs].addf(
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
[externc.rope])

View File

@@ -16,16 +16,13 @@ type
p: BProc
visitorFrmt: string
const
visitorFrmt = "#nimGCvisit((void*)$1, $2);$n"
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
proc visit(p: BProc, data, visitor: Snippet) =
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisit"),
cCast(CPointer, data),
visitor)
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
typ: PType) =
if n == nil: return
@@ -40,32 +37,29 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
if disc.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()")
let discField = dotField(accessor, disc.loc.snippet)
p.s(cpsStmts).addSwitchStmt(discField):
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
var caseBuilder: SwitchCaseBuilder
p.s(cpsStmts).addSwitchCase(caseBuilder):
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch, caseBuilder)
else:
p.s(cpsStmts).addCaseElse(caseBuilder)
do:
genTraverseProc(c, accessor, lastSon(branch), typ)
p.s(cpsStmts).addBreak()
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
genTraverseProc(c, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
if field.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()")
genTraverseProc(c, dotField(accessor, field.loc.snippet), field.loc.t)
genTraverseProc(c, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
else: internalError(c.p.config, n.info, "genTraverseProc()")
proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
if not m.compileToCpp:
result = dotField(accessor, "Sup")
result = "$1.Sup" % [accessor]
else:
result = accessor
@@ -82,14 +76,16 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
let arraySize = lengthOrd(c.p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
var oldLen, newLen: int
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
oldLen = p.s(cpsStmts).buf.len
genTraverseProc(c, subscript(accessor, i.snippet), typ.elementType)
newLen = p.s(cpsStmts).buf.len
if oldLen == newLen:
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
@@ -98,25 +94,23 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
genTraverseProc(c, dotField(accessor, "Field" & $i), a)
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), a)
of tyRef:
visit(p, accessor, c.visitorFrmt)
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
of tySequence:
if optSeqDestructors notin c.p.module.config.globalOptions:
visit(p, accessor, c.visitorFrmt)
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
elif containsGarbageCollectedRef(typ.elementType):
# destructor based seqs are themselves not traced but their data is, if
# they contain a GC'ed type:
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisitSeq"),
cCast(CPointer, accessor),
c.visitorFrmt)
lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
#genTraverseProcSeq(c, accessor, typ)
of tyString:
if tfHasAsgn notin typ.flags:
visit(p, accessor, c.visitorFrmt)
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
of tyProc:
if typ.callConv == ccClosure:
visit(p, dotField(accessor, "ClE_0"), c.visitorFrmt)
lineCg(p, cpsStmts, visitorFrmt, [ropecg(c.p.module, "$1.ClE_0", [accessor]), c.visitorFrmt])
else:
discard
@@ -125,17 +119,18 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
assert typ.kind == tySequence
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
var oldLen, newLen: int
freeze oldCode
var a = TLoc(snippet: accessor)
let le = lenExpr(c.p, a)
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), le):
oldLen = p.s(cpsStmts).buf.len
genTraverseProc(c, subscript(dataField(c.p, accessor), i.snippet), typ.elementType)
newLen = p.s(cpsStmts).buf.len
if newLen == oldLen:
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, lenExpr(c.p, a)])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
lineF(p, cpsStmts, "}$n", [])
proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
var p = newProc(nil, m)
@@ -144,10 +139,11 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
hcrOn = m.hcrOn
typ = origTyp.skipTypes(abstractInstOwned)
markerName = if hcrOn: result & "_actual" else: result
header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [markerName]
t = getTypeDesc(m, typ)
p.s(cpsLocals).addVar(kind = Local, name = "a", typ = t)
p.s(cpsInit).addAssignment("a", cCast(t, "p"))
lineF(p, cpsLocals, "$1 a;$n", [t])
lineF(p, cpsInit, "a = ($1)p;$n", [t])
var c = TTraversalClosure(p: p,
visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
@@ -161,40 +157,18 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
# C's arrays are broken beyond repair:
genTraverseProc(c, "a".rope, typ.elementType)
else:
genTraverseProc(c, cDeref("a"), typ.elementType)
genTraverseProc(c, "(*a)".rope, typ.elementType)
var headerBuilder = newBuilder("")
headerBuilder.addProcHeaderWithParams(ccNimCall, markerName, CVoid):
var paramBuilder: ProcParamBuilder
headerBuilder.addProcParams(paramBuilder):
headerBuilder.addParam(paramBuilder, name = "p", typ = CPointer)
headerBuilder.addParam(paramBuilder, name = "op", typ = NimInt)
let header = extract(headerBuilder)
let generatedProc = "$1 {$n$2$3$4}\n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
m.s[cfsProcHeaders].add(header)
m.s[cfsProcHeaders].finishProcHeaderAsProto()
m.s[cfsProcs].addDeclWithVisibility(StaticProc):
m.s[cfsProcs].add(header)
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].add(extract(p.s(cpsLocals)))
m.s[cfsProcs].add(extract(p.s(cpsInit)))
m.s[cfsProcs].add(extract(p.s(cpsStmts)))
m.s[cfsProcHeaders].addf("$1;\n", [header])
m.s[cfsProcs].add(generatedProc)
if hcrOn:
var desc = newBuilder("")
var unnamedParamBuilder: ProcParamBuilder
desc.addProcParams(unnamedParamBuilder):
desc.addUnnamedParam(unnamedParamBuilder, CPointer)
desc.addUnnamedParam(unnamedParamBuilder, NimInt)
let unnamedParams = extract(desc)
m.s[cfsProcHeaders].addProcVar(ccNimCall, result, unnamedParams, CVoid)
m.s[cfsDynLibInit].addAssignmentWithValue(result):
m.s[cfsDynLibInit].addCast(procPtrTypeUnnamed(ccNimCall, CVoid, unnamedParams)):
m.s[cfsDynLibInit].addCall("hcrRegisterProc",
getModuleDllPath(m),
'"' & result & '"',
cCast(CPointer, markerName))
m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
[result, markerName, getModuleDllPath(m)])
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfoV1(m, s.loc.t, info)
@@ -205,28 +179,17 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
if sfThread in s.flags and emulatedThreadVars(m.config):
accessThreadLocalVar(p, s)
sLoc = derefField("NimTV_", sLoc)
sLoc = "NimTV_->" & sLoc
var c = TTraversalClosure(p: p,
visitorFrmt: cIntValue(0) # "#nimGCvisit((void*)$1, 0);$n"
visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n"
)
let header = "static N_NIMCALL(void, $1)(void)" % [result]
genTraverseProc(c, sLoc, s.loc.t)
var headerBuilder = newBuilder("")
headerBuilder.addProcHeaderWithParams(ccNimCall, result, CVoid):
var paramBuilder: ProcParamBuilder
headerBuilder.addProcParams(paramBuilder):
# (void)
discard
let header = extract(headerBuilder)
let generatedProc = "$1 {$n$2$3$4}$n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
m.s[cfsProcHeaders].add(header)
m.s[cfsProcHeaders].finishProcHeaderAsProto()
m.s[cfsProcs].addDeclWithVisibility(StaticProc):
m.s[cfsProcs].add(header)
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].add(extract(p.s(cpsLocals)))
m.s[cfsProcs].add(extract(p.s(cpsInit)))
m.s[cfsProcs].add(extract(p.s(cpsStmts)))
m.s[cfsProcHeaders].addf("$1;$n", [header])
m.s[cfsProcs].add(generatedProc)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
import
ast, ropes, options,
lineinfos, pathutils, modulegraphs, cbuilderbase
lineinfos, pathutils, modulegraphs
import std/[intsets, tables, sets]
@@ -43,12 +43,12 @@ type
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
TCFileSections* = array[TCFileSection, Builder] # represents a generated C file
TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
cpsInit, # section for init of variables for C proc
cpsStmts # section of local statements for C proc
TCProcSections* = array[TCProcSection, Builder] # represents a generated C proc
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
BModule* = ref TCGen
BProc* = ref TCProc
TBlock* = object
@@ -115,7 +115,7 @@ type
# computing alive data on our own.
BModuleList* = ref object of RootObj
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Builder
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
mapping*: Rope # the generated mapping file (if requested)
modules*: seq[BModule] # list of all compiled modules
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
@@ -127,7 +127,7 @@ type
graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use
nimtv*: Builder # Nim thread vars; the struct body
nimtv*: Rope # Nim thread vars; the struct body
nimtvDeps*: seq[PType] # type deps: every module needs whole struct
nimtvDeclared*: IntSet # so that every var/field exists only once
# in the struct
@@ -161,15 +161,14 @@ type
typeInfoMarkerV2*: TypeCache
initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc
hcrCreateTypeInfosProc*: Builder # type info globals are in here when HCR=on
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
hcrInitGuard*: IfBuilder
typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable
typeNodes*, nimTypes*: int # used for type info generation
typeNodesName*, nimTypesName*: Rope # used for type info generation
labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', Builder] # special procs for the
extensionLoaders*: array['0'..'9', Rope] # special procs for the
# OpenGL wrapper
sigConflicts*: CountTable[SigHash]
g*: BModuleList
@@ -182,18 +181,18 @@ proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
this.headerFiles.add header
proc s*(p: BProc, s: TCProcSection): var Builder {.inline.} =
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block
result = p.blocks[^1].sections[s]
proc procSec*(p: BProc, s: TCProcSection): var Builder {.inline.} =
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections
result = p.blocks[0].sections[s]
proc initBlock*(): TBlock =
result = TBlock()
for i in low(result.sections)..high(result.sections):
result.sections[i] = newBuilder("")
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(

View File

@@ -159,7 +159,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimUseStrictDefs") # deadcode
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasCastExtendedVm")
@@ -171,4 +171,3 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasJsNoLambdaLifting")
defineSymbol("nimHasDefaultFloatRoundtrip")
defineSymbol("nimHasXorSet")

View File

@@ -1207,8 +1207,6 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
result.ast[pragmasPos].add newTree(nkExprColonExpr,
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
if kind == attachedDestructor:
incl result.options, optQuirky
completePartialOp(g, idgen.module, typ, kind, result)

View File

@@ -222,7 +222,7 @@ type
strictEffects,
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs, # deadcode
strictDefs,
strictCaseObjects,
inferGenericTypes,
openSym, # remove nfDisabledOpenSym when this is default

View File

@@ -1318,12 +1318,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises:
of wEnforceNoRaises, wQuirky:
sym.flags.incl sfNeverRaises
of wQuirky:
sym.flags.incl sfNeverRaises
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
sym.options.incl optQuirky
of wSystemRaisesDefect:
sym.flags.incl sfSystemRaisesDefect
of wVirtual:

View File

@@ -1501,10 +1501,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
addParamOrResult(c, arg, kind)
styleCheckDef(c, a[j].info, arg)
onDef(a[j].info, arg)
if a[j].kind == nkPragmaExpr:
a[j][0] = newSymNode(arg)
else:
a[j] = newSymNode(arg)
a[j] = newSymNode(arg)
var r: PType = nil
if n[0].kind != nkEmpty:

View File

@@ -1692,8 +1692,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if aAsObject.kind == tyObject and trIsOutParam notin flags:
let baseType = aAsObject.base
if baseType != nil:
if tfFinal notin aAsObject.flags:
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
let ret = typeRel(c, f, baseType, flags)
return if ret in {isEqual,isGeneric}: isSubtype else: ret
@@ -1734,10 +1733,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let tr = typeRel(c, f[i], x[i], flags)
if tr <= isSubtype: return
result = isGeneric
let impl = last(f[0])
if impl.kind == tyObject and tfFinal notin impl.flags:
# match non-invocation case
inc c.inheritancePenalty, 0 + int(c.inheritancePenalty < 0)
elif x.kind == tyGenericInst and f[0] == x[0] and
x.len - 1 == f.len:
for i in 1..<f.len:
@@ -1794,8 +1789,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
depth = -1
if depth >= 0:
if aobj.kind == tyObject and tfFinal notin aobj.flags:
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
# bug #4863: We still need to bind generic alias crap, so
# we cannot return immediately:
result = if depth == 0: isGeneric else: isSubtype

View File

@@ -12,7 +12,7 @@
import semmacrosanity
import
std/[strutils, tables, intsets, parseutils],
std/[strutils, tables, parseutils],
msgs, vmdef, vmgen, nimsets, types,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
@@ -2425,12 +2425,9 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
setupGlobalCtx(module, g, idgen)
var c = PCtx g.vm
let oldMode = c.mode
let oldLocals = c.locals
c.mode = mode
c.locals = initIntSet()
c.cannotEval = false
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
c.locals = oldLocals
if c.cannotEval:
return errorNode(idgen, prc, n)
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import std/[tables, strutils, intsets]
import std/[tables, strutils]
import ast, idents, options, modulegraphs, lineinfos
@@ -272,7 +272,6 @@ type
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
cannotEval*: bool
locals*: IntSet
PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object

View File

@@ -1583,7 +1583,6 @@ proc checkCanEval(c: PCtx; n: PNode) =
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
elif s.kind in {skVar, skLet} and s.id in c.locals: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
@@ -1976,7 +1975,7 @@ proc genVarSection(c: PCtx; n: PNode) =
c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
elif a[0].kind == nkSym:
let s = a[0].sym
c.locals.incl(s.id)
checkCanEval(c, a[0])
if s.isGlobal:
let runtimeAccessToCompileTime = c.mode == emRepl and
sfCompileTime in s.flags and s.position > 0

View File

@@ -5186,22 +5186,22 @@ caught by reference. Example:
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b = ""
var b: cstring
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = $e.what()
doAssert b == "foo2"
b = e.what()
doAssert $b == "foo2"
try: raise initStdException()
except CStdException: discard
try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = $e.what()
b = e.what()
except CStdException:
doAssert false
doAssert b == "foo3"
doAssert $b == "foo3"
fn()
```
@@ -9043,119 +9043,3 @@ This means the following compiles (for now) even though it really should not:
inc i
access a[i].v
```
Strict definitions and `out` parameters
=======================================
*every* local variable must be initialized explicitly before it can be used:
```nim
proc test =
var s: seq[string]
s.add "abc" # invalid!
```
Needs to be written as:
```nim
proc test =
var s: seq[string] = @[]
s.add "abc" # valid!
```
A control flow analysis is performed in order to prove that a variable has been written to
before it is used. Thus the following is valid:
```nim
proc test(cond: bool) =
var s: seq[string]
if cond:
s = @["y"]
else:
s = @[]
s.add "abc" # valid!
```
In this example every path does set `s` to a value before it is used.
```nim
proc test(cond: bool) =
let s: seq[string]
if cond:
s = @["y"]
else:
s = @[]
```
`let` statements are allowed to not have an initial value, but every path should set `s` to a value before it is used.
`out` parameters
----------------
An `out` parameter is like a `var` parameter but it must be written to before it can be used:
```nim
proc myopen(f: out File; name: string): bool =
f = default(File)
result = open(f, name)
```
While it is usually the better style to use the return type in order to return results API and ABI
considerations might make this infeasible. Like for `var T` Nim maps `out T` to a hidden pointer.
For example POSIX's `stat` routine can be wrapped as:
```nim
proc stat*(a1: cstring, a2: out Stat): cint {.importc, header: "<sys/stat.h>".}
```
When the implementation of a routine with output parameters is analysed, the compiler
checks that every path before the (implicit or explicit) return does set every output
parameter:
```nim
proc p(x: out int; y: out string; cond: bool) =
x = 4
if cond:
y = "abc"
# error: not every path initializes 'y'
```
Out parameters and exception handling
-------------------------------------
The analysis should take exceptions into account (but currently does not):
```nim
proc p(x: out int; y: out string; cond: bool) =
x = canRaise(45)
y = "abc" # <-- error: not every path initializes 'y'
```
Once the implementation takes exceptions into account it is easy enough to
use `outParam = default(typeof(outParam))` in the beginning of the proc body.
Out parameters and inheritance
------------------------------
It is not valid to pass an lvalue of a supertype to an `out T` parameter:
```nim
type
Superclass = object of RootObj
a: int
Subclass = object of Superclass
s: string
proc init(x: out Superclass) =
x = Superclass(a: 8)
var v: Subclass
init v
use v.s # the 's' field was never initialized!
```
However, in the future this could be allowed and provide a better way to write object
constructors that take inheritance into account.

View File

@@ -1919,6 +1919,136 @@ restrictions / changes:
yet performed for ordinary slices outside of a `parallel` section.
Strict definitions and `out` parameters
=======================================
With `experimental: "strictDefs"` *every* local variable must be initialized explicitly before it can be used:
```nim
{.experimental: "strictDefs".}
proc test =
var s: seq[string]
s.add "abc" # invalid!
```
Needs to be written as:
```nim
{.experimental: "strictDefs".}
proc test =
var s: seq[string] = @[]
s.add "abc" # valid!
```
A control flow analysis is performed in order to prove that a variable has been written to
before it is used. Thus the following is valid:
```nim
{.experimental: "strictDefs".}
proc test(cond: bool) =
var s: seq[string]
if cond:
s = @["y"]
else:
s = @[]
s.add "abc" # valid!
```
In this example every path does set `s` to a value before it is used.
```nim
{.experimental: "strictDefs".}
proc test(cond: bool) =
let s: seq[string]
if cond:
s = @["y"]
else:
s = @[]
```
With `experimental: "strictDefs"`, `let` statements are allowed to not have an initial value, but every path should set `s` to a value before it is used.
`out` parameters
----------------
An `out` parameter is like a `var` parameter but it must be written to before it can be used:
```nim
proc myopen(f: out File; name: string): bool =
f = default(File)
result = open(f, name)
```
While it is usually the better style to use the return type in order to return results API and ABI
considerations might make this infeasible. Like for `var T` Nim maps `out T` to a hidden pointer.
For example POSIX's `stat` routine can be wrapped as:
```nim
proc stat*(a1: cstring, a2: out Stat): cint {.importc, header: "<sys/stat.h>".}
```
When the implementation of a routine with output parameters is analysed, the compiler
checks that every path before the (implicit or explicit) return does set every output
parameter:
```nim
proc p(x: out int; y: out string; cond: bool) =
x = 4
if cond:
y = "abc"
# error: not every path initializes 'y'
```
Out parameters and exception handling
-------------------------------------
The analysis should take exceptions into account (but currently does not):
```nim
proc p(x: out int; y: out string; cond: bool) =
x = canRaise(45)
y = "abc" # <-- error: not every path initializes 'y'
```
Once the implementation takes exceptions into account it is easy enough to
use `outParam = default(typeof(outParam))` in the beginning of the proc body.
Out parameters and inheritance
------------------------------
It is not valid to pass an lvalue of a supertype to an `out T` parameter:
```nim
type
Superclass = object of RootObj
a: int
Subclass = object of Superclass
s: string
proc init(x: out Superclass) =
x = Superclass(a: 8)
var v: Subclass
init v
use v.s # the 's' field was never initialized!
```
However, in the future this could be allowed and provide a better way to write object
constructors that take inheritance into account.
**Note**: The implementation of "strict definitions" and "out parameters" is experimental but the concept
is solid and it is expected that eventually this mode becomes the default in later versions.
Strict case objects
===================

View File

@@ -242,7 +242,6 @@ else:
`=destroy`(pattern.captureNameToId)
proc getinfo[T](pattern: Regex, opt: cint): T =
result = default(T)
let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result)
if retcode < 0:
@@ -276,8 +275,8 @@ proc initRegex(pattern: string, flags: int, study = true): Regex =
new(result, destroyRegex)
result.pattern = pattern
var errorMsg: cstring = ""
var errOffset: cint = 0
var errorMsg: cstring
var errOffset: cint
result.pcreObj = pcre.compile(cstring(pattern),
# better hope int is at least 4 bytes..
@@ -289,7 +288,7 @@ proc initRegex(pattern: string, flags: int, study = true): Regex =
if study:
var options: cint = 0
var hasJit: cint = cint(0)
var hasJit: cint
if pcre.config(pcre.CONFIG_JIT, addr hasJit) == 0:
if hasJit == 1'i32:
options = pcre.STUDY_JIT_COMPILE
@@ -314,7 +313,7 @@ proc matchesCrLf(pattern: Regex): bool =
return true
# get flags from build config
var confFlags: cint = cint(0)
var confFlags: cint
if pcre.config(pcre.CONFIG_NEWLINE, addr confFlags) != 0:
assert(false, "CONFIG_NEWLINE apparently got screwed up")
@@ -574,7 +573,7 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R
pcre.UTF8) > 0u32
let strlen = if endpos == int.high: str.len else: endpos+1
var offset = start
var match: Option[RegexMatch] = default(Option[RegexMatch])
var match: Option[RegexMatch]
var neverMatched = true
while true:
@@ -763,7 +762,7 @@ proc escapeRe*(str: string): string {.gcsafe.} =
const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(',
')', '{', '}', '=', '!', '<', '>', '|', ':',
'-'}
result = ""
for c in items(str):
case c
of SpecialCharMatcher:

View File

@@ -466,7 +466,7 @@ template `=~` *(s: string, pattern: Regex): untyped =
doAssert parse(" # comment ... ") == """("# comment ... ",)"""
bind MaxSubpatterns
when not declaredInScope(matches):
var matches {.inject.}: array[MaxSubpatterns, string] = default(array[MaxSubpatterns, string])
var matches {.inject.}: array[MaxSubpatterns, string]
match(s, pattern, matches)
# ------------------------- more string handling ------------------------------

View File

@@ -470,6 +470,12 @@ typedef char* NCSTRING;
#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
#define STRING_LITERAL(name, str, length) \
static const struct { \
TGenericSeq Sup; \
NIM_CHAR data[(length) + 1]; \
} name = {{length, (NI) ((NU)length | NIM_STRLIT_FLAG)}, str}
/* declared size of a sequence/variable length array: */
#if defined(__cplusplus) && defined(__clang__)
# define SEQ_DECL_SIZE 1

View File

@@ -143,7 +143,6 @@ proc reversed*[T](a: openArray[T]): seq[T] {.inline.} =
runnableExamples:
assert [10, 11, 12].reversed == @[12, 11, 10]
assert seq[string].default.reversed == @[]
result = @[]
let n = a.len
result.setLen(n)
for i in 0..<n: result[i] = a[n - (i + 1)]

View File

@@ -264,9 +264,9 @@ proc asyncSingleProc(prc: NimNode): NimNode =
procBody.insert(0): quote do:
{.push warning[resultshadowed]: off.}
when `subRetType` isnot void:
var `resultIdent`: `subRetType` = default(`subRetType`)
var `resultIdent`: `subRetType`
else:
var `resultIdent`: Future[void] = nil
var `resultIdent`: Future[void]
{.pop.}
var `needsCompletionSym` = false

View File

@@ -151,12 +151,10 @@ proc encode*[T: byte|char](s: openArray[T], safe = false): string =
assert encode(['n', 'i', 'm']) == "bmlt"
assert encode(@['n', 'i', 'm']) == "bmlt"
assert encode([1'u8, 2, 3, 4, 5]) == "AQIDBAU="
result = ""
encodeImpl()
proc encode*[T: SomeInteger and not byte](s: openArray[T], safe = false): string
{.deprecated: "use `byte` or `char` instead".} =
result = ""
encodeImpl()
proc encodeMime*(s: string, lineLen = 75.Positive, newLine = "\r\n",

View File

@@ -67,7 +67,6 @@ func len*[T](c: CritBitTree[T]): int {.inline.} =
result = c.count
proc rawGet[T](c: CritBitTree[T], key: string): Node[T] =
result = nil
var it = c.root
while it != nil:
if not it.isLeaf:
@@ -146,7 +145,7 @@ func exclImpl[T](c: var CritBitTree[T], key: string): int =
var whereq: ptr Node[T] = nil
if p == nil: return c.count
var dir = 0
var q: Node[T] = nil
var q: Node[T]
while not p.isLeaf:
whereq = wherep
q = p
@@ -395,7 +394,6 @@ iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] =
for x in leaves(c.root): yield (x.key, x.val)
proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] =
result = nil
var p = c.root
var top = p
if p != nil:

View File

@@ -92,7 +92,6 @@ proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] =
##
## **See also:**
## * `toDeque proc <#toDeque,openArray[T]>`_
result = Deque[T]()
result.initImpl(initialSize)
func len*[T](deq: Deque[T]): int {.inline.} =
@@ -298,7 +297,7 @@ proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} =
let a = toDeque([7, 8, 9])
assert len(a) == 3
assert $a == "[7, 8, 9]"
result = Deque[T]()
result.initImpl(x.len)
for item in items(x):
result.addLast(item)

View File

@@ -157,7 +157,7 @@ proc toHeapQueue*[T](x: openArray[T]): HeapQueue[T] {.since: (1, 3).} =
assert heap[0] == 8
# see https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap
result = HeapQueue[T](data: @x)
result.data = @x
for i in countdown(x.len div 2 - 1, 0):
siftdown(result, i)

View File

@@ -115,7 +115,7 @@ proc initSinglyLinkedList*[T](): SinglyLinkedList[T] =
runnableExamples:
let a = initSinglyLinkedList[int]()
result = default(SinglyLinkedList[T])
discard
proc initDoublyLinkedList*[T](): DoublyLinkedList[T] =
## Creates a new doubly linked list that is empty.
@@ -125,7 +125,7 @@ proc initDoublyLinkedList*[T](): DoublyLinkedList[T] =
runnableExamples:
let a = initDoublyLinkedList[int]()
result = default(DoublyLinkedList[T])
discard
proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] =
## Creates a new singly linked ring that is empty.
@@ -135,7 +135,7 @@ proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] =
runnableExamples:
let a = initSinglyLinkedRing[int]()
result = default(SinglyLinkedRing[T])
discard
proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
## Creates a new doubly linked ring that is empty.
@@ -145,7 +145,7 @@ proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
runnableExamples:
let a = initDoublyLinkedRing[int]()
result = default(DoublyLinkedRing[T])
discard
proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
## Creates a new doubly linked node with the given `value`.
@@ -319,10 +319,6 @@ proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] =
let a = [9, 8].toSinglyLinkedList
assert a.find(9).value == 9
assert a.find(1) == nil
when typeof(nodes(L)) is SinglyLinkedNode[T]:
result = SinglyLinkedNode[T](nil)
else:
result = DoublyLinkedNode[T](nil)
for x in nodes(L):
if x.value == value: return x

View File

@@ -167,7 +167,7 @@ func count*[T](s: openArray[T], x: T): int =
assert count(a, 2) == 4
assert count(a, 99) == 0
assert count(b, 'r') == 2
result = 0
for itm in items(s):
if itm == x:
inc result
@@ -244,7 +244,7 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
assert minIndex(b) == 3
assert minIndex(c) == 1
assert minIndex(d) == 2
result = 0
for i in 1..high(s):
if s[i] < s[result]: result = i
@@ -261,7 +261,7 @@ func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
assert maxIndex(b) == 0
assert maxIndex(c) == 2
assert maxIndex(d) == 0
result = 0
for i in 1..high(s):
if s[i] > s[result]: result = i

View File

@@ -45,7 +45,7 @@ proc enlarge[A](s: var HashSet[A]) =
template inclImpl() {.dirty.} =
if s.data.len == 0:
initImpl(s, defaultInitialSize)
var hc: Hash = default(Hash)
var hc: Hash
var index = rawGet(s, key, hc)
if index < 0:
if mustRehash(s):

View File

@@ -670,7 +670,7 @@ proc initOrderedSet*[A](initialSize = defaultInitialSize): OrderedSet[A] =
var a = initOrderedSet[int]()
a.incl(3)
assert len(a) == 1
result = OrderedSet[A]()
result.init(initialSize)
proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =

View File

@@ -139,15 +139,12 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A,
proc mget*[A, B](t: var SharedTable[A, B], key: A): var B =
## Retrieves the value at `t[key]`. The value can be modified.
## If `key` is not in `t`, the `KeyError` exception is raised.
acquire(t.lock)
var hc: Hash = Hash(0)
var index = rawGet(t, key, hc)
let hasKey = index >= 0
if hasKey:
result = t.data[index].val
release(t.lock)
else:
release(t.lock)
withLock t:
var hc: Hash
var index = rawGet(t, key, hc)
let hasKey = index >= 0
if hasKey: result = t.data[index].val
if not hasKey:
when compiles($key):
raise newException(KeyError, "key not found: " & $key)
else:

View File

@@ -30,7 +30,7 @@ proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline, outParamsAt: [3
rawGetDeepImpl()
proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B],
key: sink A, val: sink B, hc: Hash, h: Hash) =
key: A, val: sink B, hc: Hash, h: Hash) =
rawInsertImpl()
template checkIfInitialized() =

View File

@@ -281,7 +281,7 @@ proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] =
result = default(Table[A, B])
initImpl(result, initialSize)
proc `[]=`*[A, B](t: var Table[A, B], key: sink A, val: sink B) =
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) =
## Inserts a `(key, value)` pair into `t`.
##
## See also:
@@ -313,7 +313,7 @@ proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] =
result = initTable[A, B](pairs.len)
for key, val in items(pairs): result[key] = val
proc `[]`*[A, B](t: Table[A, B], key: sink A): lent B =
proc `[]`*[A, B](t: Table[A, B], key: A): lent B =
## Retrieves the value at `t[key]`.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -336,7 +336,7 @@ proc `[]`*[A, B](t: Table[A, B], key: sink A): lent B =
echo a['z']
get(t, key)
proc `[]`*[A, B](t: var Table[A, B], key: sink A): var B =
proc `[]`*[A, B](t: var Table[A, B], key: A): var B =
## Retrieves the value at `t[key]`. The value can be modified.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -494,7 +494,7 @@ proc len*[A, B](t: Table[A, B]): int =
result = t.counter
proc add*[A, B](t: var Table[A, B], key: sink A, val: sink B) {.deprecated:
proc add*[A, B](t: var Table[A, B], key: A, val: sink B) {.deprecated:
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
##
@@ -628,7 +628,7 @@ template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) =
assert t[1].uid == 1314
mixin rawGet
var hc: Hash = default(Hash)
var hc: Hash
var index = rawGet(t, key, hc)
let hasKey = index >= 0
if hasKey:
@@ -677,7 +677,7 @@ template withValue*[A, B](t: var Table[A, B], key: A,
body2
iterator pairs*[A, B](t: Table[A, B]): (lent A, lent B) =
iterator pairs*[A, B](t: Table[A, B]): (A, B) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -864,7 +864,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
for item in collection:
result[index(item)] = item
proc `[]`*[A, B](t: TableRef[A, B], key: sink A): var B =
proc `[]`*[A, B](t: TableRef[A, B], key: A): var B =
## Retrieves the value at `t[key]`.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -888,7 +888,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: sink A): var B =
result = t[][key]
proc `[]=`*[A, B](t: TableRef[A, B], key: sink A, val: sink B) =
proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: sink B) =
## Inserts a `(key, value)` pair into `t`.
##
## See also:
@@ -1045,7 +1045,7 @@ proc len*[A, B](t: TableRef[A, B]): int =
result = t.counter
proc add*[A, B](t: TableRef[A, B], key: sink A, val: sink B) {.deprecated:
proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated:
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
##
@@ -1139,7 +1139,7 @@ proc `==`*[A, B](s, t: TableRef[A, B]): bool =
iterator pairs*[A, B](t: TableRef[A, B]): (lent A, lent B) =
iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -1297,7 +1297,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
proc rawInsert[A, B](t: var OrderedTable[A, B],
data: var OrderedKeyValuePairSeq[A, B],
key: sink A, val: sink B, hc: Hash, h: Hash) =
key: A, val: sink B, hc: Hash, h: Hash) =
rawInsertImpl()
data[h].next = -1
if t.first < 0: t.first = h
@@ -1349,7 +1349,7 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A,
result = default(OrderedTable[A, B])
initImpl(result, initialSize)
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: sink A, val: sink B) =
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) =
## Inserts a `(key, value)` pair into `t`.
##
## See also:
@@ -1382,7 +1382,7 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] =
result = initOrderedTable[A, B](pairs.len)
for key, val in items(pairs): result[key] = val
proc `[]`*[A, B](t: OrderedTable[A, B], key: sink A): lent B =
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): lent B =
## Retrieves the value at `t[key]`.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -1406,7 +1406,7 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: sink A): lent B =
get(t, key)
proc `[]`*[A, B](t: var OrderedTable[A, B], key: sink A): var B =
proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B =
## Retrieves the value at `t[key]`. The value can be modified.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -1547,7 +1547,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
result = t.counter
proc add*[A, B](t: var OrderedTable[A, B], key: sink A, val: sink B) {.deprecated:
proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated:
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
##
@@ -1727,7 +1727,7 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool =
iterator pairs*[A, B](t: OrderedTable[A, B]): (lent A, lent B) =
iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
## Iterates over any `(key, value)` pair in the table `t` in insertion
## order.
##
@@ -1884,7 +1884,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
for key, val in items(pairs): result[key] = val
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: sink A): var B =
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
## Retrieves the value at `t[key]`.
##
## If `key` is not in `t`, the `KeyError` exception is raised.
@@ -1907,7 +1907,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: sink A): var B =
echo a['z']
result = t[][key]
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: sink A, val: sink B) =
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) =
## Inserts a `(key, value)` pair into `t`.
##
## See also:
@@ -2048,7 +2048,7 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
result = t.counter
proc add*[A, B](t: OrderedTableRef[A, B], key: sink A, val: sink B) {.deprecated:
proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated:
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
##
@@ -2150,7 +2150,7 @@ proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool =
iterator pairs*[A, B](t: OrderedTableRef[A, B]): (lent A, lent B) =
iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
## Iterates over any `(key, value)` pair in the table `t` in insertion
## order.
##
@@ -2345,7 +2345,7 @@ proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
result = initCountTable[A](keys.len)
for key in items(keys): result.inc(key)
proc `[]`*[A](t: CountTable[A], key: sink A): int =
proc `[]`*[A](t: CountTable[A], key: A): int =
## Retrieves the value at `t[key]` if `key` is in `t`.
## Otherwise `0` is returned.
##
@@ -2413,7 +2413,8 @@ proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
for h in 0 .. high(t.data):
if t.data[h].val > 0 and (minIdx == -1 or t.data[minIdx].val > t.data[h].val):
minIdx = h
result = (t.data[minIdx].key, t.data[minIdx].val)
result.key = t.data[minIdx].key
result.val = t.data[minIdx].val
proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
## Returns the `(key, value)` pair with the largest `val`. Efficiency: O(n)
@@ -2424,7 +2425,8 @@ proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
var maxIdx = 0
for h in 1 .. high(t.data):
if t.data[maxIdx].val < t.data[h].val: maxIdx = h
result = (t.data[maxIdx].key, t.data[maxIdx].val)
result.key = t.data[maxIdx].key
result.val = t.data[maxIdx].val
proc hasKey*[A](t: CountTable[A], key: A): bool =
## Returns true if `key` is in the table `t`.
@@ -2564,7 +2566,7 @@ proc `==`*[A](s, t: CountTable[A]): bool =
equalsImpl(s, t)
iterator pairs*[A](t: CountTable[A]): (lent A, int) =
iterator pairs*[A](t: CountTable[A]): (A, int) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -2703,7 +2705,7 @@ proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
{.noSideEffect.}:
for key in items(keys): result.inc(key)
proc `[]`*[A](t: CountTableRef[A], key: sink A): int =
proc `[]`*[A](t: CountTableRef[A], key: A): int =
## Retrieves the value at `t[key]` if `key` is in `t`.
## Otherwise `0` is returned.
##
@@ -2845,7 +2847,7 @@ proc `==`*[A](s, t: CountTableRef[A]): bool =
else: result = s[] == t[]
iterator pairs*[A](t: CountTableRef[A]): (lent A, int) =
iterator pairs*[A](t: CountTableRef[A]): (A, int) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -2953,19 +2955,16 @@ iterator mvalues*[A](t: CountTableRef[A]): var int =
assert(len(t) == L, "the length of the table changed while iterating over it")
proc hash*[K,V](s: Table[K,V]): Hash =
result = Hash(0)
for p in pairs(s):
result = result xor hash(p)
result = !$result
proc hash*[K,V](s: OrderedTable[K,V]): Hash =
result = Hash(0)
for p in pairs(s):
result = result !& hash(p)
result = !$result
proc hash*[V](s: CountTable[V]): Hash =
result = Hash(0)
for p in pairs(s):
result = result xor hash(p)
result = !$result

View File

@@ -46,15 +46,18 @@ type
func complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] =
## Returns a `Complex[T]` with real part `re` and imaginary part `im`.
result = Complex[T](re: re, im: im)
result.re = re
result.im = im
func complex32*(re: float32; im: float32 = 0.0): Complex32 =
## Returns a `Complex32` with real part `re` and imaginary part `im`.
result = Complex32(re: re, im: im)
result.re = re
result.im = im
func complex64*(re: float64; im: float64 = 0.0): Complex64 =
## Returns a `Complex64` with real part `re` and imaginary part `im`.
result = Complex64(re: re, im: im)
result.re = re
result.im = im
template im*(arg: typedesc[float32]): Complex32 = complex32(0, 1)
## Returns the imaginary unit (`complex32(0, 1)`).
@@ -82,16 +85,15 @@ func sgn*[T](z: Complex[T]): Complex[T] =
let a = abs(z)
if a != 0:
result = z / a
else:
result = Complex[T]()
func conjugate*[T](z: Complex[T]): Complex[T] =
## Returns the complex conjugate of `z` (`complex(z.re, -z.im)`).
result = Complex[T](re: z.re, im: -z.im)
result.re = z.re
result.im = -z.im
func inv*[T](z: Complex[T]): Complex[T] =
## Returns the multiplicative inverse of `z` (`1/z`).
result = conjugate(z) / abs2(z)
conjugate(z) / abs2(z)
func `==`*[T](x, y: Complex[T]): bool =
## Compares two complex numbers for equality.
@@ -99,48 +101,58 @@ func `==`*[T](x, y: Complex[T]): bool =
func `+`*[T](x: T; y: Complex[T]): Complex[T] =
## Adds a real number to a complex number.
result = Complex[T](re: x + y.re, im: y.im)
result.re = x + y.re
result.im = y.im
func `+`*[T](x: Complex[T]; y: T): Complex[T] =
## Adds a complex number to a real number.
result = Complex[T](re: x.re + y, im: x.im)
result.re = x.re + y
result.im = x.im
func `+`*[T](x, y: Complex[T]): Complex[T] =
## Adds two complex numbers.
result = Complex[T](re: x.re + y.re, im: x.im + y.im)
result.re = x.re + y.re
result.im = x.im + y.im
func `-`*[T](z: Complex[T]): Complex[T] =
## Unary minus for complex numbers.
result = Complex[T](re: -z.re, im: -z.im)
result.re = -z.re
result.im = -z.im
func `-`*[T](x: T; y: Complex[T]): Complex[T] =
## Subtracts a complex number from a real number.
result = Complex[T](re: x - y.re, im: -y.im)
result.re = x - y.re
result.im = -y.im
func `-`*[T](x: Complex[T]; y: T): Complex[T] =
## Subtracts a real number from a complex number.
result = Complex[T](re: x.re - y, im: x.im)
result.re = x.re - y
result.im = x.im
func `-`*[T](x, y: Complex[T]): Complex[T] =
## Subtracts two complex numbers.
result = Complex[T](re: x.re - y.re, im: x.im - y.im)
result.re = x.re - y.re
result.im = x.im - y.im
func `*`*[T](x: T; y: Complex[T]): Complex[T] =
## Multiplies a real number with a complex number.
result = Complex[T](re: x * y.re, im: x * y.im)
result.re = x * y.re
result.im = x * y.im
func `*`*[T](x: Complex[T]; y: T): Complex[T] =
## Multiplies a complex number with a real number.
result = Complex[T](re: x.re * y, im: x.im * y)
result.re = x.re * y
result.im = x.im * y
func `*`*[T](x, y: Complex[T]): Complex[T] =
## Multiplies two complex numbers.
result = Complex[T](re: x.re * y.re - x.im * y.im,
im: x.im * y.re + x.re * y.im)
result.re = x.re * y.re - x.im * y.im
result.im = x.im * y.re + x.re * y.im
func `/`*[T](x: Complex[T]; y: T): Complex[T] =
## Divides a complex number by a real number.
result = Complex[T](re: x.re / y, im: x.im / y)
result.re = x.re / y
result.im = x.im / y
func `/`*[T](x: T; y: Complex[T]): Complex[T] =
## Divides a real number by a complex number.
@@ -190,9 +202,10 @@ func sqrt*[T](z: Complex[T]): Complex[T] =
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1.0 + r * r)))
if z.re >= 0.0:
result = Complex[T](re: w, im: z.im / (w * 2.0))
result.re = w
result.im = z.im / (w * 2.0)
else:
result = Complex[T](im: if z.im >= 0.0: w else: -w)
result.im = if z.im >= 0.0: w else: -w
result.re = z.im / (result.im + result.im)
func exp*[T](z: Complex[T]): Complex[T] =
@@ -200,13 +213,15 @@ func exp*[T](z: Complex[T]): Complex[T] =
let
rho = exp(z.re)
theta = z.im
result = Complex[T](re: rho * cos(theta), im: rho * sin(theta))
result.re = rho * cos(theta)
result.im = rho * sin(theta)
func ln*[T](z: Complex[T]): Complex[T] =
## Returns the
## ([principal value](https://en.wikipedia.org/wiki/Complex_logarithm#Principal_value)
## of the) natural logarithm of `z`.
result = Complex[T](re: ln(abs(z)), im: arctan2(z.im, z.re))
result.re = ln(abs(z))
result.im = arctan2(z.im, z.re)
func log10*[T](z: Complex[T]): Complex[T] =
## Returns the logarithm base 10 of `z`.
@@ -226,9 +241,11 @@ func pow*[T](x, y: Complex[T]): Complex[T] =
## `x` raised to the power of `y`.
if x.re == 0.0 and x.im == 0.0:
if y.re == 0.0 and y.im == 0.0:
result = Complex[T](re: 1.0, im: 0.0)
result.re = 1.0
result.im = 0.0
else:
result = Complex[T](re: 0.0, im: 0.0)
result.re = 0.0
result.im = 0.0
elif y.im == 0.0:
if y.re == 1.0:
result = x
@@ -240,7 +257,8 @@ func pow*[T](x, y: Complex[T]): Complex[T] =
result = sqrt(x)
elif x.im == 0.0:
# Revert to real pow when both base and exponent are real
result = Complex[T](re: pow(x.re, y.re), im: 0.0)
result.re = pow(x.re, y.re)
result.im = 0.0
else:
# Special case when the exponent is real
let
@@ -248,7 +266,8 @@ func pow*[T](x, y: Complex[T]): Complex[T] =
theta = arctan2(x.im, x.re)
s = pow(rho, y.re)
r = y.re * theta
result = Complex[T](re: s * cos(r), im: s * sin(r))
result.re = s * cos(r)
result.im = s * sin(r)
elif x.im == 0.0 and x.re == E:
# Special case Euler's formula
result = exp(y)
@@ -258,15 +277,18 @@ func pow*[T](x, y: Complex[T]): Complex[T] =
theta = arctan2(x.im, x.re)
s = pow(rho, y.re) * exp(-y.im * theta)
r = y.re * theta + y.im * ln(rho)
result = Complex[T](re: s * cos(r), im: s * sin(r))
result.re = s * cos(r)
result.im = s * sin(r)
func pow*[T](x: Complex[T]; y: T): Complex[T] =
## The complex number `x` raised to the power of the real number `y`.
pow(x, complex[T](y))
func sin*[T](z: Complex[T]): Complex[T] =
## Returns the sine of `z`.
result = Complex[T](re: sin(z.re) * cosh(z.im), im: cos(z.re) * sinh(z.im))
result.re = sin(z.re) * cosh(z.im)
result.im = cos(z.re) * sinh(z.im)
func arcsin*[T](z: Complex[T]): Complex[T] =
## Returns the inverse sine of `z`.
@@ -274,9 +296,8 @@ func arcsin*[T](z: Complex[T]): Complex[T] =
func cos*[T](z: Complex[T]): Complex[T] =
## Returns the cosine of `z`.
result = Complex[T](re: cos(z.re) * cosh(z.im),
im: -sin(z.re) * sinh(z.im)
)
result.re = cos(z.re) * cosh(z.im)
result.im = -sin(z.re) * sinh(z.im)
func arccos*[T](z: Complex[T]): Complex[T] =
## Returns the inverse cosine of `z`.

View File

@@ -1213,7 +1213,7 @@ proc request*(client: HttpClient | AsyncHttpClient, url: Uri | string,
redirectBody = body
else:
# Unreachable
raiseAssert "unreachable"
doAssert(false)
# Check if the redirection is to the same domain or a sub-domain (foo.com
# -> sub.foo.com)

View File

@@ -1256,7 +1256,7 @@ proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathL
when nimvm:
when isRefSkipDistinct(`tmpSym`.`fieldSym`):
# workaround #12489
var tmp: `fieldType` = default(typeof(`fieldType`))
var tmp: `fieldType`
initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`)
`tmpSym`.`fieldSym` = tmp
else:
@@ -1272,7 +1272,7 @@ proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathL
let kindType = typeNode[0][1]
let kindOffsetLit = newLit(uint(getOffset(kindSym)))
dst.add quote do:
var kindTmp: `kindType` = default(typeof(`kindType`))
var kindTmp: `kindType`
jsonPath.add `kindPathLit`
initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`)
jsonPath.setLen `originalJsonPathLen`

View File

@@ -312,7 +312,7 @@ proc store*[T](s: Stream, data: sink T) =
storeAny(s, toAny(d), stored)
proc loadVM[T](typ: typedesc[T], x: T): string =
raiseAssert "the implementation is in the compiler/vmops"
discard "the implementation is in the compiler/vmops"
proc `$$`*[T](x: sink T): string =
## Returns a string representation of `x` (serialization, marshalling).
@@ -343,7 +343,7 @@ proc `$$`*[T](x: sink T): string =
result = s.data
proc toVM[T](typ: typedesc[T], data: string): T =
raiseAssert "the implementation is in the compiler/vmops"
discard "the implementation is in the compiler/vmops"
proc to*[T](data: string): T =
## Reads data and transforms it to a type `T` (deserialization, unmarshalling).
@@ -363,6 +363,5 @@ proc to*[T](data: string): T =
when nimvm:
result = toVM(T, data)
else:
result = default(T)
var tab = initTable[BiggestInt, pointer]()
loadAny(newStringStream(data), toAny(result), tab)

View File

@@ -105,7 +105,7 @@ when not defined(js) and not defined(nimscript): # C
when compileOption("overflowChecks"):
if y == 0:
raise new(DivByZeroDefect)
elif (x == T.low and int64(y) == -1):
elif (x == T.low and y == -1.T):
raise new(OverflowDefect)
let res = divmod_c(x, y)
result[0] = res.quot
@@ -989,9 +989,8 @@ func frexp*[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} =
doAssert frexp(Inf).frac == Inf # +- Inf preserved
doAssert frexp(NaN).frac.isNaN
result = default(tuple[frac: T, exp: int])
when not defined(js):
var exp: cint = cint(0)
var exp: cint
result.frac = c_frexp2(x, exp)
result.exp = exp
else:
@@ -1069,8 +1068,10 @@ func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
runnableExamples:
doAssert splitDecimal(5.25) == (intpart: 5.0, floatpart: 0.25)
doAssert splitDecimal(-2.73) == (intpart: -2.0, floatpart: -0.73)
result = default(tuple[intpart: T, floatpart: T])
var absolute: T = abs(x)
var
absolute: T
absolute = abs(x)
result.intpart = floor(absolute)
result.floatpart = absolute - result.intpart
if x < 0:
@@ -1127,7 +1128,7 @@ func sum*[T](x: openArray[T]): T =
runnableExamples:
doAssert sum([1, 2, 3, 4]) == 10
doAssert sum([-4, 3, 5]) == 4
result = default(T)
for i in items(x): result = result + i
func prod*[T](x: openArray[T]): T =
@@ -1186,7 +1187,7 @@ func cumsummed*[T](x: openArray[T]): seq[T] =
## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version
runnableExamples:
doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10]
result = @[]
let xLen = x.len
if xLen == 0:
return @[]

View File

@@ -186,7 +186,6 @@ proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i
var num64: int64
doAssert parseHex("4E69ED4E69ED", num64) == 12
doAssert num64 == 86216859871725
result = 0
var i = 0
var output = T(0)
var foundDigit = false

View File

@@ -563,8 +563,6 @@ template matchOrParse(mopProc: untyped) =
# are provided which just return *discard*.
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe, raises: [].} =
result = 0
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
# Parse handler code must run in an *of* clause of its own for each
# *PegKind*, so we encapsulate the identical clause body for
@@ -581,7 +579,7 @@ template matchOrParse(mopProc: untyped) =
n = Peg(kind: pkTerminalIgnoreStyle, term: s.substr(a, b))
of pkBackRefIgnoreCase:
n = Peg(kind: pkTerminalIgnoreCase, term: s.substr(a, b))
else: raiseAssert "impossible case"
else: assert(false, "impossible case")
mopProc(s, n, start, c)
case p.kind
@@ -697,7 +695,7 @@ template matchOrParse(mopProc: untyped) =
enter(pkTerminalIgnoreStyle, s, p, start)
var
i = 0
a, b: Rune = default(Rune)
a, b: Rune
result = start
while i < len(p.term):
while i < len(p.term):
@@ -1069,7 +1067,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) =
proc parser(s: string): int {.gensym.} =
# the proc to be returned
var
ms: array[MaxSubpatterns, (int, int)] = default(array[MaxSubpatterns, (int, int)])
ms: array[MaxSubpatterns, (int, int)]
cs = Captures(matches: ms, ml: 0, origStart: 0)
rawParse(s, pegAst, 0, cs)
parser

View File

@@ -228,7 +228,6 @@ proc skipRandomNumbers*(s: var Rand) =
proc rand[T: uint | uint64](r: var Rand; max: T): T =
# xxx export in future work
result = default(T)
if max == 0: return
else:
let max = uint64(max)

View File

@@ -57,7 +57,8 @@ func initRational*[T: SomeInteger](num, den: T): Rational[T] =
##
## **Note:** `den != 0` is not checked when assertions are turned off.
assert(den != 0, "a denominator of zero is invalid")
result = Rational[T](num: num, den: den)
result.num = num
result.den = den
reduce(result)
func `//`*[T](num, den: T): Rational[T] =
@@ -79,7 +80,9 @@ func toRational*[T: SomeInteger](x: T): Rational[T] =
## Converts some integer `x` to a rational number.
runnableExamples:
doAssert toRational(42) == 42 // 1
result = Rational[T](num: x, den: 1)
result.num = x
result.den = 1
func toRational*(x: float,
n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] =
@@ -122,18 +125,19 @@ func toInt*[T](x: Rational[T]): int =
func `+`*[T](x, y: Rational[T]): Rational[T] =
## Adds two rational numbers.
let common = lcm(x.den, y.den)
result = Rational[T](num: common div x.den * x.num + common div y.den * y.num,
den: common
)
result.num = common div x.den * x.num + common div y.den * y.num
result.den = common
reduce(result)
func `+`*[T](x: Rational[T], y: T): Rational[T] =
## Adds the rational `x` to the int `y`.
result = Rational[T](num: x.num + y * x.den, den: x.den)
result.num = x.num + y * x.den
result.den = x.den
func `+`*[T](x: T, y: Rational[T]): Rational[T] =
## Adds the int `x` to the rational `y`.
result = Rational[T](num: x * y.den + y.num, den: y.den)
result.num = x * y.den + y.num
result.den = y.den
func `+=`*[T](x: var Rational[T], y: Rational[T]) =
## Adds the rational `y` to the rational `x` in-place.
@@ -148,23 +152,25 @@ func `+=`*[T](x: var Rational[T], y: T) =
func `-`*[T](x: Rational[T]): Rational[T] =
## Unary minus for rational numbers.
result = Rational[T](num: -x.num, den: x.den)
result.num = -x.num
result.den = x.den
func `-`*[T](x, y: Rational[T]): Rational[T] =
## Subtracts two rational numbers.
let common = lcm(x.den, y.den)
result = Rational[T](num: common div x.den * x.num - common div y.den * y.num,
den: common
)
result.num = common div x.den * x.num - common div y.den * y.num
result.den = common
reduce(result)
func `-`*[T](x: Rational[T], y: T): Rational[T] =
## Subtracts the int `y` from the rational `x`.
result = Rational[T](num: x.num - y * x.den, den: x.den)
result.num = x.num - y * x.den
result.den = x.den
func `-`*[T](x: T, y: Rational[T]): Rational[T] =
## Subtracts the rational `y` from the int `x`.
result = Rational[T](num: x * y.den - y.num, den: y.den)
result.num = x * y.den - y.num
result.den = y.den
func `-=`*[T](x: var Rational[T], y: Rational[T]) =
## Subtracts the rational `y` from the rational `x` in-place.
@@ -179,17 +185,20 @@ func `-=`*[T](x: var Rational[T], y: T) =
func `*`*[T](x, y: Rational[T]): Rational[T] =
## Multiplies two rational numbers.
result = Rational[T](num: x.num * y.num, den: x.den * y.den)
result.num = x.num * y.num
result.den = x.den * y.den
reduce(result)
func `*`*[T](x: Rational[T], y: T): Rational[T] =
## Multiplies the rational `x` with the int `y`.
result = Rational[T](num: x.num * y, den: x.den)
result.num = x.num * y
result.den = x.den
reduce(result)
func `*`*[T](x: T, y: Rational[T]): Rational[T] =
## Multiplies the int `x` with the rational `y`.
result = Rational[T](num: x * y.num, den: y.den)
result.num = x * y.num
result.den = y.den
reduce(result)
func `*=`*[T](x: var Rational[T], y: Rational[T]) =
@@ -207,25 +216,30 @@ func reciprocal*[T](x: Rational[T]): Rational[T] =
## Calculates the reciprocal of `x` (`1/x`).
## If `x` is 0, raises `DivByZeroDefect`.
if x.num > 0:
result = Rational[T](num: x.den, den: x.num)
result.num = x.den
result.den = x.num
elif x.num < 0:
result = Rational[T](num: -x.den, den: -x.num)
result.num = -x.den
result.den = -x.num
else:
raise newException(DivByZeroDefect, "division by zero")
func `/`*[T](x, y: Rational[T]): Rational[T] =
## Divides the rational `x` by the rational `y`.
result = Rational[T](num: x.num * y.den, den: x.den * y.num)
result.num = x.num * y.den
result.den = x.den * y.num
reduce(result)
func `/`*[T](x: Rational[T], y: T): Rational[T] =
## Divides the rational `x` by the int `y`.
result = Rational[T](num: x.num, den: x.den * y)
result.num = x.num
result.den = x.den * y
reduce(result)
func `/`*[T](x: T, y: Rational[T]): Rational[T] =
## Divides the int `x` by the rational `y`.
result = Rational[T](num: x * y.den, den: y.num)
result.num = x * y.den
result.den = y.num
reduce(result)
func `/=`*[T](x: var Rational[T], y: Rational[T]) =
@@ -263,7 +277,9 @@ func abs*[T](x: Rational[T]): Rational[T] =
runnableExamples:
doAssert abs(1 // 2) == 1 // 2
doAssert abs(-1 // 2) == 1 // 2
result = Rational[T](num: abs x.num, den: abs x.den)
result.num = abs x.num
result.den = abs x.den
func `div`*[T: SomeInteger](x, y: Rational[T]): T =
## Computes the rational truncated division.
@@ -295,7 +311,6 @@ func floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] =
func hash*[T](x: Rational[T]): Hash =
## Computes the hash for the rational `x`.
# reduce first so that hash(x) == hash(y) for x == y
result = Hash(0)
var copy = x
reduce(copy)
@@ -316,8 +331,10 @@ func `^`*[T: SomeInteger](x: Rational[T], y: T): Rational[T] =
doAssert (-3 // 5) ^ -2 == (25 // 9)
if y >= 0:
result = Rational[T](num: x.num ^ y, den: x.den ^ y)
result.num = x.num ^ y
result.den = x.den ^ y
else:
result = Rational[T](num: x.den ^ -y, den: x.num ^ -y)
result.num = x.den ^ -y
result.den = x.num ^ -y
# Note that all powers of reduced rationals are already reduced,
# so we don't need to call reduce() here

View File

@@ -336,7 +336,7 @@ else:
elif defined(zephyr) or defined(freertos):
FD_MAX
else:
var fdLim: RLimit = default(RLimit)
var fdLim: RLimit
var res = int(getrlimit(RLIMIT_NOFILE, fdLim))
if res >= 0:
res = int(fdLim.rlim_cur) - 1

View File

@@ -109,7 +109,7 @@ import std/private/since
import std/exitprocs
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
import std/assertions
import std/[macros, strutils, streams, times, sets, sequtils]
@@ -665,7 +665,9 @@ macro check*(conditions: untyped): untyped =
checkpoint(name & " was " & $value)
proc inspectArgs(exp: NimNode): tuple[assigns, check, printOuts: NimNode] =
result = (newNimNode(nnkStmtList), copyNimTree(exp), newNimNode(nnkStmtList))
result.check = copyNimTree(exp)
result.assigns = newNimNode(nnkStmtList)
result.printOuts = newNimNode(nnkStmtList)
var counter = 0

View File

@@ -110,10 +110,6 @@ when defined(js):
}
if (Number.isSafeInteger(`a`))
`result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0";
else if (isNaN(`a`)) // Number.isNaN is since ES6
`result` = "nan"; // or it'll be "NaN"
else if (!isFinite(`a`)) // Number.isFinite newer but unnecessary here
`result` = `a` > 0 ? "inf" : "-inf"; // or it'll be [-]Infinity
else {
`result` = `a`+"";
if(nimOnlyDigitsOrMinus(`result`)){
@@ -144,5 +140,4 @@ proc addFloat*(result: var string; x: float | float32) {.inline.} =
when defined(nimPreviewSlimSystem):
func `$`*(x: float | float32): string =
## Outplace version of `addFloat`.
result = ""
result.addFloat(x)

View File

@@ -186,7 +186,7 @@ proc discKeyMatch[T](obj: T, json: JsonNode, key: static string): bool =
if not json.hasKey key:
return true
let field = accessField(obj, key)
var jsonVal: typeof(field) = default(typeof(field))
var jsonVal: typeof(field)
fromJson(jsonVal, json[key])
if jsonVal != field:
return false
@@ -295,7 +295,6 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) =
proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T =
## reverse of `toJson`
result = default(T)
fromJson(result, b, opt)
proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode =

View File

@@ -462,7 +462,7 @@ proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] =
c = union(a, b)
assert c.len == 5
assert c == [1, 2, 3, 4, 5].toPackedSet
result = default(PackedSet[A])
result.assign(s1)
incl(result, s2)
@@ -509,7 +509,7 @@ proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] =
c = symmetricDifference(a, b)
assert c.len == 4
assert c == [1, 2, 4, 5].toPackedSet
result = default(PackedSet[A])
result.assign(s1)
for item in s2.items:
if containsOrIncl(result, item):

View File

@@ -63,7 +63,7 @@ proc threadFunc(obj: ptr seq[int]) {.thread.} =
proc threadHandler() =
var thr: array[0..4, Thread[ptr seq[int]]]
var s = newSeq[int]()
for i in 0..high(thr):
createThread(thr[i], threadFunc, s.addr)
joinThreads(thr)
@@ -137,7 +137,6 @@ when defined(zephyr):
{.push stack_trace:off.}
when defined(windows):
proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} =
result = 0'i32
nimThreadProcWrapperBody(closure)
# implicitly return 0
elif defined(genode):
@@ -145,7 +144,6 @@ elif defined(genode):
nimThreadProcWrapperBody(closure)
else:
proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} =
result = nil
nimThreadProcWrapperBody(closure)
{.pop.}
@@ -166,7 +164,7 @@ when hostOS == "windows":
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
## Waits for every thread in `t` to finish.
var a: array[MAXIMUM_WAIT_OBJECTS, SysThread] = default(array[MAXIMUM_WAIT_OBJECTS, SysThread])
var a: array[MAXIMUM_WAIT_OBJECTS, SysThread]
var k = 0
while k < len(t):
var count = min(len(t) - k, MAXIMUM_WAIT_OBJECTS)
@@ -222,7 +220,7 @@ when hostOS == "windows":
when TArg isnot void: t.data = param
t.dataFn = tp
when hasSharedHeap: t.core.stackSize = ThreadStackSize
var dummyThreadId: int32 = 0'i32
var dummyThreadId: int32
t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
addr(t), 0'i32, dummyThreadId)
if t.sys <= 0:

View File

@@ -58,7 +58,7 @@ proc finalize(n: NimNode, lhs: NimNode, level: int): NimNode =
if level == 0:
result = quote: `lhs` = `n`
else:
result = quote: (var `lhs` = `n`)
result = quote: (let `lhs` = `n`)
proc process(n: NimNode, lhs: NimNode, label: NimNode, level: int): NimNode =
result = nil
@@ -78,7 +78,7 @@ proc process(n: NimNode, lhs: NimNode, label: NimNode, level: int): NimNode =
let check = it[1]
let okSet = check[1]
let kind1 = check[2]
let tmp = genSym(nskVar, "tmpCase")
let tmp = genSym(nskLet, "tmpCase")
let body = process(objRef, tmp, label, level + 1)
let tmp3 = nnkDerefExpr.newTree(tmp)
it[0][0] = tmp3
@@ -92,7 +92,7 @@ proc process(n: NimNode, lhs: NimNode, label: NimNode, level: int): NimNode =
`assgn`
break
elif it.kind in {nnkHiddenDeref, nnkDerefExpr}:
let tmp = genSym(nskVar, "tmp")
let tmp = genSym(nskLet, "tmp")
let body = process(it[0], tmp, label, level + 1)
it[0] = tmp
let assgn = finalize(n, lhs, level)
@@ -117,7 +117,7 @@ macro `?.`*(a: typed): auto =
let label = genSym(nskLabel, "label")
let body = process(a, lhs, label, 0)
result = quote do:
var `lhs`: type(`a`) = default(type(`a`))
var `lhs`: type(`a`)
block `label`:
`body`
`lhs`
@@ -149,9 +149,9 @@ macro `??.`*(a: typed): Option =
let label = genSym(nskLabel, "label")
let body = process(a, lhs2, label, 0)
result = quote do:
var `lhs`: Option[type(`a`)] = default(Option[type(`a`)])
var `lhs`: Option[type(`a`)]
block `label`:
var `lhs2`: type(`a`) = default(type(`a`))
var `lhs2`: type(`a`)
`body`
`lhs` = option(`lhs2`)
`lhs`

View File

@@ -2357,7 +2357,7 @@ when notJSnotNims:
else:
let c3 = cast[proc(y: int; env: pointer): int {.nimcall.}](p)
echo c3(3, e)
result = nil
{.emit: """
`result` = (void*)`x`.ClP_0;
""".}
@@ -2365,14 +2365,12 @@ when notJSnotNims:
proc rawEnv*[T: proc {.closure.} | iterator {.closure.}](x: T): pointer {.noSideEffect, inline.} =
## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`.
## This is not available for the JS target.
result = nil
{.emit: """
`result` = `x`.ClE_0;
""".}
proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} =
## It can be used to determine if a first class iterator has finished.
result = false
when defined(js):
# TODO: mangle `:state`
{.emit: """

View File

@@ -87,9 +87,6 @@ else:
template count(x: Cell): untyped =
x.rc shr rcShift
when not defined(nimHasQuirky):
{.pragma: quirky.}
proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
let hdrSize = align(sizeof(RefHeader), alignment)
let s = size + hdrSize
@@ -193,7 +190,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
#proc dispose*(x: pointer) = nimRawDispose(x)
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, quirky, raises: [].} =
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
let rti = cast[ptr PNimTypeV2](p)
if rti.destructor != nil:
cast[DestructorProc](rti.destructor)(p)

View File

@@ -6,11 +6,11 @@ const
## ```
# see also std/private/since
NimMinor* {.intdefine.}: int = 3
NimMinor* {.intdefine.}: int = 2
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 1
NimPatch* {.intdefine.}: int = 2
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -112,10 +112,9 @@ proc nimToCStringConv(s: NimStringV2): cstring {.compilerproc, nonReloadable, in
proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inline.} =
if src.len > 0:
# don't copy the \0 terminator:
copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len)
# also copy the \0 terminator:
copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len+1)
inc dest.len, src.len
dest.p.data[dest.len] = '\0'
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
dest.p.data[dest.len] = c

View File

@@ -68,7 +68,7 @@ else:
when defined(nimV2):
thrd.dataFn(thrd.data)
else:
var x: TArg = default(TArg)
var x: TArg
deepCopy(x, thrd.data)
thrd.dataFn(x)
except:

View File

@@ -16,8 +16,6 @@ import ../compiler / [idents, llstream, ast, msgs, syntaxes, options, pathutils,
import parseopt, strutils, os, sequtils
import std/tempfiles
const
Version = "0.2"
Usage = "nimpretty - Nim Pretty Printer Version " & Version & """
@@ -28,7 +26,6 @@ Usage:
Options:
--out:file set the output file (default: overwrite the input file)
--outDir:dir set the output dir (default: overwrite the input files)
--stdin read input from stdin and write output to stdout
--indent:N[=0] set the number of spaces that is used for indentation
--indent:0 means autodetection (default behaviour)
--maxLineLen:N set the desired maximum line length (default: 80)
@@ -87,7 +84,7 @@ proc finalCheck(content: string; origAst: PNode): bool {.nimcall.} =
closeParser(parser)
result = conf.errorCounter == oldErrors # and goodEnough(newAst, origAst)
proc prettyPrint*(infile, outfile: string; opt: PrettyOptions) =
proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) =
var conf = newConfigRef()
let fileIdx = fileInfoIdx(conf, AbsoluteFile infile)
let f = splitFile(outfile.expandTilde)
@@ -102,28 +99,12 @@ proc prettyPrint*(infile, outfile: string; opt: PrettyOptions) =
when defined(nimpretty):
closeEmitter(parser.em, fullAst, finalCheck)
proc handleStdinInput(opt: PrettyOptions) =
var content = readAll(stdin)
var (cfile, path) = createTempFile("nimpretty_", ".nim")
writeFile(path, content)
prettyPrint(path, path, opt)
echo(readAll(cfile))
close(cfile)
removeFile(path)
proc main =
var outfile, outdir: string
var infiles = newSeq[string]()
var outfiles = newSeq[string]()
var isStdin = false
var backup = false
# when `on`, create a backup file of input in case
# `prettyPrint` could overwrite it (note that the backup may happen even
@@ -131,6 +112,7 @@ proc main =
# --backup was un-documented (rely on git instead).
var opt = PrettyOptions(indWidth: 0, maxLineLen: 80)
for kind, key, val in getopt():
case kind
of cmdArgument:
@@ -150,15 +132,8 @@ proc main =
of "outDir", "outdir": outdir = val
of "indent": opt.indWidth = parseInt(val)
of "maxlinelen": opt.maxLineLen = parseInt(val)
# "" is equal to '-' as input
of "stdin", "": isStdin = true
else: writeHelp()
of cmdEnd: assert(false) # cannot happen
if isStdin:
handleStdinInput(opt)
return
if infiles.len == 0:
quit "[Error] no input file."

View File

@@ -79,7 +79,7 @@ pkg "hts", "nim c -o:htss src/hts.nim"
pkg "httpauth"
pkg "httputils"
pkg "illwill", "nimble examples"
# pkg "inim"
pkg "inim"
pkg "itertools", "nim doc src/itertools.nim"
pkg "iterutils"
pkg "json_rpc"

View File

@@ -38,7 +38,6 @@ proc splitTestFile*(file: string): tuple[cat: string, path: string] =
## At least one directory is required in the path, to use as a category name
runnableExamples:
doAssert splitTestFile("tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath)
result = ("", "")
for p in file.parentDirs(inclusive = false):
let parent = p.parentDir
if parent.lastPathPart == testsFname:

View File

@@ -6,18 +6,13 @@ proc mismatch*[T](lhs: T, rhs: T): string =
## while avoiding pulling too many dependencies. On failure, diagnostic
## information is provided that in particular makes it easy to spot
## whitespace mismatches and where the mismatch is.
result = ""
proc replaceInvisible(s: string): string =
result = ""
for a in s:
case a
of '\n': result.add "\\n\n"
else: result.add a
proc quoted(s: string): string =
result = ""
result.addQuoted s
proc quoted(s: string): string = result.addQuoted s
result.add '\n'
result.add "lhs:{" & replaceInvisible(

View File

@@ -1,20 +0,0 @@
discard """
matrix: "--mm:orc"
output: '''
found entry
'''
"""
import std/tables
type NoCopies = object
proc `=copy`(a: var NoCopies, b: NoCopies) {.error.}
# bug #24720
proc foo() =
var t: Table[int, NoCopies]
t[3] = NoCopies() # only moves
for k, v in t.pairs(): # lent values, no need to copy!
echo "found entry"
foo()

View File

@@ -1,7 +1,3 @@
discard """
ccodecheck: "'Result[(i_1 - 0)] = eqdup'"
"""
# issue #24626
proc arrayWith2[T](y: T, size: static int): array[size, T] {.noinit, nodestroy, raises: [].} =

View File

@@ -1,16 +0,0 @@
discard """
cmd: "nim c --mm:orc -d:useMalloc $file"
valgrind: "true"
"""
import std/streams
proc foo() =
var name = newStringStream("2r2")
raise newException(ValueError, "sh")
try:
foo()
except:
discard

View File

@@ -1,7 +1,7 @@
discard """
matrix: "--mm:refc"
output: "Hello"
ccodecheck: "\\i@'a_1 = ((NimStringDesc*) NIM_NIL)'"
ccodecheck: "\\i@'a = ((NimStringDesc*) NIM_NIL)'"
"""
proc main() =

View File

@@ -1,7 +1,7 @@
discard """
output: "1"
cmd: r"nim c --hints:on $options --mm:refc -d:release $file"
ccodecheck: "'NI volatile state_1;'"
ccodecheck: "'NI volatile state;'"
targets: "c"
"""

View File

@@ -1,32 +0,0 @@
# issue #20653
type
EmptySeq* {.bycopy.} = object
ChoiceWithEmptySeq_d* {.bycopy.} = object
a*: bool
INNER_C_UNION* {.bycopy, union.} = object
a*: char
b*: EmptySeq
c*: byte
d*: ChoiceWithEmptySeq_d
ChoiceWithEmptySeq_selection* = enum
ChoiceWithEmptySeq_NONE,
ChoiceWithEmptySeq_a_PRESENT,
ChoiceWithEmptySeq_b_PRESENT,
ChoiceWithEmptySeq_c_PRESENT,
ChoiceWithEmptySeq_d_PRESENT
ChoiceWithEmptySeq* {.bycopy.} = object
kind*: ChoiceWithEmptySeq_selection
u*: INNER_C_UNION
Og_Context* {.bycopy.} = object
state*: int
init_done*: bool
ch*: ChoiceWithEmptySeq
em*: EmptySeq
var context* : Og_Context = Og_Context(init_done: false)

View File

@@ -45,14 +45,3 @@ block: # bug #22354
main()
proc main = # bug #24677
let NULL = 1
doAssert NULL == 1
var COMMA = 1
doAssert COMMA == 1
for NDEBUG in 0..2:
doAssert NDEBUG == NDEBUG
main()

View File

@@ -1,4 +1,6 @@
discard """
# doesn't work on macos 13 seemingly due to libc++ linking issue https://stackoverflow.com/a/77375947
disabled: osx
targets: cpp
"""
@@ -16,21 +18,21 @@ proc initStdException(): CStdException {.importcpp: "std::exception()", construc
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b = ""
var b: cstring
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = $e.what()
doAssert b == "foo2"
b = e.what()
doAssert $b == "foo2"
try: raise initStdException()
except CStdException: discard
try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = $e.what()
b = e.what()
except CStdException:
doAssert false
doAssert b == "foo3"
doAssert $b == "foo3"
fn()

View File

@@ -1,7 +1,7 @@
discard """
nimoutFull: true
action: "reject"
cmd: "nim r --hint:Conf:off --warnings:off $file"
cmd: "nim r --hint:Conf:off $file"
nimout: '''
tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects
> tdiagnostic_messages.nim(37, 30) Hint: 'a' calls `.sideEffect` 'callWithSideEffects'

View File

@@ -164,9 +164,7 @@ runnableExamples:
# bug #13491
block:
proc fun(): int =
result = 0
doAssert false
proc fun(): int = doAssert false
doAssertRaises(AssertionDefect, (discard fun()))
block:

View File

@@ -673,11 +673,11 @@ template main {.dirty.} =
result = v
proc failed(): Result[int, string] =
result = default(Result[int, string])
discard
proc calling(): Result[int, string] =
let _ = ? failed()
raiseAssert "false"
doAssert false
let r = calling()
doAssert assigned

View File

@@ -1,16 +0,0 @@
discard """
nimout: '''
proc foo(a {.attr.}: int) =
discard
'''
"""
# fixes #24702
import macros
template attr*() {.pragma.}
proc foo(a {.attr.}: int) = discard
macro showImpl(a: typed) =
echo repr getImpl(a)
showImpl(foo)

View File

@@ -22,7 +22,7 @@ heyho
Val1
Val1
'''
matrix: "--hints:off --warnings:off --mm:orc; --hints:off --warnings:off --mm:refc"
matrix: "--hints:off --mm:orc; --hints:off --mm:refc"
"""
import macros

View File

@@ -3,5 +3,3 @@ switch("styleCheck", "error")
switch("define", "nimPreviewSlimSystem")
switch("define", "nimPreviewCstringConversion")
switch("define", "nimPreviewProcConversion")
switch("warningAserror", "ProveInit")
switch("warningAserror", "Uninit")

View File

@@ -124,7 +124,7 @@ proc main() =
var x = @[1, 7, 8, 11, 21, 33, 45, 99]
var y = @[6, 7, 9, 12, 57, 66]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged == sorted(x & y)
@@ -133,7 +133,7 @@ proc main() =
var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3]
var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y, (x, y) => -system.cmp(x, y))
doAssert merged.isSorted((x, y) => -system.cmp(x, y))
doAssert merged == sorted(x & y, SortOrder.Descending)
@@ -142,7 +142,7 @@ proc main() =
var x: seq[int] = @[]
var y = @[1]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged.isSorted(SortOrder.Descending)
@@ -152,7 +152,7 @@ proc main() =
var x = [1, 3, 5, 5, 7]
var y: seq[int] = @[]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged == @x
@@ -167,26 +167,26 @@ proc main() =
block:
var x = default(array[0, int])
var x: array[0, int]
var y = [1, 4, 6, 7, 9]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged == @y
block:
var x: array[0, int] = []
var y: array[0, int] = []
var x: array[0, int]
var y: array[0, int]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged.len == 0
block:
var x: array[0, int] = []
var y: array[0, int] = []
var x: array[0, int]
var y: array[0, int]
var merged: seq[int] = @[99, 99, 99]
merged.setLen(0)
@@ -195,10 +195,10 @@ proc main() =
doAssert merged.len == 0
block:
var x: seq[int] = @[]
var y: seq[int] = @[]
var x: seq[int]
var y: seq[int]
var merged: seq[int] = @[]
var merged: seq[int]
merged.merge(x, y)
doAssert merged.isSorted
doAssert merged.len == 0
@@ -245,7 +245,7 @@ proc main() =
var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
var merged: seq[Record] = @[]
var merged: seq[Record]
merged.setLen(0)
merged.merge(x, y, ascendingCmp)
doAssert merged.isSorted(ascendingCmp)
@@ -267,7 +267,7 @@ proc main() =
doAssert merged == sorted(x & y, ascendingCmp)
var x: seq[(int, int)] = @[]
var x: seq[(int, int)]
x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0])
doAssert x == @[(1, 1), (1, 2)]

View File

@@ -173,7 +173,7 @@ proc main() =
block:
# basic mask operations (mutating)
var v: uint8 = 0'u8
var v: uint8
v.setMask(0b1100_0000)
v.setMask(0b0000_1100)
doAssert v == 0b1100_1100
@@ -254,7 +254,7 @@ proc main() =
doAssert a.clearMasked(3 .. 6) == 0b1000_0100
block:
# single bit operations
var v: uint8 = 0'u8
var v: uint8
v.setBit(0)
doAssert v == 0x0000_0001
v.setBit(1)
@@ -269,7 +269,7 @@ proc main() =
doAssert not v.testBit(6)
block:
# multi bit operations
var v: uint8 = 0'u8
var v: uint8
v.setBits(0, 1, 7)
doAssert v == 0b1000_0011
v.flipBits(2, 3)
@@ -278,11 +278,11 @@ proc main() =
doAssert v == 0b0000_1100
block:
# signed
var v: int8 = 0'i8
var v: int8
v.setBit(7)
doAssert v == -128
block:
var v: uint64 = 0'u64
var v: uint64
v.setBit(63)
doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
@@ -335,7 +335,7 @@ proc main() =
block: # not ready for vm because exception is compile error
try:
var v: uint32 = 0'u32
var v: uint32
var i = 32
v.setBit(i)
doAssert false

View File

@@ -190,7 +190,7 @@ proc main() =
doAssert $a == "[10, 20, 30]"
block:
var a, b: Deque[int] = initDeque[int]()
var a, b: Deque[int]
for i in 1 .. 256:
a.addLast(i)
for i in 1 .. 255:

View File

@@ -8,7 +8,6 @@ import std/strutils
import std/assertions
proc testHelper(f: seq[Item]): string =
result = ""
for it in f:
result.add(
$it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*"

View File

@@ -25,7 +25,7 @@ proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string,
var args = @[$f.int, msg, $expectLeak]
when defined(windows):
var refFd: Handle = default(Handle)
var refFd: Handle
# NOTE: This function shouldn't be used to duplicate sockets,
# as this function may mess with the socket internal refcounting.
# but due to the lack of type segmentation in the stdlib for
@@ -51,7 +51,7 @@ proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string,
proc isValidHandle(f: int): bool =
## Check if a handle is valid. Requires OS-native handles.
when defined(windows):
var flags: DWORD = default(DWORD)
var flags: DWORD
result = getHandleInformation(f.Handle, addr flags) != 0
else:
result = fcntl(f.cint, F_GETFD) != -1
@@ -88,7 +88,7 @@ proc main() =
defer: close client
client.connect("127.0.0.1", port)
var input: Socket = default(Socket)
var input: Socket
server.accept(input)
leakCheck(input.getFd, "accept()")

View File

@@ -12,12 +12,12 @@ when manualTest:
import strformat
proc frexp_test(lo, hi, step: float64) =
var exp: int = 0
var exp: int
var frac: float64
var eps = 1e-15.float64
var x: float64 = lo
var x:float64 = lo
while x <= hi:
frac = frexp(x.float, exp)
let rslt = pow(2.0, float(exp)) * frac

View File

@@ -54,7 +54,7 @@ proc main =
x.a = val
m1()
var x0: Foo = Foo()
var x0: Foo
x0.a1 = 10
doAssert x0 == Foo(a: 10)

View File

@@ -112,7 +112,7 @@ proc main() =
when sizeof(int) == 8 or defined(js):
block:
var s: seq[Hash] = @[]
var s: seq[Hash]
for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]:
let b = hash(a)
doAssert b notin s
@@ -197,7 +197,7 @@ proc main() =
doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))
block: # hash(ref|ptr|pointer)
var a: array[10, uint8] = default(array[10, uint8])
var a: array[10, uint8]
# disableVm:
whenVMorJs:
# pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417

View File

@@ -45,7 +45,7 @@ when not defined(windows) and not disableSSLTesting():
proc runServer(port: Port): bool {.thread.} =
## Run a trivial HTTPS server in a {.thread.}
## Exit after serving one request
result = false
var socket = newSocket()
socket.setSockOpt(OptReusePort, true)
socket.bindAddr(port)
@@ -55,7 +55,7 @@ when not defined(windows) and not disableSSLTesting():
## Handle one connection
socket.listen()
var client: Socket = default(Socket)
var client: Socket
var address = ""
log "server: ready"

View File

@@ -125,7 +125,7 @@ proc main(moveZeroesOut: static bool) =
doAssert data.extract.id == 12
block:
var x: seq[Isolated[JsonNode]] = @[]
var x: seq[Isolated[JsonNode]]
x.add isolate(newJString("1234"))
doAssert $x == """@[(value: "1234")]"""

View File

@@ -15,7 +15,7 @@ proc testRoundtrip[T](t: T, expected: string) =
let j = t.toJson
doAssert $j == expected, "\n" & $j & "\n" & expected
doAssert j.jsonTo(T).toJson == j
var t2: T = default(T)
var t2: T
t2.fromJson(j)
doAssert t2.toJson == j

View File

@@ -25,7 +25,6 @@ block: # bug #17454
block: # unpackVarargs
block:
proc bar1(a: varargs[int]): string =
result = ""
for ai in a: result.add " " & $ai
proc bar2(a: varargs[int]) =
let s1 = bar1(a)

View File

@@ -545,8 +545,3 @@ when not defined(js) and not defined(danger):
doAssertRaises(OverflowDefect):
discard sum(x)
block: # bug #24673
let x: Natural = 5
let y: Natural = 3
doAssert divmod(x, y) == (Natural 1, Natural 2)

View File

@@ -94,10 +94,10 @@ block: # "IpAddress/Sockaddr conversion"
doAssert($ipaddrstr == $ipaddr_1)
var sockaddr: Sockaddr_storage = default(Sockaddr_storage)
var socklen: SockLen = default(SockLen)
var ipaddr_2: IpAddress = default(IpAddress)
var port_2: Port = default(Port)
var sockaddr: Sockaddr_storage
var socklen: SockLen
var ipaddr_2: IpAddress
var port_2: Port
toSockAddr(ipaddr_1, Port(0), sockaddr, socklen)
fromSockAddr(sockaddr, socklen, ipaddr_2, port_2)
@@ -108,11 +108,11 @@ block: # "IpAddress/Sockaddr conversion"
doAssert($ipaddr_1 == $ipaddr_2)
if sockaddr.ss_family.cint == AF_INET.toInt:
var sockaddr4: Sockaddr_in = default(Sockaddr_in)
var sockaddr4: Sockaddr_in
copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
elif sockaddr.ss_family.cint == AF_INET6.toInt:
var sockaddr6: Sockaddr_in6 = default(Sockaddr_in6)
var sockaddr6: Sockaddr_in6
copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)

View File

@@ -40,7 +40,7 @@ proc testThread() {.thread.} =
proc test() =
let serverFd = initIPv6Server("::1", port)
var t: Thread[void] = default(Thread[void])
var t: Thread[void]
createThread(t, testThread)
var done = false

View File

@@ -47,7 +47,6 @@ proc main() =
block example:
proc find(haystack: string, needle: char): Option[int] =
result = none(int)
for i, c in haystack:
if c == needle:
return some i
@@ -106,7 +105,7 @@ proc main() =
block filter:
doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123))
doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone)
doAssert(intNone.filter(proc (v: int): bool = raiseAssert "false").isNone)
doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone)
block flatMap:
proc addOneIfNotZero(v: int): Option[int] =
@@ -137,7 +136,7 @@ proc main() =
doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))
block SomePointer:
var intref: ref int = nil
var intref: ref int
doAssert(option(intref).isNone)
intref.new
doAssert(option(intref).isSome)

View File

@@ -44,12 +44,12 @@ proc test() =
doAssert(parseSaturatedNatural("1_000_000", value) == 9)
doAssert value == 1_000_000
var i64Value: int64 = 0'i64
var i64Value: int64
discard parseBiggestInt("9223372036854775807", i64Value)
doAssert i64Value == 9223372036854775807
block:
var f: float = 0.0
var f: float
let res = collect:
for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
(parseFloat(x, f, 0), $f)

View File

@@ -192,7 +192,7 @@ block:
expr.rule = sequence(capture(ident), *sequence(
nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
var c: Captures = default(Captures)
var c: Captures
var s = "a+b + c +d+e+f"
doAssert rawMatch(s, expr.rule, 0, c) == len(s)
var a = ""
@@ -208,7 +208,7 @@ block:
doAssert match("_______ana", peg"A <- 'ana' / . A")
doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
var matches: array[0..MaxSubpatterns-1, string] = default(array[0..MaxSubpatterns-1, string])
var matches: array[0..MaxSubpatterns-1, string]
if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
doAssert matches[0] == "abc"
else:
@@ -325,7 +325,7 @@ block:
call()
call()
"""
var c: Captures = default(Captures)
var c: Captures
doAssert program.len == program.rawMatch(grammar, 0, c)
doAssert c.ml == 1

View File

@@ -11,7 +11,7 @@ when not defined(js):
randomize(233)
proc main() =
var occur: array[1000, int] = default(array[1000, int])
var occur: array[1000, int]
for i in 0..100_000:
let x = rand(high(occur))

Some files were not shown because too many files have changed in this diff Show More