Compare commits

..

272 Commits

Author SHA1 Message Date
tersec
772b62cdeb don't access void* out of alignment in refc GC to avoid UB (#21560)
(cherry picked from commit e8a70ff179)
2023-04-05 08:10:11 +02:00
ringabout
82e9ec3b5c fixes broken CI; bump macOS version to macos-11 (#20098)
* bump macOS image on Azure CI to macos-11
* fix CI error

(cherry picked from commit 8ef509b85b)
2022-07-28 07:49:17 +02:00
narimiran
7e3e04c469 use --stylecheck:hint for chronicles package 2022-07-20 12:01:17 +02:00
Tanguy
f2bbff989f Fix nested finally handling in closureiters [backport] (#19933)
* Fix nested finally handling in closureiters

* Fix CI

* review comment

* third time the charm

* Update compiler/closureiters.nim

Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>

Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>
(cherry picked from commit fb5fbf1e08)
2022-07-18 17:16:06 +02:00
narimiran
de715892ac fix one more Defect 2022-06-22 10:19:00 +02:00
narimiran
24fb72c8ad no Defects in Nim 1.2 2022-06-21 12:24:12 +02:00
Tanguy
7e5686a828 Fix nimRawSetjmp for VCC [backport: 1.2] (#19899)
(cherry picked from commit 40464fa762)
2022-06-20 08:52:56 +02:00
Tanguy
843c479593 Windows: enable nimRawSetjmp by default [backport] (#19891)
* Windows: enable nimRawSetjmp by default

See #19197. The default setjmp can randomly segfault on windows

* Attempt to disable the flag for bootstraping

* Disable styleCheck for c_setjmp

(cherry picked from commit 251bdc1d5a)
2022-06-20 08:52:17 +02:00
flywind
7b35ce9812 fix NimNode comment repr() regression [backport: 1.2] (#19726)
(cherry picked from commit 15ae9323e8)
2022-06-20 08:49:34 +02:00
flywind
0798bd020b setjump => setjmp [backport: 1.2] (#19496)
(cherry picked from commit d0287748fe)
2022-06-20 08:48:57 +02:00
narimiran
c956aeae7f bump NimVersion to 1.2.19 2022-06-20 08:47:19 +02:00
narimiran
af3d1342c0 disable more packages that don't work anymore on Nim 1.2.x 2022-06-10 10:33:26 +02:00
narimiran
aa0dbaf3a1 disable packages that don't work anymore on Nim 1.2.x 2022-05-04 18:21:24 +02:00
narimiran
8a5c8d3e22 bump NimVersion to 1.2.18 2022-02-08 15:19:37 +01:00
narimiran
315a286d7c disable 'fragments' and 'telebot' packages 2022-01-17 11:27:23 +01:00
flywind
1d92e79dac mangle names in nimbase.h using cppDefine (#19395) [backport]
mangle names in nimbase.h
fix comments

(cherry picked from commit 4f6b59de96)
2022-01-17 11:18:36 +01:00
narimiran
01c8262426 bump NimVersion to 1.2.17 2022-01-17 07:41:23 +01:00
flywind
5e102df04d nrvo shouldn't touch bycopy object[backport:1.2] (#19385)
fix nim-lang#19342

(cherry picked from commit 9b9ae8a487)
2022-01-17 07:40:54 +01:00
Andreas Rumpf
57c9de181a Revert "Update uri.nim (#19148) [backport:1.0]" (#19280)
This reverts commit a3ef5df680.

(cherry picked from commit 81d32cf7e5)
2021-12-31 05:23:04 +01:00
narimiran
eeea72060c bump NimVersion to 1.2.16 2021-12-16 09:05:32 +01:00
Miran
0b1fee5d66 [backport:1.0] json: limit recursion depth (#19252)
* json: limit recursion depth

* do not run this check for JS backend

(cherry picked from commit c17baaefbc)
2021-12-14 18:23:42 +01:00
flywind
594831620b oids: switch from PRNG to random module (#16203)
* switch from PRNG to random module
* fix the regression
* comments + tests
* runnableExamples
* make oids better

(cherry picked from commit 89a21e4ec7)
2021-12-13 15:00:32 +01:00
Dominik Picheta
2eb0442a9a Update uri.nim (#19148) [backport:1.0]
(cherry picked from commit a3ef5df680)
2021-12-11 09:25:46 +01:00
Ștefan Talpalaru
002621b61d nimc.rst: fix table markup (#19239)
(cherry picked from commit 1a92edeb89)
2021-12-11 05:48:38 +01:00
Ștefan Talpalaru
8ea5475dd9 nimRawSetjmp: support Windows (#19197)
* nimRawSetjmp: support Windows

Using `_setjmp()` directly is required to avoid some rare (but very
annoying) exception-related stack corruption leading to segfaults on
Windows, with Mingw-w64 and SEH.
More details: https://github.com/status-im/nimbus-eth2/issues/3121

Also add "nimBuiltinSetjmp" - mostly for benchmarking.

* fix for Apple's Clang++

(cherry picked from commit 69aabdab80)
2021-12-11 05:48:35 +01:00
Andreas Rumpf
3e6d708175 implements https://github.com/nim-lang/RFCs/issues/260 (#15505)
* implements https://github.com/nim-lang/RFCs/issues/260

* added a test case

(cherry picked from commit 51e3e0c7c4)
2021-12-10 14:59:44 +01:00
narimiran
e3fb2c21d7 rename the file to prevent clashes in megatest 2021-12-08 14:58:18 +01:00
narimiran
c4ab020f0f correctly enable chronos 2021-12-08 08:26:01 +01:00
Tanguy
6e4fdbc4a9 fix #19193 (#19195) [backport:1.2]
(cherry picked from commit cd592ed85b)
2021-12-07 21:51:46 +01:00
Andreas Rumpf
497d061cd1 re-enable chronos testing once again [backport:1.2] (#19222)
(cherry picked from commit 93c8427fca)
2021-12-07 21:49:26 +01:00
Etan Kissling
4cb522fb8a allow HSlice bounded by constants of distinct types (#19219) [backport:1.2]
When creating heterogenous slices of distinct types, the compiler does
not initialize the internal type's `size` before accessing it.
This then leads to this crash message:
```
compiler/int128.nim(594, 11) `false` masking only implemented for 1, 2, 4 and 8 bytes [AssertionError]
```
This patch initializes the `size` properly, fixing the problem.

(cherry picked from commit 0213c7313b)
2021-12-07 21:48:08 +01:00
narimiran
84c1b1af0e we must use Ubuntu 18.04 2021-12-07 19:27:45 +01:00
narimiran
a683ca3fac bigints are not supposed to work on 1.2.x 2021-12-07 19:15:47 +01:00
narimiran
f7ea7b3c4f disable nimpy 2021-12-07 18:09:57 +01:00
Andreas Rumpf
a34845b66c fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-12-07 16:34:58 +01:00
Andreas Rumpf
79f95a2efc misc bugfixes [backport:1.2] (#19203)
(cherry picked from commit 23c117a950)
2021-12-06 12:53:37 +01:00
Andreas Rumpf
8a3f542532 fixes #14470 [backport:1.2] (#19115)
(cherry picked from commit 15157d06c3)
2021-12-06 12:51:56 +01:00
Andreas Rumpf
2009df72cb fixes a 'mixin' statement handling regression [backport:1.2] (#18968)
(cherry picked from commit 8eef557157)
2021-12-06 12:51:32 +01:00
narimiran
f4216f12b3 bump NimVersion to 1.2.15 2021-12-06 12:50:03 +01:00
narimiran
d327eaacbf bump NimVersion to 1.2.14 2021-11-07 09:51:32 +01:00
Etan Kissling
735e3eea78 allow converting static vars to openArray (#19049)
When assigning constant output to a seq, and then passing that static
seq to other functions that take `openArray`, the compiler may end up
producing errors, as it does not know how to convert `static[seq[T]]`
to `openArray[T]`. By ignoring the `static` wrapper on the type for
the purpose of determining data memory location and length, this gets
resolved cleanly. Unfortunately, it is relatively tricky to come up
with a minimal example, as there are followup problems from the failing
conversion, e.g., this may lead to `internal error: inconsistent
environment type`, instead of the relevant `openArrayLoc` error message.

(cherry picked from commit 490c4226a5)
2021-10-27 11:04:39 +02:00
flywind
d8cc349ac6 [tools] use the right parameter [backport:1.0] (#18957)
(cherry picked from commit b2873f0f63)
2021-10-06 13:41:27 +02:00
narimiran
e05daba73e try to fix the flaky test, similarly to the devel version 2021-08-25 08:22:51 +02:00
narimiran
2a72eeafdf it is IndexError, not IndexDefect, in 1.2 2021-08-24 15:05:17 +02:00
narimiran
2d06867388 disable testing packages which depend on newer Nim versions 2021-08-24 11:32:45 +02:00
narimiran
9b47614ba1 we can't use collect like that in 1.2 2021-08-24 11:32:28 +02:00
flywind
8d5065453f fix #18702(fix parseutils.parseFloat) (#18703) [backport:1.0]
* fix #18702
* Apply suggestions from code review

(cherry picked from commit 901c5ded52)
2021-08-24 07:20:47 +02:00
Andreas Rumpf
1802f94868 fixes #18643 [backport:1.0] (#18678)
(cherry picked from commit 018465a234)
2021-08-24 07:18:08 +02:00
Timothee Cour
5a42d393a4 link stable and devel docs in nim docs (#18272) [backport:1.2]
(cherry picked from commit d3b27eb63e)
2021-08-24 07:14:17 +02:00
Ștefan Talpalaru
76560576d2 asyncdispatch+stackTraceOverride: fix premature collection (#18039) [backport:1.2]
Copying StackTraceEntry instances when nimStackTraceOverride is defined
breaks the link between a cstring field that's supposed to point at
another string field in the same object.

Sometimes, the original object is garbage collected, that memory region
reused for storing other strings, so when the StackTraceEntry copy tries
to use its cstring pointer to construct a traceback message, it accesses
unrelated strings.

This only happens for async tracebacks and this patch prevents that by
making sure we only use the string fields when nimStackTraceOverride is
defined.

Async tracebacks also beautified slightly by getting rid of an extra line
that was supposed to be commented out, along with the corresponding debugging output.

There's also a micro-optimisation to avoid concatenating two strings just
to get their combined length.

(cherry picked from commit a1c82c39af)
2021-05-19 19:52:50 +02:00
narimiran
2684b04ab1 disable 'nimquery' package 2021-05-17 22:27:10 +02:00
Timothee Cour
6dde797752 fix #13166 tioselectors flaky test on freebsd+OSX (#14634)
(cherry picked from commit d149823019)
2021-05-17 22:26:45 +02:00
Andreas Rumpf
74f34c81e8 feature: the compiler can warn when you use the implicit 'result' variable (#17988) [backport:1.2]
* implements #17855

(cherry picked from commit 378ee7f888)
2021-05-17 19:04:34 +02:00
Andreas Rumpf
34563f86c2 fixes #15848 [backport:1.2] (#17959)
(cherry picked from commit 51f3ef6cb8)
2021-05-17 16:13:10 +02:00
shirleyquirk
7a9e5ba68f Fix buffer-overrun bug in net (#17728) [backport:1.0]
(cherry picked from commit fdd4391534)
2021-05-17 16:10:33 +02:00
narimiran
d2af421089 use csources_v1 in build_all scripts 2021-04-30 10:56:42 +02:00
Andreas Rumpf
ba02bf50b9 CIs: attempt to use csources_v1 (#16282)
* CIs: attempt to use csources_v1
* also updated the BSDs
* also updated azure pipelines
* std modules should not itself use the 'std/' import dir...
* compiler has to be careful with std/ for v1 booting

(cherry picked from commit a9b62de895)
2021-04-28 08:50:39 +02:00
narimiran
424a00db2b bump NimVersion to 1.2.13 2021-04-28 08:40:02 +02:00
zah
fb03c4b937 Remove the use of usrToCell in gcMark [backport:1.2] (#17709)
* Remove the use of usrToCell in gcMark [backport:1.2]

Recently, we've discovered a GC crash resulting from inlining of
the memory allocation procs that allowed the compiler to avoid
maintaining any references to the "user pointer" on the stack.
Instead, a "cell pointer" appeared there and all field accesses
were performed with adjusted offsets. This interfered with the
ability of the GC to mark the correct cell in the conservative
stack scans which lead to premature collection of objects.

More details here:
af69b3ceae

This commit closes another theoretical loophole that may lead to
the same problem. If a short proc is accessing both the object and
its reference count in a short sequence of instructions, the compiler
may be enticed to reduce the number of registers being used by storing
only a single pointer to the object and using offsets when reading
and writing fields. A perfectly good strategy would be to store only
the cell pointer, so the reference count updates can be performed
without applying offsets. Accessing the fields of the object requires
offsets anyway, but these can be adjusted at compile-time without any
loss. Following this strategy will lead to the same problem of marking
a wrong cell during the conservative stack scan, leading to premature
collection.

The problem is avoided by not using `usrToCell` in `gcMark`. Since
the cell discovery logic can already handle interior pointers, the
user pointers don't need to be adjusted for the GC to function correctly.

(cherry picked from commit 3b47a689cf)
2021-04-14 12:10:39 +02:00
narimiran
ba8f657635 bump NimVersion to 1.2.12 2021-04-13 21:52:25 +02:00
narimiran
6238f2ee1e Revert "fixes #11225; generic sandwich problems; [backport:1.2] (#17255)"
This reverts commit d85b7dde7b.
2021-04-13 09:59:53 +02:00
narimiran
7aff6ded84 [ci skip] minor: fix indentation in manual.rst
(cherry picked from commit d3529d0d5a)
2021-03-31 13:42:48 +02:00
Miran
fe8b84496f [backport:1.2] Avoid inlining of newObj and newObjRC1 calls (#17582)
This is taken from:
af69b3ceae

Full original comment:

This is to avoid heavy inlining happening when two allocation calls
would occur shortly after each other.

This inlining would sometimes be accompanied with an optimisation
as the compiler is able to see that cellToUsr ending the first
allocation call is shortly followed by an usrToCell call. The
pointer arithmetic is redundant and the compiler can eliminate it,
leaving only the cell address in a register (and later the stack)
instead of the actual pointer to the user data, as one would expect.

This combined with a GC collect cycle will cause the stack scan to
only notice the cell address, which is of no good due to a usrToCell
in the gcMark call which shifts that address to an adjacent cell.
This means that the actual cell of importance will not get marked
and thus cause a premature collection of that cell. BOOM.

(cherry picked from commit 40093b4a93)
2021-03-30 11:47:39 +02:00
Danil Yarantsev
7f834c69fb Free the certificate after checking in checkCertName (#17558) [backport:1.2]
* Fix small leak in checkCertName
* Size is not needed either
* Free the certificate after checking

(cherry picked from commit b36182b0a4)
2021-03-29 15:34:11 +02:00
Timothee Cour
9a58bddc55 fix #17454 (#17461)
(cherry picked from commit d78ebe4a0e)
2021-03-29 15:34:03 +02:00
narimiran
9ebf537341 bump NimVersion to 1.2.11 2021-03-26 09:02:54 +01:00
narimiran
5ea5d82507 Revert "fixes #15210 [backport:1.2] (#15237)"
This reverts commit ae688aa7f5.
2021-03-22 11:52:22 +01:00
Andreas Rumpf
d85b7dde7b fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-03-20 08:44:04 +01:00
Igor Ribeiro de Assis
1d301e354f Fix FutureStream memory usage (#17395) [backport:1.2]
(cherry picked from commit 9bb0e55749)
2021-03-18 17:46:59 +01:00
xioren
a7570ff0c2 Relocate 4xx/5xx exception in downloadFile (#17332) [backport:1.2]
Move 4xx/5xx exception to before disk i/o. As it stands an empty file is created on http error 4xx/5xx.

(cherry picked from commit 3d198fdcc2)
2021-03-18 17:30:15 +01:00
alaviss
86c8977726 compiler/installer.ini: package cacert.pem on Windows [backport:1.2] (#17172)
Follow up of 5dc544e1f5

After updating windeps.zip, it appears that Windows' build was
unchanged. As it turns out, cacert.pem is not set for packaging by the
compiler package manifest.

This commit add cacert.pem to the Windows package.

(cherry picked from commit d35f366d6f)
2021-03-18 17:25:41 +01:00
Andreas Rumpf
2ee078cdf8 fixes yet another SSL problem on Windows [backport:1.2] (#17167)
(cherry picked from commit b48a32053f)
2021-03-18 17:24:37 +01:00
narimiran
ebc114c526 Revert "fix #17118 (#17119) [backport:1.2]"
This reverts commit 2e896e3360.
2021-02-22 13:51:01 +01:00
narimiran
6da0bf80c3 bump NimVersion to 1.2.10 2021-02-22 10:31:38 +01:00
flywind
2e896e3360 fix #17118 (#17119) [backport:1.2]
* fix js unsigned integer
* Use `std` prefix for standard library modules
* fix #17118

(cherry picked from commit 32bf10126c)
2021-02-22 10:31:14 +01:00
Miran
d922751d98 [backport:1.2] update nimble commit hash (#17109)
(cherry picked from commit da52e81327)
2021-02-19 20:38:09 +01:00
Andreas Rumpf
ca1f97951c fixes #17085 [backport:1.2] (#17101)
(cherry picked from commit 4395a26764)
2021-02-19 20:36:13 +01:00
Benoit Favre
a48abc262c Fix bug in removeDotSegments when path ends with dot (#17038) [backport:1.2]
(cherry picked from commit 8f54d3b792)
2021-02-17 18:39:34 +01:00
narimiran
c18726f4a1 correctly backport pragmas changes 2021-02-09 20:23:13 +01:00
Miran
965b37ab4a [backport:1.2] update the nimble commit hash to the latest one (#16971)
(cherry picked from commit 0d34345f29)
2021-02-09 19:09:37 +01:00
narimiran
7deedd3601 remove 'tsugar' 2021-02-09 17:33:38 +01:00
Andreas Rumpf
2db37e2e0e final SSL changes [backport:1.2] (#16983)
(cherry picked from commit 74d6a4d7f4)
2021-02-09 15:45:05 +01:00
hlaaftana
aa98aee18d Remove declPragmas from lambdas [backport:1.0] (#16966)
* Remove declPragmas from lambdas [backport:1.0]

* add test for exportc

* fix test

* fix align, nodecl -> noinit

(cherry picked from commit 49b64e8dc7)
2021-02-09 15:44:29 +01:00
hlaaftana
3fb7979211 fix #16967 [backport:1.2] (#16976)
* fix #16967 [backport:1.2]

* move test to tsugar

(cherry picked from commit 49ee2f7f3b)
2021-02-09 15:41:34 +01:00
narimiran
5ffa88e7e0 enable 'protobuf' 2021-02-09 15:40:26 +01:00
narimiran
5788d288ad disable 'protobuf' package 2021-02-08 18:45:45 +01:00
Andreas Rumpf
793bd0a977 basic cleanups regarding SSL handling (#16940) [backport:1.0]
* basic cleanups regarding SSL handling
* enabled certificate checking on Windows
* updated the SSL test
* quoting helps

(cherry picked from commit abac35e743)
2021-02-08 17:26:07 +01:00
Andreas Rumpf
90cf7177ca fixes #16897 [backport:1.2] (#16900)
(cherry picked from commit 91ace2188a)
2021-02-02 14:35:54 +01:00
narimiran
98894e5e07 disable unsupported packages 2021-02-02 08:46:29 +01:00
Timothee Cour
040adf415b [backport 1.0] add backend support for js bigint (#16606)
* add backend support for js bigint

* cleanup

* add tests

* add -d:nimHasJsBigIntBackend

* cleanup

* more tests

(cherry picked from commit 025ca660f7)
2021-02-01 15:24:46 +01:00
Timothee Cour
bdb3cc3a8a [backport => 1.0] fix #16428 vmops now works for generic procs (#16429)
* fix #16428 vmops now works for generic procs

* remove duplication

(cherry picked from commit bc84d9c8cb)
2021-02-01 15:23:58 +01:00
Code Hz
435eca6232 removing out T from docs since it no longer working (#16378) [backport]
* remove `out T` from docs

see https://github.com/nim-lang/Nim/issues/16131

* remove `out T` in title
* remove entire paragraph

(cherry picked from commit 90dbb6f3fb)
2021-02-01 15:23:23 +01:00
Araq
6d75a9c996 better documentation
(cherry picked from commit cb19dc53ca)
2020-12-27 15:06:09 +01:00
Tomohiro
6e0c052509 Fix osproc so that it doesn't close pipe/process/thread handles twice (#16385) [backport]
* Add error check to closeHandle and fix closing handle twice in osproc

* Fix compile error on Linux

(cherry picked from commit dcdbae798c)
2020-12-19 14:28:53 +01:00
Andreas Rumpf
c5bf0d6fa9 fixes #16359 [backport] (#16377)
(cherry picked from commit b87bcb6d92)
2020-12-19 14:23:11 +01:00
Andreas Rumpf
2b9c458692 OSX: support for M1 [backport:1.0] (#16279)
(cherry picked from commit 94bb816de3)
2020-12-19 14:21:50 +01:00
Andreas Rumpf
28049053e8 fixes #16214 [backport] (#16252)
(cherry picked from commit edce5897a5)
2020-12-19 14:16:16 +01:00
Timothee Cour
a82cfb2d54 simplify toHex (#15821)
(cherry picked from commit 235e4930ab)
2020-12-07 15:47:36 +01:00
Miran
e3810646eb fix toHex - make it work with int literals (#15770)
(cherry picked from commit c0fdc8b215)
2020-12-07 15:47:26 +01:00
Andreas Rumpf
0888ac4097 fixes #16069; [backport:1.2] [backport:1.4] (#16115)
* fixes #16069; refs https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] [backport:1.4]

* make tests green again

(cherry picked from commit d306a04466)
2020-11-26 08:09:49 +01:00
narimiran
c2982d5a9d re-enable telebot 2020-11-25 16:03:50 +01:00
Euan
212dcafcaa Fix FreeBSD build failures (#15613)
The FreeBSD is/was failing, due to a conflict with installing Git.

Git is guaranteed to be in the base image, so this removes that package from the package list. It also reverts back to the built-in `packages` tag since it's officially supported.

Should the build fail in the future, the best place to go is the #sr.ht channel on freenode.

(cherry picked from commit ba2a477e64)
2020-11-25 16:03:11 +01:00
narimiran
f04c8f0ba4 disable failing packages 2020-11-25 15:30:53 +01:00
Araq
67bdbb676e fixes 'nim doc'
(cherry picked from commit 19d52033f8)
2020-11-25 15:30:23 +01:00
flywind
93552e2e31 fix rope index (#16100)
* fix rope index

* add testcase

(cherry picked from commit ab2c082cb3)
2020-11-25 13:49:47 +01:00
ee7
1ee94744e3 CI(actions): Replace deprecated add-path commands (#15892)
This commit resolves the following warning in the CI logs:

> Error: The `add-path` command is deprecated and will be disabled soon.
> Please upgrade to using Environment Files. For more information see:
> https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/

The deprecation is due to an injection vulnerability (CVE-2020-15228).

See:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=2070
- https://github.com/nim-lang/Nim/runs/1373146963#step:8:1

(cherry picked from commit 3948b40bcd)
2020-11-25 13:39:55 +01:00
flywind
db70fec7ca fix #16103 (#16109) [backport:1.0]
* fix #16103

* docs

(cherry picked from commit 823a71380d)
2020-11-25 13:02:20 +01:00
flywind
252bebd16e fix ropes format errors (#16106) [backport:1.0]
* fix rope index

* add testcase

* fix ropes format

(cherry picked from commit 0c6c4be0e7)
2020-11-25 13:02:02 +01:00
flywind
a27459fc08 fix #9695 asyncmacro: tfuturevar fails when activated [backport: 1.0] (#16090)
* fix asyncmacro

* Apply suggestions from code review

* Update lib/pure/asyncmacro.nim

(cherry picked from commit 6f1a72069a)
2020-11-25 12:59:01 +01:00
Andreas Rumpf
8c3f500338 fixes #15942 [backport:1.2] [backport:1.4] (#16051)
(cherry picked from commit 1efd11e266)
2020-11-25 12:58:49 +01:00
Andreas Rumpf
9af27994c9 makes parsesql .gcsafe [backport:1.0] (#16039)
(cherry picked from commit 743f2f5faa)
2020-11-25 12:58:35 +01:00
Igor Ribeiro de Assis
ee6b9d37c0 Do not read the whole file to compute SHA1 hash (fixes 15997) (#16006)
* Do not read the whole file to compute SHA1 hash (fixes 15997)

* Update lib/std/sha1.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* Update lib/std/sha1.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* Directly break from loop

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

 [backport:1.2] [backport:1.4]

(cherry picked from commit baaa19b927)
2020-11-25 12:58:23 +01:00
Andreas Rumpf
71c0b6e76c asynchttpserver cleanups [backport:1.0] (#15966)
* asynchttpserver cleanups [backport:1.0]

(cherry picked from commit 122f22d163)
2020-11-25 12:57:21 +01:00
Araq
b3a12b4e3f attempt to make asynchttpserver better; fixes #15925; [backport:1.0]
(cherry picked from commit 8778d4a6f3)
2020-11-25 12:54:07 +01:00
Bung
a832fa65c4 Fix #8404 JS backend doesn't handle float->int type conversion (#15950) [backport]
* Fix #8404 JS backend doesn't handle float->int type conversion
* handle conv to uint as cast, discard other cases
* limit to int32, times use int64
* toInt including tyInt64 break times timezones lib, ignore for now
* also affect to vm
* move to tests/misc/t8404.nim

(cherry picked from commit 797cb2e67b)
2020-11-25 12:52:23 +01:00
Christopher Dunn
6c5eaa955d Fix a problem for long symlinks in conda (#15908) [backport]
* d8c80ea69d (diff-e1d8e552330911f9f779f85b6f2c00a15e790dcc3fbb3b28f5da1d660a30c5b8)

(cherry picked from commit c6ceefea6d)
2020-11-25 12:52:10 +01:00
narimiran
e9e93bd0ca bump NimVersion to 1.2.9 2020-11-25 12:47:35 +01:00
narimiran
dde13f38c9 revert adding a test, should have been part of 00cd7b8ca backport 2020-10-26 11:22:09 +01:00
Jason Beetham
fabbb7ea3e Fixed iteration limit hit from execproc (#15723) [backport:1.2] [backport:1.4]
When calling procs from Nim in Nimscript you could hit the VM iteration limit even though the code is functioning properly. This resolves that by making the iteration limit reset eachtime you call a proc.

(cherry picked from commit a87617956f)
2020-10-26 11:14:55 +01:00
Danil Yarantsev
76971596ad Add support to the latest LibreSSL version (#15715) [backport:1.2] [backport:1.4]
(cherry picked from commit b2740f5c63)
2020-10-26 11:14:49 +01:00
Timothee Cour
d777a8f86c fix #15704 #15597 wrong VM register was freed (#15705)
(cherry picked from commit d4c2e2c53f)
2020-10-26 10:29:54 +01:00
Clyybber
00cd7b8ca4 Revert "fixes #15280 [backport:1.2] (#15281)" (#15700)
This reverts commit 3f00a738db.

(cherry picked from commit d4022ebe53)
2020-10-24 17:18:44 +02:00
narimiran
714fd81199 remove tests that shouldn't have been backported in previous commit 2020-10-15 14:00:15 +02:00
Andreas Rumpf
59b5bdc2c6 renamed '=' to '=copy' [backport:1.2] (#15585)
(cherry picked from commit da4aa2e1fb)
2020-10-15 13:32:25 +02:00
Igor Ribeiro de Assis
4642a3485c Fix crash in parsexml (#15582) (#15583)
Co-authored-by: Igor Ribeiro de Assis <igor.ribeiro_de_assis@zeiss.com>
(cherry picked from commit 42c180c665)
2020-10-15 13:27:46 +02:00
genotrance
58d711ec57 Bump nimble (#15573)
(cherry picked from commit a4c28394be)
2020-10-15 13:27:29 +02:00
narimiran
8f3f264160 bump NimVersion to 1.2.8 2020-10-14 11:01:02 +02:00
Andreas Rumpf
2ce9352285 sigmatch: hotfix [backport] (#15565)
(cherry picked from commit c664fb2843)
2020-10-14 11:00:47 +02:00
alaviss
825f358c8b terminal: fix fgColor/bgColor commands [backport] (#15554)
Since #8296, fgSetColor is no longer a global. These commands were
probably left out from the change as an oversight, so some tests have
been added to make sure this won't happen again.

(cherry picked from commit d1af9587b8)
2020-10-13 21:21:52 +02:00
Christopher Dunn
17bed3c966 Fix doc for CountTable (#15561) [backport]
(cherry picked from commit f1d81dc6e6)
2020-10-13 08:43:46 +02:00
Christian Ulrich
eb51fa5ead close socket in getPrimaryIPAddr (#15538) [backport]
(cherry picked from commit c7ccbfac39)
2020-10-13 08:43:27 +02:00
alaviss
dc1c251a2c tslow_tables: wait for an additional 2 seconds (#14266)
This test runtime tends to hover around the 5s mark depending on how
loaded the system currently is. This causes the test to fail a lot
during CI, per analytics:
https://dev.azure.com/nim-lang/Nim/_test/analytics?definitionId=1&contextType=build

Give the test an extra 2 seconds to account for unrelated overhead.

(cherry picked from commit 83435fe696)
2020-10-09 15:09:48 +02:00
narimiran
d6c8a91b72 fix wrong word-wrap in tunknown_named_parameter 2020-10-09 14:55:20 +02:00
Araq
991902e286 fixes a renderer regression
(cherry picked from commit 0ac74ddd74)
2020-10-09 12:06:05 +02:00
narimiran
5534c56d05 manually backport #15506 2020-10-09 12:03:07 +02:00
cooldome
777c28cf45 fix #15516 (#15518)
(cherry picked from commit fe187719ab)
2020-10-09 10:04:24 +02:00
alaviss
3f0432bf8d koch: unify nimble building scripts [backport:1.4] (#15443)
This commit gets rid of buildNimble in favor of the simpler
bundleNimbleExe, which does pretty much the same thing.

(cherry picked from commit 3919f0aa54)
2020-10-07 20:11:18 +02:00
alaviss
bc42ec515e tools/deps: fix git dir check (#15470)
On Windows, a successful call will have a trailing newline appended, so
strip that away before doing any checks.

(cherry picked from commit e3eae3f7c7)
2020-10-07 19:44:35 +02:00
alaviss
60783ccc11 koch, compiler: bundle fusion as part of the source archive (#15409)
This allows distributions to build Nim from the downloaded source
archive without an Internet connection.

(cherry picked from commit d4892e9388)
2020-10-07 19:44:00 +02:00
Andreas Rumpf
9599d95caa fixes https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] (#15479)
(cherry picked from commit 2288188fe9)
2020-10-06 09:50:36 +02:00
Andreas Rumpf
e3c85f5885 remove nim.cfg file change lefover [backport:1.2] (#15469)
(cherry picked from commit ff70ff529d)
2020-10-06 08:49:06 +02:00
Andreas Rumpf
da03b5ca8b closureiters: fixes #15243 (#15454) [backport:1.2]
* fixes #15243 [backport:1.2]

(cherry picked from commit aa1d7fe1e9)
2020-10-06 08:48:44 +02:00
Miran
736e1dd0a0 various documentation fixes [backport] (#15422)
(cherry picked from commit eb2a4961c7)
2020-10-06 08:46:54 +02:00
Yuriy Glukhov
c6d51805be Dont assert on setstacksize result in iOS (#15427) [backport:1.2]
(cherry picked from commit 22d0a39932)
2020-10-06 08:46:41 +02:00
Andreas Rumpf
c53c6458b0 finish the stacktraces.nim implementation [backport:1.2] (#15393)
(cherry picked from commit e2d80b15a6)
2020-10-06 08:46:25 +02:00
Andreas Rumpf
eefb13d638 better nativestacktrace support; refs #15284; backport [1.2] (#15384)
* nimStackTraceOverride: enable stack traces in exceptions

This is a two-step stack trace collection scheme, because re-raised
exceptions will collect multiple stack traces but use them rarely, when
printing info about an uncaught exception, so it makes sense to only do
the cheap stack unwinding all the time and the relatively expensive
debugging information collection on-demand.

`asyncfutures` implements its own `$` proc for printing
`seq[StackTraceEntry]`, so we have to add the debugging info there, just
like we do for the private `$` proc in `system/excpt`.

* cleaned up PR #15284

Co-authored-by: Ștefan Talpalaru <stefantalpalaru@yahoo.com>
(cherry picked from commit 1fae66e4df)
2020-10-06 08:45:13 +02:00
Andreas Rumpf
7ef706fef9 fixes #15360 [backport:1.2] (#15378)
(cherry picked from commit c2434d939e)
2020-09-21 18:19:13 +02:00
Andreas Rumpf
4827bf5e88 base64: fixes the error message for an invalid base64 input character [backport:1.2]
(cherry picked from commit cbdda631db)
2020-09-21 18:19:04 +02:00
Andreas Rumpf
2624de0588 fixes #9754 [backport] (#15342)
(cherry picked from commit 8b66412a8b)
2020-09-21 18:18:44 +02:00
flywind
183f876bd1 remove annoying messages when creating orderedTables (#15309)
* nativesockets docs minor [backport: 1.2]

* remove annoying messages

(cherry picked from commit a41b243fea)
2020-09-21 18:15:54 +02:00
alaviss
6eb656a75b Small optimization for the CI pipeline. (#15088)
* azure-pipelines: cache csources to speed up build

Building csources takes about 2-4 mins, and since it hasn't changed for
a long time, employ some caching to cut the time spent.

* azure-pipelines: remove ppa avoidance configs

Testing shows that there aren't any difference between having this and
not having it, so removing this to simplify the code.

(cherry picked from commit c292c57e48)
2020-09-14 09:07:03 +02:00
narimiran
0e457ae92c disable package 'ws' 2020-09-12 08:47:17 +02:00
narimiran
5254e0693e fix failing tests 2020-09-11 15:54:17 +02:00
slangmgh
abe72ba1b3 fix #14203 (#14204)
(cherry picked from commit b56432bd8a)
2020-09-11 14:49:21 +02:00
narimiran
e980256794 fix RangeDefect to RangeError 2020-09-11 14:39:51 +02:00
Andreas Rumpf
7bba0deb1d fixes #15280 [backport:1.2] (#15281)
* fixes #15280 [backport:1.2]

* make tests green again

* adapt tests

(cherry picked from commit 3f00a738db)
2020-09-11 13:58:04 +02:00
flywind
0845e88110 nativesockets docs minor [backport: 1.2] (#15285)
(cherry picked from commit a81610230d)
2020-09-11 13:58:04 +02:00
flywind
040ac6cd2b more Protocol supports in windows (#15274) [backport:1.2]
(cherry picked from commit e08b802d79)
2020-09-11 13:58:04 +02:00
shirleyquirk
1c8ed1de0e Fix c_malloc inside syslocks.nim to take size_t (#15268) [backport]
* update c_malloc's to csize_t

(cherry picked from commit 57f98dae9a)
2020-09-11 13:58:04 +02:00
Miran
b5c90a3431 fix #15257, toHex couldn't handle large uint64 (#15261) [backport:1.2]
(cherry picked from commit 4fb17bc03b)
2020-09-11 13:58:04 +02:00
PMunch
53f3bd9376 Fix sets for architectures with default integers smaller than 32 bits (#15258) [backport]
(cherry picked from commit 244760197c)
2020-09-11 13:58:04 +02:00
Andreas Rumpf
ae688aa7f5 fixes #15210 [backport:1.2] (#15237)
* fixes #15210 [backport:1.2]

* use patched version of bigints library

(cherry picked from commit ff13f8cc3c)
2020-09-11 13:58:04 +02:00
Araq
4e428c5a18 fixes #15207 [backport:1.2]
(cherry picked from commit 40969296e9)
2020-09-11 13:58:04 +02:00
Miran
dc3f74f1c2 [backport] fix #15064, strscans.scanf edge case for '$+' (#15223)
(cherry picked from commit 15ff89cec1)
2020-09-11 13:58:04 +02:00
alaviss
98e73512d1 asyncnet: don't try to close the socket again [backport] (#15174)
The closed flag isn't a good design by any means, but let's have this
working first before I get rid of the flag and potentially create a
non-backportable commit.

(cherry picked from commit 957bf15a08)
2020-09-11 13:58:04 +02:00
Andreas Rumpf
a41ece8d86 fixes #15101 [backport] (#15171)
(cherry picked from commit 2a8bf470af)
2020-09-11 13:58:04 +02:00
Andreas Rumpf
67d729aa2e fixes a collect() bug reported on the forum (#15156) [backport:1.2]
(cherry picked from commit 64aec6eb85)
2020-09-11 13:58:04 +02:00
Andreas Rumpf
0ddf7153b8 fixes #15129 [backport:1.2] (#15144)
(cherry picked from commit d6161e7e9e)
2020-09-11 13:58:04 +02:00
Andreas Rumpf
0aec43e850 fixes #15071 [backport] (#15131)
(cherry picked from commit d23ae49535)
2020-09-11 13:58:04 +02:00
narimiran
f94a3fa671 bump Nim version to 1.2.7 2020-09-11 13:58:04 +02:00
c-blake
bf320ed172 Attempt to explain better why delImplIdx is the way it is. Maybe this can (#15108)
avoid future implementation mischief.  (Maybe not.  Sometimes, general
distrust of theory leads people to distrust simple reasoning over times
from CPUs trying as hard as possible to mask DRAM latency via pre-fetch.)

(cherry picked from commit 196e747df1)
2020-07-29 11:59:40 +02:00
Andreas Rumpf
e9d6d2b961 fixes #14616 [backport:1.2] (#15109)
(cherry picked from commit a3a87cdb29)
2020-07-29 11:59:20 +02:00
Bung
9d11fc026b fixes #14189 (#15080) [backport]
(cherry picked from commit 191c388792)
2020-07-29 10:43:48 +02:00
Jjp137
896c3c41d3 parsecsv: fix '\0' being displayed as '0' in docs (#15086) [backport]
(cherry picked from commit a62bc55955)
2020-07-29 10:43:36 +02:00
Andreas Rumpf
f2844ba2d3 fixes #15038 [backport:1.2]
(cherry picked from commit aae998feff)
2020-07-29 10:43:20 +02:00
Bung
a3f00b87e1 fix #14534 (#15060) [backport]
(cherry picked from commit 9746868832)
2020-07-29 10:39:39 +02:00
Araq
df490bd59f fixes #15056 [backport]
(cherry picked from commit 12a9fe017e)
2020-07-29 10:39:29 +02:00
Andreas Rumpf
b4ccdf870b fixes #15044 [backport:1.2]
(cherry picked from commit c90c53e8bb)
2020-07-29 10:39:11 +02:00
narimiran
c0e1ee965a bump NimVersion to 1.2.6 2020-07-29 09:54:54 +02:00
c-blake
c804e559ad Fulfill https://github.com/nim-lang/Nim/pull/14995#issuecomment-664914391 (#15104)
request.  This can be conceived as an alternate, more capable resolution of
  https://github.com/nim-lang/Nim/issues/12200
than
  https://github.com/nim-lang/Nim/pull/12208

The code re-org idea here is to upgrade tablimpl.nim:`delImpl`/`delImplIdx`
to abstract client code conventions for cell emptiness & cell hashing via
three new template arguments - `makeEmpty`, `cellEmpty`, `cellHash` which
all take a single integer argument and clear a cell, test if clear or
produce the hash of the key stored at that index in `.data[]`.

Then we update the 3 call sites (`Table`, `CountTable`, `SharedTable`) of
`delImpl`/`delImplIdx` by defining define those arguments just before the
first invocation as non-exported templates.

Because `CountTable` does not save hash() outputs as `.hcode`, it needs a
new tableimpl.nim:`delImplNoHCode` which simply in-lines the hash search
when no `.hcode` field is available for "prefix compare" acceleration.
It is conceivable this new template could be used by future variants, such
as one optimized for integer keys where `hash()` and `==` are fast and
`.hcode` is both wasted space & time (though a small change to interfaces
there for a sentinel key meaning "empty" is needed for maximum efficiency).

We also eliminate the old O(n) `proc remove(CountTable...)` in favor of
simply invoking the new `delImpl*` templates and take care to correctly
handle the case where `val` is either zero for non-existent keys in `inc`
or evolves to zero over time in `[]=` or `inc`.

The only user-visible changes from the +-42 delta here are speed, iteration
order post deletes, and relaxing the `Positive` constraint on `val` in
`proc inc` again, as indicated in the `changelog.md` entry.

(cherry picked from commit b2a1944587)
2020-07-29 09:54:39 +02:00
narimiran
378dc7c9fb bump NimVersion to 1.2.5 2020-07-23 20:24:00 +02:00
Andreas Rumpf
d0a2857675 enforce browsers.nim only handles URLs [backport] (#15045)
(cherry picked from commit 925dd92e07)
2020-07-23 11:52:15 +02:00
Miran
170f5b6229 asyncftpclient.nim - don't assume a sufficiend line length (#14973)
(cherry picked from commit f4f21c89e5)
2020-07-22 15:52:18 +02:00
Miran
e71395f571 fix several newline problems (#15028) [backend]
* prevent newlines where they shouldn't be
* 'contentLength' shouldn't be negative

(cherry picked from commit 5fafa2fd5c)
2020-07-22 15:47:58 +02:00
Dominik Picheta
ddcbc1a58f [Backport] Fixes callbacks being dropped on Linux/macOS/BSD. (#15012)
Fixes #15003.

This is a serious bug which occurs when data cannot be read/sent
immediately and there are a bunch of other read/write events
pending. What happens is that the new events are dropped which
results in the case of the reported bug resulted in some data not
being sent (!).

(cherry picked from commit 1e3a0ef1e1)
2020-07-21 15:46:41 +02:00
cooldome
28bc815d3e fix odbc regressions (#15009) [backport]
* fix odbc regressions

* make only necessary changes

(cherry picked from commit edbbbdf1a8)
2020-07-21 15:46:23 +02:00
Bung
e854d385f5 fix #9771 (#14357)
* fix #9771
* map SQLLEN SQLULEN
* fix proc params take TSqlLen

Co-authored-by: bung87 <crc32@qq.com>
(cherry picked from commit ce0552c100)
2020-07-21 15:46:11 +02:00
Miran
27acb43e69 fix #14082, don't crash on incorrectly formatted input (#14977) [backport]
(cherry picked from commit c62513049c)
2020-07-21 15:42:58 +02:00
Clyybber
1b093d7ec7 Fix #14911 (#14922) [backport]
* Fix #14911

* Add testcase

* Fix test

(cherry picked from commit 5bd2da3f64)
2020-07-21 15:40:24 +02:00
aguspiza
4d6cb1ff21 SSL_CTX_load_verify_locations parameters are reversed (#14815) [backport]
(cherry picked from commit d968163cd1)
2020-07-21 15:40:18 +02:00
narimiran
ba808ba7ee bump NimVersion to 1.2.4 2020-06-26 10:46:56 +02:00
narimiran
a5667218a9 update test command for 'norm' package 2020-06-25 13:03:12 +02:00
Miran
7c27cdc719 [backport] fix #14748, move gdb files to other section of installer.ini (#14772)
(cherry picked from commit 6bf2990f66)
2020-06-24 06:56:37 +02:00
Andreas Rumpf
f864c351f0 fixes #14240 [backport:1.2] (#14757)
(cherry picked from commit 451129de42)
2020-06-24 06:56:14 +02:00
Andreas Rumpf
ac00504928 fixes #14458 [backport:1.2] (#14756)
(cherry picked from commit 8df20276c9)
2020-06-24 06:56:05 +02:00
alaviss
bcb6d9a763 posix_other: add define to force time_t to 64 bit [backport] (#14753)
This is a temporary remedy for time_t transition to 64 bit on newer
Linux libc (musl >= 1.2.0, glibc >= 2.32).

In the future we might want to move away from libc, or figure out a way
to reliably detect the real size of C types at compile time, both of
which are difficult.

(cherry picked from commit c8554ebc0c)
2020-06-24 06:55:56 +02:00
ee7
90546716dc [backport] Docs: Fix broken code-block (#14749)
This commit indents the contents of a `code-block` in `httpclient.nim`
so that it displays correctly. The bug was introduced by 42a64245f8.

I did a quick search for other `code-block`s that are broken in the same
way, but the only other one I found (in `pegs.nim`) is not included in
the generated documentation.

(cherry picked from commit 1e484ed62b)
2020-06-24 06:55:34 +02:00
alaviss
8083a1fd2f encodings: use only one iconv definition [backport:1.2] (#14741)
Fix an issue reported on IRC: using encodings with --dynlibOverrideAll
result in duplicated iconv definitions, causing compile errors.

This commit remove the `var` wrapper of iconv and go all out on
pointers, as it should due to how the API accepts nil. Also corrected
the API to resemble iconv(3p).

(cherry picked from commit c7dee55b87)
2020-06-24 06:54:15 +02:00
Araq
49f2b7eac6 fixes #14718 [backport]
(cherry picked from commit 65c7884a3c)
2020-06-24 06:54:05 +02:00
narimiran
25c21711b7 bump NimVersion to 1.2.3 2020-06-24 06:53:25 +02:00
narimiran
be34b5abe2 bump Nim version to 1.2.2 2020-06-09 11:50:15 +02:00
Andreas Rumpf
5297bbe1cb optimized wrapWords; fixes #14579 (#14606) [backport:1.2]
(cherry picked from commit c308c2e60b)
2020-06-09 11:40:15 +02:00
Andreas Rumpf
10fb986fb6 more precise analysis about 'observable stores' [backport:1.2] (#14582)
(cherry picked from commit 32083c7ff8)
2020-06-08 13:26:33 +02:00
Andreas Rumpf
33bf7839ba fixes #14514 [backport:1.2] (#14533)
(cherry picked from commit 8710395a0f)
2020-06-08 13:26:28 +02:00
Zed
56b1e52e17 Fix asynchttpserver newline breaking content-length (#14565) [backport]
(cherry picked from commit ea761419ad)
2020-06-08 13:22:20 +02:00
Danil Yarantsev
5702a60793 Change severity of template instantiation message [backport] (#14526)
* Change severity of template instatiation msg

* Add a test

* Trailing newline argh

(cherry picked from commit 3698f197f1)
2020-06-01 17:41:04 +02:00
genotrance
4f689d4960 Fix #14057 - moveFile should overwrite on Windows (#14433)
(cherry picked from commit b012205b2e)
2020-06-01 17:40:11 +02:00
narimiran
4c0c82ae42 disable 'nimx' package, see PR #14293 2020-06-01 17:39:30 +02:00
Andreas Rumpf
2c64868764 warn about observerable stores but don't prevent them for 1.2.2 [backport:1.2]; refs https://github.com/nim-lang/RFCs/issues/230 (#14510)
(cherry picked from commit 52c3633223)
2020-06-01 13:39:16 +02:00
narimiran
957e74e99e correctly backport #14496 2020-06-01 13:38:04 +02:00
Andreas Rumpf
97c68d9446 fixes #14498 [backport:1.2] (#14503)
(cherry picked from commit 7ccc7d7e93)
2020-06-01 12:15:28 +02:00
Andreas Rumpf
aec0d583d1 fixes #14495 [backport:1.2] (#14496)
(cherry picked from commit 3105909f88)
2020-06-01 12:15:15 +02:00
Andreas Rumpf
051f4ffad9 manual.rst: updates [backport] (#14445)
(cherry picked from commit 79e85cb0b5)
2020-06-01 12:13:18 +02:00
Mamy Ratsimbazafy
ed966b77c3 The whole options module should be inline (#14417) [backport:1.2]
* The whole options module should be inline

* Use inline per proc and tag `lent` where appropriate

* Remove lent annotation (failing at compiletime)

(cherry picked from commit f71f8b0239)
2020-06-01 12:11:15 +02:00
Andreas Rumpf
7800fa394f specialize genericReset (#14398)
* progress
* make tests green
* maybe we also want to reset pointers, dunno
* progress
* cleanup; fixes #13879 [backport:1.2]

(cherry picked from commit b35d370d88)
2020-05-20 15:30:20 +02:00
Danil Yarantsev
bcfbaea833 Fix some typos in the manual [backport] (#14399)
(cherry picked from commit 1450924b1e)
2020-05-20 15:29:12 +02:00
Andreas Rumpf
acc3879c54 fixes #14126 [backport:1.2] (#14390)
* fixes #14126 [backport:1.2]

* used more logic to optimize it further; updated Nimble version

(cherry picked from commit 16003bffe1)
2020-05-20 09:04:49 +02:00
Ștefan Talpalaru
c0b749da38 fix #14364 (#14372) [backport:1.2]
Turn on the TLS emulation when using Boehm, since it doesn't scan the
real TLS.

(cherry picked from commit 27741d6a5c)
2020-05-19 12:15:59 +02:00
Clyybber
87992a3a18 Fix #14269 (#14286)
(cherry picked from commit 8e93105606)
2020-05-19 12:12:45 +02:00
Clyybber
c3ecd38da1 New "ping-pong" DFA (#14322)
* New ping-pong analysis

* Add testcase for #13456

* Remove debugging leftover

* Unquote "unstructured controlflow"

* Fix typo

* Fix exponential complexity in edge cases

* Add sanity testcase

* Fix

(cherry picked from commit 9f78f116b2)
2020-05-19 12:12:45 +02:00
cooldome
a7ebbad8cf fix #14219 (#14225)
Co-authored-by: cooldome <ariabushenko@bk.ru>
(cherry picked from commit a39123c93c)
2020-05-19 12:12:45 +02:00
Antonis
e9d2b8971a better error message
(cherry picked from commit 517dd800f8)
2020-05-18 22:22:27 +02:00
Antonis
287dff200d fix closure env check
(cherry picked from commit 3616b0698b)
2020-05-18 22:22:08 +02:00
Clyybber
d60a01e513 Fix the DFA for "unstructured controlflow" (#14263)
* Fix the DFA for "unstructured controlflow"

* Add testcase from #14233

(cherry picked from commit 42db75c970)
2020-05-18 22:21:56 +02:00
cooldome
8cb8cb7861 Implements RFCs #209 (#13995)
* add test
* add changelod entry
Co-authored-by: cooldome <ariabushenko@bk.ru>

(cherry picked from commit 9295251e68)
2020-05-18 22:16:07 +02:00
narimiran
9b510643fa install gtk3 on osx for package testing 2020-05-18 16:46:40 +02:00
narimiran
d2d401c657 disable the new fragile test in 'tosproc.nim' 2020-05-14 09:58:15 +02:00
Kaushal Modi
7826356f36 Fail quickly if re or nre module is attempted to be compiled with js [backport] (#14341)
Fixes https://github.com/nim-lang/Nim/issues/14338 .

(cherry picked from commit a2a3fa1039)
2020-05-14 07:32:38 +02:00
Andreas Rumpf
32d56fa913 fixes #13998 [backport:1.2]
(cherry picked from commit 82870e0737)
2020-05-14 07:32:29 +02:00
Andreas Rumpf
59a97a0e06 fixes #13104 [backport]
(cherry picked from commit f3e17e7c77)
2020-05-14 07:32:23 +02:00
slangmgh
de867bea3c Fix #14289 (#14304) [backport]
(cherry picked from commit 76f7e95814)
2020-05-14 07:31:03 +02:00
Timothee Cour
8e5e92f679 fix https://github.com/nim-lang/Nim/issues/14275 querySetting(nimcacheDir) works even if implicitly set (#14277)
(cherry picked from commit 363b7ff3b8)
2020-05-13 08:15:50 +02:00
Timothee Cour
01f42a5933 fix a critical bug in windows.osproc leading to resource leaks and blocking IO [backport] (#14296)
(cherry picked from commit d11cb9d495)
2020-05-13 08:15:24 +02:00
alaviss
8e5c389bef net: remove more erroneous set constructions (#14252) [backport]
Refs #13764

(cherry picked from commit 1a1e9986a3)
2020-05-13 08:15:17 +02:00
Andreas Rumpf
75abd4dc68 fixes #14209 [backport:1.2] (#14213)
* fixes #14209 [backport:1.2]
* improve stability

(cherry picked from commit 64e839d5fd)
2020-05-06 17:22:16 +02:00
Andreas Rumpf
2977a31654 destructors: don't produce stupid code for 'cast' (#14208) [backport:1.2]
* destructors: don't produce stupid code for 'cast'

* fixes #14207

(cherry picked from commit b6fb609e0d)
2020-05-06 17:20:07 +02:00
slangmgh
05151d7f62 Fix #14151 (#14205) [backport]
(cherry picked from commit d5c014e59b)
2020-05-06 17:13:52 +02:00
Araq
a5d0950eb0 fixes #14159 [backport:1.2]
(cherry picked from commit 87ac28d19a)
2020-05-06 17:13:34 +02:00
Kaushal Modi
9ff2ec7ec5 Document that proc named fooTask is created for every foo task [backport] (#14187)
Ref: https://irclogs.nim-lang.org/01-05-2020.html#15:18:03
(cherry picked from commit 0880f118d3)
2020-05-06 17:09:59 +02:00
Andreas Rumpf
9caa1a5aa8 arc: do not unload globals when building a library [backport:1.2] (#14180)
(cherry picked from commit d5fc35c968)
2020-05-06 17:09:35 +02:00
Andreas Rumpf
62b9dcb8db fixes #13698 [backport:1.2] (#14175)
(cherry picked from commit 89be5be03e)
2020-05-06 17:09:21 +02:00
Andreas Rumpf
b997e32129 fixes #13986 [backport:1.2] (#14173)
(cherry picked from commit cf3e0008b9)
2020-05-06 17:09:12 +02:00
Andreas Rumpf
ff90206332 fixes #14054 [backport:1.2] (#14061)
* fixes #14054

* make tests green again

* more tests are green

* maybe now

(cherry picked from commit cc60caedb3)
2020-05-06 17:09:07 +02:00
Araq
b09f7275b2 fixes another silly arc/orc bug [backport:1.2]
(cherry picked from commit bd57f0cd32)
2020-05-06 17:08:43 +02:00
Andreas Rumpf
49decbf4b4 fixes #14079 [backport:1.2] (#14163)
(cherry picked from commit d9e907c0e2)
2020-05-06 17:08:32 +02:00
narimiran
dc3919bb1a use the same Azure Pipelines workflow as current devel 2020-04-28 14:27:07 +02:00
genotrance
d3cd0cc843 Improve #12920 fix (#13958)
(cherry picked from commit 35b046373a)
2020-04-28 08:00:08 +02:00
Timothee Cour
0136fc3e53 fix #14132 dsymutil should not be called on static libraries (#14133) [backport:1.2]
(cherry picked from commit b8d7a98265)
2020-04-28 07:59:11 +02:00
hlaaftana
14ce3e45e0 small docs fix in typetraits (#14108)
(cherry picked from commit 31ba27590c)
2020-04-26 07:25:07 +02:00
Jae Yang
4513cb0680 Fixes #14110 (#14111)
Fixes jsffi usage example in doc

(cherry picked from commit 362c8964bf)
2020-04-26 07:25:01 +02:00
Timothee Cour
b8573064e0 fix nim CI; fix local testament (#14102)
(cherry picked from commit d5b7e9902c)
2020-04-25 15:17:57 +02:00
alaviss
b306c1a449 testament: don't try to test nimgrep if it's not there [backport:1.2] (#14085)
One more compiler source-specific tackled

(cherry picked from commit dd5ccc3e5a)
2020-04-25 15:15:35 +02:00
Timothee Cour
a5b74b99ad [ci skip] changelog conflicts are a thing of the past (#14098)
(cherry picked from commit f07f07eef9)
2020-04-25 15:15:22 +02:00
alaviss
abbf94127d testament: don't rely on Nim source structure [backport:1.2] (#14077)
It's also just faster to get the current file name instead of scanning
the PATH.

(cherry picked from commit 4b43d42b98)
2020-04-23 18:45:38 +02:00
alaviss
bd12e7fb17 tools/finish: don't quote path with space (#14058) [backport]
Path with spaces should be added as is, quoting them makes utilities
treat the quotes as part of the path. This makes `nim` unable to be used
from the command line even if it appears to be added to user's Path
environment variable.

Even more confusing, Windows 10's PATH editor shows the path without any
quotes, you only see them when you use "Edit text". Took me a good 15
minutes to figure out why couldn't I run `nim` despite it being in Path.

(cherry picked from commit 22418ce8fb)
2020-04-23 18:45:28 +02:00
Andreas Rumpf
6e625246ce fixes #14052 [backport:1.2] (#14055)
(cherry picked from commit 1b6c4ed2ba)
2020-04-23 18:44:38 +02:00
alaviss
57f41d6b6c asyncdispatch: export Callback (#14042) [backport]
This let us see the definition of `Callback` in docs, which is required
to even make use of asyncdispatch.

Ref #13539.

(cherry picked from commit 7beed44fc9)
2020-04-23 18:44:24 +02:00
Timothee Cour
dbf35e2ac3 fix https://github.com/nim-lang/RFCs/issues/211: var a: DateTime compiles and is usable (#14002) [backport:1.2]
* fix https://github.com/nim-lang/RFCs/issues/211: `var a: DateTime` works
* assertValidDate checks for sentinel month

(cherry picked from commit e3919b658f)
2020-04-23 18:44:03 +02:00
cooldome
9d667306df fix #14007 (#14012) [backport]
Co-authored-by: cooldome <ariabushenko@bk.ru>
(cherry picked from commit d839eb9352)
2020-04-23 18:43:50 +02:00
cooldome
605d395ace fixes #14003 (#14006) [backport:1.2]
Co-authored-by: cooldome <ariabushenko@bk.ru>
(cherry picked from commit f10689d3d4)
2020-04-23 18:43:35 +02:00
Miran
a1610420c5 make fuzzy search a bit less fuzzy (#13996) [backport:1.2]
(cherry picked from commit 06e0c75ba9)
2020-04-23 18:43:25 +02:00
narimiran
dd0e823a0c package 'inim' now has dependencies 2020-04-20 18:55:57 +02:00
Timothee Cour
341141529f backport nimExe from #13876 (#14024) 2020-04-20 13:39:17 +02:00
narimiran
1e3bdf04d8 bump Nim version to 1.2.1 2020-04-14 09:30:20 +02:00
Dominik Picheta
f1bf28d5de Fixes issues with dynamic loading OpenSSL. Fixes #13903. (#13919) [backport]
This fixes at least a couple of issues:

* Procs loaded from the DLL being used even when the pointer is nil.
* The actual issue (#13903) which appeared to cause stack corruption on
  Android 7.1.1 with OpenSSL 1.1.1f. The change that fixed this was the
  move to loading the procs in `sslSym`.

(cherry picked from commit 350ee0308a)
2020-04-14 07:30:29 +02:00
cooldome
9ef1acac64 fix #13909 (#13914) [backport:1.2]
Co-authored-by: cooldome <ariabushenko@bk.ru>
(cherry picked from commit f86fc5316a)
2020-04-14 07:30:24 +02:00
Timothee Cour
f34779c289 fix #13902 distinct uint64 type corruption on 32-bit with borrow (#13907) [backport:1.2]
* fix #13902 distinct uint64 type corruption on 32-bit with borrow

Co-authored-by: Timothee Cour <timothee.cour2+lightsail@gmail.com>
(cherry picked from commit 95fd8ae93c)
2020-04-14 07:30:14 +02:00
Clyybber
078df45e99 Fix #13889 with testcase (#13896) [backport]
* Fix https://github.com/nim-lang/Nim/issues/13889

* Add testcase

* Reduce test time

Co-authored-by: Elie Zedeck RANDRIAMIANDRIRAY <elie.zedeck@gmail.com>
(cherry picked from commit 92c4aad205)
2020-04-14 07:30:06 +02:00
Timothee Cour
adf644d6a4 openDefaultBrowser now works on OSX (#13892) [backport]
(cherry picked from commit e6d870896b)
2020-04-14 07:29:59 +02:00
Timothee Cour
0d59ec9b54 fix https://github.com/timotheecour/Nim/issues/88 (#13865) [backport:1.2]
(cherry picked from commit f1fd3ef7f4)
2020-04-14 07:29:37 +02:00
supakeen
c4dfdb71f4 Add isNil check to custom Content-Length. (#13867) [backport:1.2]
Related to #13866.

(cherry picked from commit 09ca19208f)
2020-04-14 07:29:26 +02:00
narimiran
7e83adff84 bump Nim version to 1.2.0 2020-04-03 14:17:15 +02:00
967 changed files with 17727 additions and 43951 deletions

View File

@@ -1,34 +0,0 @@
## do not edit directly; auto-generated by `nim r tools/ci_generate.nim`
image: openbsd/latest
packages:
- gmake
- sqlite3
- node
- boehm-gc
- pcre
- sfml
- sdl2
- libffi
sources:
- https://github.com/nim-lang/Nim
environment:
NIM_TESTAMENT_BATCH: "0_3"
CC: /usr/bin/clang
tasks:
- setup: |
cd Nim
git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources
gmake -C csources -j $(sysctl -n hw.ncpuonline)
bin/nim c koch
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
- test: |
cd Nim
if ! ./koch runCI; then
nim c -r tools/ci_testresults.nim
exit 1
fi
triggers:
- action: email
condition: failure
to: Andreas Rumpf <rumpf_a@web.de>

View File

@@ -1,34 +0,0 @@
## do not edit directly; auto-generated by `nim r tools/ci_generate.nim`
image: openbsd/latest
packages:
- gmake
- sqlite3
- node
- boehm-gc
- pcre
- sfml
- sdl2
- libffi
sources:
- https://github.com/nim-lang/Nim
environment:
NIM_TESTAMENT_BATCH: "1_3"
CC: /usr/bin/clang
tasks:
- setup: |
cd Nim
git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources
gmake -C csources -j $(sysctl -n hw.ncpuonline)
bin/nim c koch
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
- test: |
cd Nim
if ! ./koch runCI; then
nim c -r tools/ci_testresults.nim
exit 1
fi
triggers:
- action: email
condition: failure
to: Andreas Rumpf <rumpf_a@web.de>

View File

@@ -1,34 +0,0 @@
## do not edit directly; auto-generated by `nim r tools/ci_generate.nim`
image: openbsd/latest
packages:
- gmake
- sqlite3
- node
- boehm-gc
- pcre
- sfml
- sdl2
- libffi
sources:
- https://github.com/nim-lang/Nim
environment:
NIM_TESTAMENT_BATCH: "2_3"
CC: /usr/bin/clang
tasks:
- setup: |
cd Nim
git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources
gmake -C csources -j $(sysctl -n hw.ncpuonline)
bin/nim c koch
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
- test: |
cd Nim
if ! ./koch runCI; then
nim c -r tools/ci_testresults.nim
exit 1
fi
triggers:
- action: email
condition: failure
to: Andreas Rumpf <rumpf_a@web.de>

View File

@@ -12,14 +12,9 @@ Function `echo` outputs the wrong string.
### Example
```nim
echo "Hello World!"
# This code should be a minimum reproducible example:
# try to simplify and minimize as much as possible. If it's a compiler
# issue, try to minimize further by removing any imports if possible.
```
### Current Output
please check whether the problem still exists in git head before posting,
see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler).
```
Hola mundo!
```
@@ -34,18 +29,12 @@ Hello World!
* In file xyz there is a call that might be the cause of it.
### Additional Information
If it's a regression, you can help us by identifying which version introduced
the bug, see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
or at least try known past releases (eg `choosenim 1.2.0`).
If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler)
which should give more context on a compiler crash.
* It was working in version a.b.c
* Issue #abc is related, but different because of ...
* This issue is blocking my project xyz
```
$ nim -v
Nim Compiler Version 0.1.2
# make sure to include the git hash if not using a tagged release
```

69
.github/stale.yml vendored
View File

@@ -1,69 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 365
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- ARC
- bounty
- Codegen
- Crash
- Generics
- High Priority
- Macros
- Next release
- Showstopper
- Static[T]
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity.
If you think it is still a valid PR, please rebase it on the latest devel;
otherwise it will be closed. Thank you for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
# closeComment: >
# Your comment here.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 20
# Limit to only `issues` or `pulls`
only: pulls
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed

View File

@@ -1,37 +1,22 @@
name: Nim Docs CI
on:
push:
# Run only on changes on these files
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'lib/**.nim'
- 'doc/**.rst'
- 'doc/nimdoc.css'
- 'lib/**.nim'
- 'nimdoc/testproject/expected/testproject.html'
- 'tools/dochack/dochack.nim'
- 'tools/kochdocs.nim'
- '.github/workflows/ci_docs.yml'
- 'koch.nim'
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/nimdoc.css'
- 'lib/**.nim'
- 'nimdoc/testproject/expected/testproject.html'
- 'tools/dochack/dochack.nim'
- 'tools/kochdocs.nim'
- '.github/workflows/ci_docs.yml'
pull_request:
# Run only on changes on these files
paths:
- 'lib/**.nim'
- 'doc/**.rst'
- '.github/workflows/ci_docs.yml'
jobs:
build:
if: |
!contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]')
strategy:
fail-fast: false
matrix:
@@ -126,14 +111,17 @@ jobs:
shell: bash
run: ./koch boot -d:release
- name: 'Clone fusion'
shell: bash
run: ./koch fusion
- name: 'Build documentation'
shell: bash
run: ./koch doc --git.commit:devel
- name: 'Prepare documentation for deployment'
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
shell: bash
run: cp -f doc/html/{overview,index}.html
- name: 'Publish documentation to Github Pages'
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&

View File

@@ -1,85 +0,0 @@
name: Packages CI
on: [push, pull_request]
jobs:
build:
if: |
!contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]')
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11]
cpu: [amd64]
pkg: [1, 2]
name: '${{ matrix.os }} (pkg: ${{ matrix.pkg }})'
runs-on: ${{ matrix.os }}
env:
NIM_TEST_PACKAGES: ${{ matrix.pkg }}
steps:
- name: 'Checkout'
uses: actions/checkout@v2
- name: 'Checkout csources'
uses: actions/checkout@v2
with:
repository: nim-lang/csources
path: csources
- name: 'Install node.js 12.x'
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt-fast update -qq
DEBIAN_FRONTEND='noninteractive' \
sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
mkdir dist
curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
7z x dist/mingw64.7z -odist
7z x dist/dlls.zip -obin
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'Build csources'
shell: bash
run: |
ncpu=
case '${{ runner.os }}' in
'Linux')
ncpu=$(nproc)
;;
'macOS')
ncpu=$(sysctl -n hw.ncpu)
;;
'Windows')
ncpu=$NUMBER_OF_PROCESSORS
;;
esac
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'Build koch'
shell: bash
run: nim c koch
- name: 'Run CI'
shell: bash
run: ./koch runCI
- name: 'Show failed tests'
if: failure()
shell: bash
run: nim c -r tools/ci_testresults.nim

View File

@@ -12,8 +12,6 @@ on:
jobs:
build:
if: |
!contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]')
strategy:
fail-fast: false
matrix:

8
.gitignore vendored
View File

@@ -66,7 +66,6 @@ testament.db
/tests/**/*.js
/csources
/dist/
/lib/fusion
# Private directories and files (IDEs)
.*/
@@ -83,8 +82,6 @@ megatest.nim
/outputExpected.txt
/outputGotten.txt
/t15148.txt
/tests/vm/tfile_rw.txt
/lib/pure/*.js
@@ -95,8 +92,7 @@ megatest.nim
# ignore debug dirs generated by dsymutil on OSX
*.dSYM
nimdoc.out.css
# for `nim c -r nimdoc/tester` etc; this can be in multiple places
htmldocs
## these are not needed anymore unless checkout old older versions
nimdoc.out.css

View File

@@ -22,7 +22,7 @@ addons:
- valgrind
before_script:
- git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
- git clone --depth 1 https://github.com/nim-lang/csources.git
- export PATH="$PWD/bin${PATH:+:$PATH}"
- make -C csources -j 2 LD=$CC ucpu=$CPU

View File

@@ -27,19 +27,17 @@ jobs:
vmImage: 'macOS-11'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
Windows_amd64:
vmImage: 'windows-2019'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
Linux_amd64_pkg:
vmImage: 'ubuntu-18.04'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
NIM_TEST_PACKAGES: true
OSX_amd64_pkg:
vmImage: 'macOS-10.15'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
NIM_TEST_PACKAGES: true
pool:
vmImage: $(vmImage)
@@ -107,7 +105,7 @@ jobs:
displayName: 'Install dependencies (i386 Linux)'
condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386'))
- bash: brew install boehmgc make sfml
- bash: brew install boehmgc make sfml gtk+3
displayName: 'Install dependencies (OSX)'
condition: eq(variables['Agent.OS'], 'Darwin')

View File

@@ -5,15 +5,17 @@ set -e
which nim > /dev/null || (echo "nim not in PATH"; exit 1)
which gdb > /dev/null || (echo "gdb not in PATH"; exit 1)
which readlink > /dev/null || (echo "readlink not in PATH."; exit 1)
if [[ "$(uname -s)" == "Darwin" || "(uname -s)" == *"BSD" ]]; then
NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim))))
if [[ "$(uname -s)" == "Darwin" ]]; then
which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from homebrew."; exit 1)
READLINK=greadlink
else
NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim))))
which readlink > /dev/null || (echo "readlink not in PATH."; exit 1)
READLINK=readlink
fi
# Find out where the pretty printer Python module is
NIM_SYSROOT=$(dirname $(dirname $($READLINK -e $(which nim))))
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py"
# Run GDB with the additional arguments that load the pretty printers

BIN
build.out Executable file

Binary file not shown.

4
build_all.sh Executable file → Normal file
View File

@@ -1,7 +1,7 @@
#! /bin/sh
# build development version of the compiler; can be rerun safely.
# arguments can be passed, e.g. `--os freebsd`
# arguments can be passed, eg `--os freebsd`
set -u # error on undefined variables
set -e # exit on first error
@@ -24,7 +24,7 @@ build_nim_csources(){
# avoid changing dir in case of failure
(
if [ $# -ne 0 ]; then
# some args were passed (e.g.: `--cpu i386`), need to call build.sh
# some args were passed (eg: `--cpu i386`), need to call build.sh
build_nim_csources_via_script "$@"
else
# no args, use multiple Make jobs (5X faster on 16 cores: 10s instead of 50s)

View File

@@ -1,14 +1,7 @@
# v1.6.x - yyyy-mm-dd
# v1.4.0 - yyyy-mm-dd
## Changes affecting backward compatibility
- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected.
The downside is that these defines now have custom logic that doesn't apply for
other defines.
## Standard library additions and changes
- Added support for parenthesized expressions in `strformat`
@@ -18,6 +11,127 @@
- Make custom op in macros.quote work for all statements.
For `net` and `nativesockets`, an `inheritable` flag has been added to all
`proc`s that create sockets, allowing the user to control whether the
resulting socket is inheritable. This flag is provided to ease the writing of
multi-process servers, where sockets inheritance is desired.
For a transistion period, define `nimInheritHandles` to enable file handle
inheritance by default. This flag does **not** affect the `selectors` module
due to the differing semantics between operating systems.
`system.setInheritable` and `nativesockets.setInheritable` is also introduced
for setting file handle or socket inheritance. Not all platform have these
`proc`s defined.
- The file descriptors created for internal bookkeeping by `ioselector_kqueue`
and `ioselector_epoll` will no longer be leaked to child processes.
- `strutils.formatFloat` with `precision = 0` has been restored to the version
1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)`
is now `3.`, not `3`.
- `critbits` adds `commonPrefixLen`.
- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results
(see #13222); instead they now use `getCurrentDir` to resolve those cases,
and this can now throw in edge cases where `getCurrentDir` throws.
`relativePath` also now works for js with `-d:nodejs`.
- JavaScript and NimScript standard library changes: `streams.StringStream` is
now supported in JavaScript, with the limitation that any buffer `pointer`s
used must be castable to `ptr string`, any incompatible pointer type will not
work. The `lexbase` and `streams` modules used to fail to compile on
NimScript due to a bug, but this has been fixed.
The following modules now compile on both JS and NimScript: `parsecsv`,
`parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally
supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for
NimScript: `json`, `parsejson`, `strtabs` and `unidecode`.
- Added `streams.readStr` and `streams.peekStr` overloads to
accept an existing string to modify, which avoids memory
allocations, similar to `streams.readLine` (#13857).
- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom`. UDP functionality.
- `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble.
- `dollars.$` now works for unsigned ints with `nim js`
- Improvements to the `bitops` module, including bitslices, non-mutating versions
of the original masking functions, `mask`/`masked`, and varargs support for
`bitand`, `bitor`, and `bitxor`.
- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed
into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency
with regular proc definitions (although you cannot use semicolons).
Pragmas and using a name are now allowed on the lefthand side of `=>`. Here
is an aggregate example of these changes:
```nim
import sugar
foo(x, y: int) {.noSideEffect.} => x + y
# is transformed into
proc foo(x: int, y: int): auto {.noSideEffect.} = x + y
```
- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters.
- The `times` module now handles the default value for `DateTime` more consistently. Most procs raise an assertion error when given
an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). The proc `times.isInitialized`
has been added which can be used to check if a `DateTime` has been initialized.
- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to
hangs if a process had both reads from stdin and writes (eg to stdout).
- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`.
- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`.
- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env`
parameters.
- Added a `ssl_config` module containing lists of secure ciphers as recommended by
[Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS)
- `net.newContext` now defaults to the list of ciphers targeting
["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29)
per Mozilla's recommendation instead of `ALL`. This change should protect
users from the use of weak and insecure ciphers while still provides
adequate compatibility with the majority of the Internet.
- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json
serialization/deserialization of custom types was added.
- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``
was added.
- Added `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator`
with `outLatex` output.
- Added `os.normalizeExe`, e.g.: `koch` => `./koch`.
- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720`
to keep old behavior.
- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution.
- Added `typetraits.elementType` to get element type of an iterable.
- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`;
`$tuple[]` is now `"tuple[]"` instead of `"tuple"`;
`$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"`
- Added `macros.extractDocCommentsAndRunnables` helper
- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now
expands to `fmt"expr={expr}"`.
- deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists`
- Added `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`,
because negative values will result in a new file being created for each logged
line which doesn't make sense.
- Changed `log` in `logging` to use proper log level on JavaScript target,
e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc.
- Tables, HashSets, SharedTables and deques don't require anymore that the passed
initial size must be a power of two - this is done internally.
Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore.
`CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again.
- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`.
- On Windows the SSL library now checks for valid certificates.
It uses the `cacert.pem` file for this purpose which was extracted
from `https://curl.se/ca/cacert.pem`. Besides
@@ -27,53 +141,214 @@
- Make `{.requiresInit.}` pragma to work for `distinct` types.
- Added a macros `enumLen` for returning the number of items in an enum to the
`typetraits.nim` module.
- `prelude` now works with the JavaScript target.
- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`.
- The JSON module can now handle integer literals and floating point literals of arbitrary length and precision.
Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are kept as string literals and
one can use external BigNum libraries to handle these. The `parseFloat` family of functions also has now optional
`rawIntegers` and `rawFloats` parameters that can be used to enforce that all integer or float literals remain
in the "raw" string form so that client code can easily treat small and large numbers uniformly.
- Added `randState` template that exposes the default random number generator. Useful for library authors.
- Added `asyncdispatch.activeDescriptors` that returns the number of currently
active async event handles/file descriptors
- Added `asyncdispatch.maxDescriptors` that returns the maximum number of
active async event handles/file descriptors.
- Added `getPort` to `asynchttpserver`.
- `--gc:orc` is now 10% faster than previously for common workloads. If
you have trouble with its changed behavior, compile with `-d:nimOldOrc`.
- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`,
determining preferred I/O block size for this file object.
- Added a simpler to use `io.readChars` overload.
- Added `**` to jsffi.
- `writeStackTrace` is available in JS backend now.
- Added `decodeQuery` to `std/uri`.
- `strscans.scanf` now supports parsing single characters.
- `strscans.scanTuple` added which uses `strscans.scanf` internally,
returning a tuple which can be unpacked for easier usage of `scanf`.
- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`,
if the iterable yields a built-in settable type.
- Added `setutils.fullSet` which returns a full built-in `set` for a valid type.
- Added `setutils.complement` which returns the complement of a built-in `set`.
- Added `setutils.[]=`.
- Added `math.isNaN`.
- Added `jsbigints` module, arbitrary precision integers for JavaScript target.
- Added `math.copySign`.
- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList`
and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes
its argument, `addMoved`, is also supplied.
- Added `euclDiv` and `euclMod` to `math`.
- Added `httpcore.is1xx` and missing HTTP codes.
- Added `jsconsole.jsAssert` for JavaScript target.
- Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs.
https://www.freedesktop.org/software/systemd/man/os-release.html
- Added `socketstream` module that wraps sockets in the stream interface
- Added `sugar.dumpToString` which improves on `sugar.dump`.
- Added `math.signbit`.
- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably)
- In `lists`: renamed `append` to `add` and retained `append` as an alias;
added `prepend` and `prependMoved` analogously to `add` and `addMoved`;
added `remove` for `SinglyLinkedList`s.
- Deprecated `any`. See https://github.com/nim-lang/RFCs/issues/281
- Added optional `options` argument to `copyFile`, `copyFileToDir`, and
`copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are
followed (copy files symlinks point to); on Windows, `options` argument is
ignored and symlinks are skipped.
- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as
symlinks (instead of skipping them as it was before); on Windows symlinks are
skipped.
- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks
(instead of skipping them sometimes as it was before).
- Added optional `followSymlinks` argument to `setFilePermissions`.
- Added `os.isAdmin` to tell whether the caller's process is a member of the
Administrators local group (on Windows) or a root (on POSIX).
- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C).
- Added `compilesettings.SingleValueSetting.libPath`.
- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding
issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages)
for modules importing `std/wrapnils`.
Added `??.` macro which returns an `Option`.
- Added `math.frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead.
- `parseopt.initOptParser` has been made available and `parseopt` has been
added back to `prelude` for all backends. Previously `initOptParser` was
unavailable if the `os` module did not have `paramCount` or `paramStr`,
but the use of these in `initOptParser` were conditionally to the runtime
arguments passed to it, so `initOptParser` has been changed to raise
`ValueError` when the real command line is not available. `parseopt` was
previously excluded from `prelude` for JS, as it could not be imported.
- Added `system.prepareStrMutation` for better support of low
level `moveMem`, `copyMem` operations for Orc's copy-on-write string
implementation.
- Added `std/strbasics` for high performance string operations.
Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`.
- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`.
- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
- Added `algorithm.merge`.
- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target.
- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target.
- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target.
- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible
with most other languages.
- Removed support for named procs in `sugar.=>`.
- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger).
- Added `std/channels`.
- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals).
- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time
zone offsets without colons, e.g. `UTC+7 -> +0700`.
- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`.
- Added dollar `$` and `len` for `jsre.RegExp`.
- Added `std/tasks`.
- Added `hasDataBuffered` to `asyncnet`.
- Added `hasClosure` to `std/typetraits`.
- Added `std/tempfiles`.
- Added `genasts.genAst` that avoids the problems inherent with `quote do` and can
be used as a replacement.
- Added `copyWithin` [for `seq` and `array` for JavaScript targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin).
- Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place.
## Language changes
- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this:
- `nimscript` now handles `except Exception as e`
- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts
`wasMoved` calls where needed.
- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there
is no need to update your code. This change was backported to 1.2 too so you can use the
more readability `=copy` without loss of compatibility.
- The `cstring` doesn't support `[]=` operator in JS backend.
- In the newruntime it is now allowed to assign to the discriminator field
without restrictions as long as case object doesn't have custom destructor.
The discriminator value doesn't have to be a constant either. If you have a
custom destructor for a case object and you do want to freely assign discriminator
fields, it is recommended to refactor object into 2 objects like this:
```nim
type
MyObj = object
case kind: bool
of true: y: ptr UncheckedArray[float]
of false: z: seq[int]
proc `=destroy`(x: MyObj) =
if x.kind and x.y != nil:
deallocShared(x.y)
x.y = nil
```
Refactor into:
```nim
type
MySubObj = object
val: ptr UncheckedArray[float]
MyObj = object
case kind: bool
of true: y: MySubObj
of false: z: seq[int]
proc `=destroy`(x: MySubObj) =
if x.val != nil:
deallocShared(x.val)
x.val = nil
```
## Compiler changes
- Added `unsafeIsolate` and `extract` to `std/isolation`.
- `--hint:CC` now goes to stderr (like all other hints) instead of stdout.
- json build instructions are now generated in `$nimcache/outFileBasename.json`
instead of `$nimcache/projectName.json`. This allows avoiding recompiling a given project
compiled with different options if the output file differs.
- `--usenimcache` (implied by `nim r main`) now generates an output file that includes a hash of
some of the compilation options, which allows caching generated binaries:
nim r main # recompiles
nim r -d:foo main # recompiles
nim r main # uses cached binary
nim r main arg1 arg2 # ditto (runtime arguments are irrelevant)
- The style checking of the compiler now supports a `--styleCheck:usages` switch. This switch
enforces that every symbol is written as it was declared, not enforcing
the official Nim style guide. To be enabled, this has to be combined either

View File

@@ -2,6 +2,7 @@
## Standard library additions and changes
- Added overloaded `strformat.fmt` macro that use specified characters as
delimiter instead of '{' and '}'.
- Added new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`,
@@ -32,7 +33,7 @@
- Added `expectIdent` to the `macros` module.
- Added `os.isValidFilename` that returns `true` if `filename` argument is valid
for cross-platform use.
- Added `times.isLeapDay`.
- Added `times.isLeapDay`
- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7.
- Added a new module, `std / compilesettings` for querying the compiler about
diverse configuration settings.
@@ -52,8 +53,6 @@
was designed for it. For example:
```nim
import std/with
type
Foo = object
col, pos: string
@@ -114,6 +113,8 @@ echo f
usage. The `$` operator can be used to obtain the string form of `HttpCode`
for comparison if desired.
- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs.
- `net.newContext` now performs SSL Certificate checking on Linux and OSX.
Define `nimDisableCertificateValidation` to disable it globally.
- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false).
If it is set to true, it will throw if input dir is invalid instead of a noop
(which is the default behaviour, as it was before this change),
@@ -127,8 +128,8 @@ echo f
of children nodes.
- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/"
as the dir component of `/root_sub_dir` instead of the empty string.
- The deprecated `lc` macro has been removed from `sugar`. It is now replaced
with the more powerful `collect` macro.
- The deprecated `lc` macro has been removed from `sugar`. It is now replaced with the
more powerful `collect` macro.
- `os.relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid
path and shouldn't be conflated with `"."`; use `-d:nimOldRelativePathBehavior`
to restore the old behavior.
@@ -137,33 +138,25 @@ echo f
Use `base64.encodeMime` instead.
### Breaking changes
- `net.newContext` now performs SSL Certificate checking on Linux and OSX.
Define `nimDisableCertificateValidation` to disable it globally.
## Language changes
- An `align` pragma can now be used for variables and object fields, similar
to the `alignas` declaration modifier in C/C++.
- The `=sink` type bound operator is now optional. The compiler can now use a
combination of `=destroy` and `copyMem` to move objects efficiently.
- `=sink` type bound operator is now optional. Compiler can now use combination
of `=destroy` and `copyMem` to move objects efficiently.
- Unsigned integer operators have been fixed to allow promotion of the first operand.
- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim
versions. The documentation was improved to acknowledge this special case.
See https://github.com/nim-lang/RFCs/issues/175 for more details.
- There is a new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by
- New syntax for lvalue references: `var b {.byaddr.} = expr` enabled by
`import std/decls`.
- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for
non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`).
## Compiler changes
- The generated JS code uses spaces, instead of mixing spaces and tabs.
- Generated JS code uses spaces, instead of mixed spaces and tabs.
- The Nim compiler now supports the ``--asm`` command option for easier
inspection of the produced assembler code.
- The Nim compiler now supports a new pragma called ``.localPassc`` to
@@ -199,6 +192,10 @@ echo f
with `-d:nimEmulateOverflowChecks`.
## Tool changes
- Nimpretty doesn't accept negative indentation argument anymore, because it was
breaking files.
## Bugfixes

View File

@@ -1,874 +0,0 @@
# v1.4.0 - 2020-10-16
## Standard library additions and changes
- Added some enhancements to `std/jsonutils` module.
* Added a possibility to deserialize JSON arrays directly to `HashSet` and
`OrderedSet` types and respectively to serialize those types to JSON arrays
via `jsonutils.fromJson` and `jsonutils.toJson` procedures.
* Added a possibility to deserialize JSON `null` objects to Nim option objects
and respectively to serialize Nim option object to JSON object if `isSome`
or to JSON null object if `isNone` via `jsonutils.fromJson` and
`jsonutils.toJson` procedures.
* Added a `Joptions` parameter to `jsonutils.fromJson` currently
containing two boolean options `allowExtraKeys` and `allowMissingKeys`.
- If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is
not required to have a field for every JSON key.
- If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is
allowed to have fields without corresponding JSON keys.
- Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement.
- Added `tryInsert`,`insert` procs to `db_*` libs which accept primary key column name.
- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text.
- `uri` module now implements RFC-2397.
- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser)
to the `dom` module for the JavaScript target.
- The default hash for `Ordinal` has changed to something more bit-scrambling.
`import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old
one in an instantiation context while `-d:nimIntHash1` recovers it globally.
- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads.
- File handles created from high-level abstractions in the stdlib will no longer
be inherited by child processes. In particular, these modules are affected:
`asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`.
For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable`
flag has been added to all `proc`s that create sockets, allowing the user to
control whether the resulting socket is inheritable. This flag is provided to
ease the writing of multi-process servers, where sockets inheritance is
desired.
For a transition period, define `nimInheritHandles` to enable file handle
inheritance by default. This flag does **not** affect the `selectors` module
due to the differing semantics between operating systems.
`asyncdispatch.setInheritable`, `system.setInheritable` and
`nativesockets.setInheritable` are also introduced for setting file handle or
socket inheritance. Not all platforms have these `proc`s defined.
- The file descriptors created for internal bookkeeping by `ioselector_kqueue`
and `ioselector_epoll` will no longer be leaked to child processes.
- `strutils.formatFloat` with `precision = 0` has been restored to the version
1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)`
is now `3.`, not `3`.
- Added `commonPrefixLen` to `critbits`.
- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results
(see #13222); instead they now use `getCurrentDir` to resolve those cases,
and this can now throw in edge cases where `getCurrentDir` throws.
`relativePath` also now works for js with `-d:nodejs`.
- JavaScript and NimScript standard library changes: `streams.StringStream` is
now supported in JavaScript, with the limitation that any buffer `pointer`s
used must be castable to `ptr string`, any incompatible pointer type will not
work. The `lexbase` and `streams` modules used to fail to compile on
NimScript due to a bug, but this has been fixed.
The following modules now compile on both JS and NimScript: `parsecsv`,
`parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally
supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for
NimScript: `json`, `parsejson`, `strtabs` and `unidecode`.
- Added `streams.readStr` and `streams.peekStr` overloads to
accept an existing string to modify, which avoids memory
allocations, similar to `streams.readLine` (#13857).
- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality.
- `dollars.$` now works for unsigned ints with `nim js`.
- Improvements to the `bitops` module, including bitslices, non-mutating versions
of the original masking functions, `mask`/`masked`, and varargs support for
`bitand`, `bitor`, and `bitxor`.
- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed
into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` for consistency
with regular proc definitions (although you cannot use semicolons).
Pragmas and using a name are now allowed on the lefthand side of `=>`. Here
is an example of these changes:
```nim
import sugar
foo(x, y: int) {.noSideEffect.} => x + y
# is transformed into
proc foo(x: int, y: int): auto {.noSideEffect.} = x + y
```
- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters.
- The `times` module now handles the default value for `DateTime` more consistently.
Most procs raise an assertion error when given
an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`).
The proc `times.isInitialized` has been added which can be used to check if
a `DateTime` has been initialized.
- Fix a bug where calling `close` on io streams in `osproc.startProcess` was a noop and led to
hangs if a process had both reads from stdin and writes (e.g. to stdout).
- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`.
- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`.
- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env`
parameters.
- Added a `ssl_config` module containing lists of secure ciphers as recommended by
[Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS)
- `net.newContext` now defaults to the list of ciphers targeting
["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29)
per Mozilla's recommendation instead of `ALL`. This change should protect
users from the use of weak and insecure ciphers while still provides
adequate compatibility with the majority of the Internet.
- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json
serialization/deserialization of custom types was added.
- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``
was added.
- Added `rstgen.rstToLatex` a convenience proc for `renderRstToOut` and `initRstGenerator`.
- Added `os.normalizeExe`.
- `macros.newLit` now preserves named vs unnamed tuples.
- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution.
- Added `typetraits.elementType` to get the element type of an iterable.
- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`;
`$tuple[]` is now `"tuple[]"` instead of `"tuple"`;
`$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"`
- Added `macros.extractDocCommentsAndRunnables` helper.
- `strformat.fmt` and `strformat.&` support `specifier =`. `fmt"{expr=}"` now
expands to `fmt"expr={expr}"`.
- Deprecations: instead of `os.existsDir` use `dirExists`, instead of `os.existsFile` use `fileExists`.
- Added the `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions).
- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`,
because negative values will result in a new file being created for each logged
line which doesn't make sense.
- Changed `log` in `logging` to use proper log level for JavaScript,
e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc.
- Tables, HashSets, SharedTables and deques don't require anymore that the passed
initial size must be a power of two - this is done internally.
Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore.
`CountTable.inc` takes `val: int` again not `val: Positive`; i.e. it can "count down" again.
- Removed deprecated symbols from `macros` module, some of which were deprecated already in `0.15`.
- Removed `sugar.distinctBase`, deprecated since `0.19`. Use `typetraits.distinctBase`.
- `asyncdispatch.PDispatcher.handles` is exported so that an external low-level libraries can access it.
- `std/with`, `sugar.dup` now support object field assignment expressions:
```nim
import std/with
type Foo = object
x, y: int
var foo = Foo()
with foo:
x = 10
y = 20
echo foo
```
- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead
cannot be applied to every use case. The limitations and the (lack of) reliability
of `round` are well documented.
- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code
from the database that matches the protocol `name`.
- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc.
- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals:
```nim
import strutils
echo dedent """
This
is
cool!
"""
```
- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname.
- Added `readLines(p: Process)` to `osproc`.
- Added the below `toX` procs for collections. The usage is similar to procs such as
`sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the
respective empty collection and add items manually.
* `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of
items or an `openArray` of pairs.
* `deques.toDeque`, which creates a `Deque` from an `openArray`.
* `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`.
* `intsets.toIntSet`, which creates an `IntSet` from an `openArray`.
- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval
at which progress callbacks are called.
- Added `os.copyFileToDir`.
## Language changes
- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts
`wasMoved` calls where needed.
- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there
is no need to update your code. This change was backported to 1.2 too so you can use the
more readable `=copy` without loss of compatibility.
- In the newruntime it is now allowed to assign to the discriminator field
without restrictions as long as the case object doesn't have a custom destructor.
The discriminator value doesn't have to be a constant either. If you have a
custom destructor for a case object and you do want to freely assign discriminator
fields, it is recommended to refactor the object into 2 objects like this:
```nim
type
MyObj = object
case kind: bool
of true: y: ptr UncheckedArray[float]
of false: z: seq[int]
proc `=destroy`(x: MyObj) =
if x.kind and x.y != nil:
deallocShared(x.y)
```
Refactor into:
```nim
type
MySubObj = object
val: ptr UncheckedArray[float]
MyObj = object
case kind: bool
of true: y: MySubObj
of false: z: seq[int]
proc `=destroy`(x: MySubObj) =
if x.val != nil:
deallocShared(x.val)
```
- `getImpl` on enum type symbols now returns field syms instead of idents. This helps
with writing typed macros. The old behavior for backwards compatibility can be restored
with `--useVersion:1.0`.
- The typed AST for proc headers will now have the arguments be syms instead of idents.
This helps with writing typed macros. The old behaviour for backwards compatibility can
be restored with `--useVersion:1.0`.
- ``let`` statements can now be used without a value if declared with
``importc``/``importcpp``/``importjs``/``importobjc``.
- The keyword `from` is now usable as an operator.
- Exceptions inheriting from `system.Defect` are no longer tracked with
the `.raises: []` exception tracking mechanism. This is more consistent with the
built-in operations. The following always used to compile (and still does):
```nim
proc mydiv(a, b): int {.raises: [].} =
a div b # can raise an DivByZeroDefect
```
Now also this compiles:
```nim
proc mydiv(a, b): int {.raises: [].} =
if b == 0: raise newException(DivByZeroDefect, "division by zero")
else: result = a div b
```
The reason for this is that `DivByZeroDefect` inherits from `Defect` and
with `--panics:on` `Defects` become unrecoverable errors.
- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes.
- Deprecated the `{.unroll.}` pragma, because it was always ignored by the compiler anyway.
- Removed the deprecated `strutils.isNilOrWhitespace`.
- Removed the deprecated `sharedtables.initSharedTable`.
- Removed the deprecated `asyncdispatch.newAsyncNativeSocket`.
- Removed the deprecated `dom.releaseEvents` and `dom.captureEvents`.
- Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour.
- There is a new experimental feature called "strictFuncs" which makes the definition of
`.noSideEffect` stricter. [See here](manual_experimental.html#stricts-funcs)
for more information.
- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer
an experimental feature. In other words, you don't have to write pragma
`{.experimental: "forLoopMacros".}` if you want to use them.
- Added the ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased
performance this keyword can enable.
- `items` no longer compiles with enums with holes as its behavior was error prone, see #14004.
- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via
`--deepcopy:on`.
- Added the `std/effecttraits` module for introspection of the inferred effects.
We hope this enables `async` macros that are precise about the possible exceptions that
can be raised.
- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be
written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new
preferred way of writing these, emphasizing their unsafe nature.
## Compiler changes
- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`.
- The `define` and `undef` pragmas have been de-deprecated.
- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache`
so that the output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to
avoid recompilations when sources don't change.
Example:
```bash
nim r compiler/nim.nim --help # only compiled the first time
echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too
nim r compiler/nim.nim --fullhelp # no recompilation
nim r --nimcache:/tmp main # binary saved to /tmp/main
```
- `--hint:processing` is now supported and means `--hint:processing:on`
(likewise with other hints and warnings), which is consistent with all other bool flags.
(since 1.3.3).
- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`.
- Added the new hint `--hint:msgOrigin` will show where a compiler msg (hint|warning|error)
was generated; this helps in particular when it's non obvious where it came from
either because multiple locations generate the same message, or because the
message involves runtime formatting.
- Added the new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change the backend; can be
used with any command (e.g. nim r, doc, check etc); safe to re-assign.
- Added the new flag `--doccmd:cmd` to pass additional flags for runnableExamples,
e.g.: `--doccmd:-d:foo --threads`
use `--doccmd:skip` to skip runnableExamples and rst test snippets.
- Added the new flag `--usenimcache` to output binary files to nimcache.
- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override
how an example is compiled and run, for example to change the backend.
- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified
(with or without `--project`); passing `--project` now automatically generates
an index and enables search.
See [docgen](docgen.html#introduction-quick-start) for details.
- Removed the `--oldNewlines` switch.
- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings.
- Removed the `--oldast` switch.
- Removed the `--oldgensym` switch.
- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is
now "typed" instead of "stmt".
- Sink inference is now disabled per default and has to enabled explicitly via
`--sinkInference:on`. *Note*: For the standard library sink inference remains
enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory
management modes.
## Tool changes
- `nimsuggest` now returns both the forward declaration and the
implementation location upon a `def` query. Previously the behavior was
to return the forward declaration only.
## Bugfixes
- Fixed "repr() not available for uint{,8,16,32,64} under --gc:arc"
([#13872](https://github.com/nim-lang/Nim/issues/13872))
- Fixed "Critical: 1 completed Future, multiple await: Only 1 await will be awakened (the last one)"
([#13889](https://github.com/nim-lang/Nim/issues/13889))
- Fixed "crash on openarray interator with argument in stmtListExpr"
([#13739](https://github.com/nim-lang/Nim/issues/13739))
- Fixed "Some compilers on Windows don't work"
([#13910](https://github.com/nim-lang/Nim/issues/13910))
- Fixed "httpclient hangs if it recieves an HTTP 204 (No Content)"
([#13894](https://github.com/nim-lang/Nim/issues/13894))
- Fixed ""distinct uint64" type corruption on 32-bit, when using {.borrow.} operators"
([#13902](https://github.com/nim-lang/Nim/issues/13902))
- Fixed "Regression: impossible to use typed pragmas with proc types"
([#13909](https://github.com/nim-lang/Nim/issues/13909))
- Fixed "openssl wrapper corrupts stack on OpenSSL 1.1.1f + Android"
([#13903](https://github.com/nim-lang/Nim/issues/13903))
- Fixed "C compile error with --gc:arc on version 1.2.0 "unknown type name 'TGenericSeq'"
([#13863](https://github.com/nim-lang/Nim/issues/13863))
- Fixed "var return type for proc doesn't work at c++ backend"
([#13848](https://github.com/nim-lang/Nim/issues/13848))
- Fixed "TimeFormat() should raise an error but craches at compilation time"
([#12864](https://github.com/nim-lang/Nim/issues/12864))
- Fixed "gc:arc cannot fully support threadpool with FlowVar"
([#13781](https://github.com/nim-lang/Nim/issues/13781))
- Fixed "simple 'var openarray[char]' assignment crash when the openarray source is a local string and using gc:arc"
([#14003](https://github.com/nim-lang/Nim/issues/14003))
- Fixed "Cant use expressions with `when` in `type` sections."
([#14007](https://github.com/nim-lang/Nim/issues/14007))
- Fixed "`for a in MyEnum` gives incorrect results with enum with holes"
([#14001](https://github.com/nim-lang/Nim/issues/14001))
- Fixed "Trivial crash"
([#12741](https://github.com/nim-lang/Nim/issues/12741))
- Fixed "Enum with holes cannot be used as Table index"
([#12834](https://github.com/nim-lang/Nim/issues/12834))
- Fixed "spawn proc that uses typedesc crashes the compiler"
([#14014](https://github.com/nim-lang/Nim/issues/14014))
- Fixed "Docs Search `Results` box styling is not Dark Mode Friendly"
([#13972](https://github.com/nim-lang/Nim/issues/13972))
- Fixed "--gc:arc -d:useSysAssert undeclared identifier `cstderr` with newSeq"
([#14038](https://github.com/nim-lang/Nim/issues/14038))
- Fixed "issues in the manual"
([#12486](https://github.com/nim-lang/Nim/issues/12486))
- Fixed "Annoying warning: inherit from a more precise exception type like ValueError, IOError or OSError [InheritFromException]"
([#14052](https://github.com/nim-lang/Nim/issues/14052))
- Fixed "relativePath("foo", "/") and relativePath("/", "foo") is wrong"
([#13222](https://github.com/nim-lang/Nim/issues/13222))
- Fixed "[regression] `parseEnum` does not work anymore for enums with holes"
([#14030](https://github.com/nim-lang/Nim/issues/14030))
- Fixed "Exception types in the stdlib should inherit from `CatchableError` or `Defect`, not `Exception`"
([#10288](https://github.com/nim-lang/Nim/issues/10288))
- Fixed "Make debugSend and debugRecv procs public in smtp.nim"
([#12189](https://github.com/nim-lang/Nim/issues/12189))
- Fixed "xmltree need add raw text, when add style element"
([#14064](https://github.com/nim-lang/Nim/issues/14064))
- Fixed "raises requirement does not propagate to derived methods"
([#8481](https://github.com/nim-lang/Nim/issues/8481))
- Fixed "tests/stdlib/tgetaddrinfo.nim fails on NetBSD"
([#14091](https://github.com/nim-lang/Nim/issues/14091))
- Fixed "tests/niminaction/Chapter8/sdl/sdl_test.nim fails on NetBSD"
([#14088](https://github.com/nim-lang/Nim/issues/14088))
- Fixed "Incorrect escape sequence for example in jsffi library documentation"
([#14110](https://github.com/nim-lang/Nim/issues/14110))
- Fixed "HCR: Can not link exported const, in external library"
([#13915](https://github.com/nim-lang/Nim/issues/13915))
- Fixed "Cannot import std/unidecode"
([#14112](https://github.com/nim-lang/Nim/issues/14112))
- Fixed "macOS: dsymutil should not be called on static libraries"
([#14132](https://github.com/nim-lang/Nim/issues/14132))
- Fixed "nim jsondoc -o:doc.json filename.nim fails when sequences without a type are used"
([#14066](https://github.com/nim-lang/Nim/issues/14066))
- Fixed "algorithm.sortedByIt template corrupts tuple input under --gc:arc"
([#14079](https://github.com/nim-lang/Nim/issues/14079))
- Fixed "Invalid C code with lvalue conversion"
([#14160](https://github.com/nim-lang/Nim/issues/14160))
- Fixed "strformat: doc example fails"
([#14054](https://github.com/nim-lang/Nim/issues/14054))
- Fixed "Nim doc fail to run for nim 1.2.0 (nim 1.0.4 is ok)"
([#13986](https://github.com/nim-lang/Nim/issues/13986))
- Fixed "Exception when converting csize to clong"
([#13698](https://github.com/nim-lang/Nim/issues/13698))
- Fixed "[Documentation] overloading using named arguments works but is not documented"
([#11932](https://github.com/nim-lang/Nim/issues/11932))
- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error"
([#14142](https://github.com/nim-lang/Nim/issues/14142))
- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error"
([#14142](https://github.com/nim-lang/Nim/issues/14142))
- Fixed "runnableExamples doc gen crashes compiler with `except Exception as e` syntax"
([#14177](https://github.com/nim-lang/Nim/issues/14177))
- Fixed "[ARC] Segfault with cyclic references (?)"
([#14159](https://github.com/nim-lang/Nim/issues/14159))
- Fixed "Semcheck regression when accessing a static parameter in proc"
([#14136](https://github.com/nim-lang/Nim/issues/14136))
- Fixed "iterator walkDir doesn't work with -d:useWinAnsi"
([#14201](https://github.com/nim-lang/Nim/issues/14201))
- Fixed "cas is wrong for tcc"
([#14151](https://github.com/nim-lang/Nim/issues/14151))
- Fixed "proc execCmdEx doesn't work with -d:useWinAnsi"
([#14203](https://github.com/nim-lang/Nim/issues/14203))
- Fixed "Use -d:nimEmulateOverflowChecks by default?"
([#14209](https://github.com/nim-lang/Nim/issues/14209))
- Fixed "Old sequences with destructor objects bug"
([#14217](https://github.com/nim-lang/Nim/issues/14217))
- Fixed "[ARC] ICE when changing the discriminant of a return value"
([#14244](https://github.com/nim-lang/Nim/issues/14244))
- Fixed "[ARC] ICE with static objects"
([#14236](https://github.com/nim-lang/Nim/issues/14236))
- Fixed "[ARC] "internal error: environment misses: a" in a finalizer"
([#14243](https://github.com/nim-lang/Nim/issues/14243))
- Fixed "[ARC] compile failure using repr with object containing `ref seq[string]`"
([#14270](https://github.com/nim-lang/Nim/issues/14270))
- Fixed "[ARC] implicit move on last use happening on non-last use"
([#14269](https://github.com/nim-lang/Nim/issues/14269))
- Fixed "[ARC] Compiler crash with a recursive non-ref object variant"
([#14294](https://github.com/nim-lang/Nim/issues/14294))
- Fixed "htmlparser.parseHtml behaves differently using --gc:arc or --gc:orc"
([#13946](https://github.com/nim-lang/Nim/issues/13946))
- Fixed "Invalid return value of openProcess is NULL rather than INVALID_HANDLE_VALUE(-1) in windows"
([#14289](https://github.com/nim-lang/Nim/issues/14289))
- Fixed "ARC codegen bug with inline iterators"
([#14219](https://github.com/nim-lang/Nim/issues/14219))
- Fixed "Building koch on OpenBSD fails unless the Nim directory is in `$PATH`"
([#13758](https://github.com/nim-lang/Nim/issues/13758))
- Fixed "[gc:arc] case object assignment SIGSEGV: destroy not called for primitive type "
([#14312](https://github.com/nim-lang/Nim/issues/14312))
- Fixed "Crash when using thread and --gc:arc "
([#13881](https://github.com/nim-lang/Nim/issues/13881))
- Fixed "Getting "Warning: Cannot prove that 'result' is initialized" for an importcpp'd proc with `var T` return type"
([#14314](https://github.com/nim-lang/Nim/issues/14314))
- Fixed "`nim cpp -r --gc:arc` segfaults on caught AssertionError"
([#13071](https://github.com/nim-lang/Nim/issues/13071))
- Fixed "tests/async/tasyncawait.nim is recently very flaky"
([#14320](https://github.com/nim-lang/Nim/issues/14320))
- Fixed "Documentation nonexistent quitprocs module"
([#14331](https://github.com/nim-lang/Nim/issues/14331))
- Fixed "SIGSEV encountered when creating threads in a loop w/ --gc:arc"
([#13935](https://github.com/nim-lang/Nim/issues/13935))
- Fixed "nim-gdb is missing from all released packages"
([#13104](https://github.com/nim-lang/Nim/issues/13104))
- Fixed "sysAssert error with gc:arc on 3 line program"
([#13862](https://github.com/nim-lang/Nim/issues/13862))
- Fixed "compiler error with inline async proc and pragma"
([#13998](https://github.com/nim-lang/Nim/issues/13998))
- Fixed "[ARC] Compiler crash when adding to a seq[ref Object]"
([#14333](https://github.com/nim-lang/Nim/issues/14333))
- Fixed "nimvm: sysFatal: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldError]"
([#14340](https://github.com/nim-lang/Nim/issues/14340))
- Fixed "[Regression] karax events are not firing "
([#14350](https://github.com/nim-lang/Nim/issues/14350))
- Fixed "odbcsql module has some wrong integer types"
([#9771](https://github.com/nim-lang/Nim/issues/9771))
- Fixed "db_sqlite needs sqlPrepared"
([#13559](https://github.com/nim-lang/Nim/issues/13559))
- Fixed "[Regression] `createThread` is not GC-safe"
([#14370](https://github.com/nim-lang/Nim/issues/14370))
- Fixed "Broken example on hot code reloading"
([#14380](https://github.com/nim-lang/Nim/issues/14380))
- Fixed "runnableExamples block with `except` on specified error fails with `nim doc`"
([#12746](https://github.com/nim-lang/Nim/issues/12746))
- Fixed "compiler as a library: findNimStdLibCompileTime fails to find system.nim"
([#12293](https://github.com/nim-lang/Nim/issues/12293))
- Fixed "5 bugs with importcpp exceptions"
([#14369](https://github.com/nim-lang/Nim/issues/14369))
- Fixed "Docs shouldn't collapse pragmas inside runnableExamples/code blocks"
([#14174](https://github.com/nim-lang/Nim/issues/14174))
- Fixed "Bad codegen/emit for hashes.hiXorLo in some contexts."
([#14394](https://github.com/nim-lang/Nim/issues/14394))
- Fixed "Boehm GC does not scan thread-local storage"
([#14364](https://github.com/nim-lang/Nim/issues/14364))
- Fixed "RVO not exception safe"
([#14126](https://github.com/nim-lang/Nim/issues/14126))
- Fixed "runnableExamples that are only compiled"
([#10731](https://github.com/nim-lang/Nim/issues/10731))
- Fixed "`foldr` raises IndexError when called on sequence"
([#14404](https://github.com/nim-lang/Nim/issues/14404))
- Fixed "moveFile does not overwrite destination file"
([#14057](https://github.com/nim-lang/Nim/issues/14057))
- Fixed "doc2 outputs in current work dir"
([#6583](https://github.com/nim-lang/Nim/issues/6583))
- Fixed "[docgen] proc doc comments silently omitted after 1st runnableExamples"
([#9227](https://github.com/nim-lang/Nim/issues/9227))
- Fixed "`nim doc --project` shows '@@/' instead of '../' for relative paths to submodules"
([#14448](https://github.com/nim-lang/Nim/issues/14448))
- Fixed "re, nre have wrong `start` semantics"
([#14284](https://github.com/nim-lang/Nim/issues/14284))
- Fixed "runnableExamples should preserve source code doc comments, strings, and (maybe) formatting"
([#8871](https://github.com/nim-lang/Nim/issues/8871))
- Fixed "`nim doc ..` fails when runnableExamples uses `$` [devel] [regression]"
([#14485](https://github.com/nim-lang/Nim/issues/14485))
- Fixed "`items` is 20%~30% slower than iteration via an index"
([#14421](https://github.com/nim-lang/Nim/issues/14421))
- Fixed "ARC: unreliable setLen "
([#14495](https://github.com/nim-lang/Nim/issues/14495))
- Fixed "lent is unsafe: after #14447 you can modify variables with "items" loop for sequences"
([#14498](https://github.com/nim-lang/Nim/issues/14498))
- Fixed "`var op = fn()` wrongly gives warning `ObservableStores` with `object of RootObj` type"
([#14514](https://github.com/nim-lang/Nim/issues/14514))
- Fixed "Compiler assertion"
([#14562](https://github.com/nim-lang/Nim/issues/14562))
- Fixed "Can't get `ord` of a value of a Range type in the JS backend "
([#14570](https://github.com/nim-lang/Nim/issues/14570))
- Fixed "js: can't take addr of param (including implicitly via `lent`)"
([#14576](https://github.com/nim-lang/Nim/issues/14576))
- Fixed "{.noinit.} ignored in for loop -> bad codegen for non-movable types"
([#14118](https://github.com/nim-lang/Nim/issues/14118))
- Fixed "generic destructor gives: `Error: unresolved generic parameter`"
([#14315](https://github.com/nim-lang/Nim/issues/14315))
- Fixed "Memory leak with arc gc"
([#14568](https://github.com/nim-lang/Nim/issues/14568))
- Fixed "escape analysis broken with `lent`"
([#14557](https://github.com/nim-lang/Nim/issues/14557))
- Fixed "`wrapWords` seems to ignore linebreaks when wrapping, leaving breaks in the wrong place"
([#14579](https://github.com/nim-lang/Nim/issues/14579))
- Fixed "`lent` gives wrong results with -d:release"
([#14578](https://github.com/nim-lang/Nim/issues/14578))
- Fixed "Nested await expressions regression: `await a(await expandValue())` doesnt compile"
([#14279](https://github.com/nim-lang/Nim/issues/14279))
- Fixed "windows CI docs fails with strange errors"
([#14545](https://github.com/nim-lang/Nim/issues/14545))
- Fixed "[CI] tests/async/tioselectors.nim flaky test for freebsd + OSX CI"
([#13166](https://github.com/nim-lang/Nim/issues/13166))
- Fixed "seq.setLen sometimes doesn't zero memory"
([#14655](https://github.com/nim-lang/Nim/issues/14655))
- Fixed "`nim dump` is roughly 100x slower in 1.3 versus 1.2"
([#14179](https://github.com/nim-lang/Nim/issues/14179))
- Fixed "Regression: devel docgen cannot generate document for method"
([#14691](https://github.com/nim-lang/Nim/issues/14691))
- Fixed "recently flaky tests/async/t7758.nim"
([#14685](https://github.com/nim-lang/Nim/issues/14685))
- Fixed "Bind no longer working in generic procs."
([#11811](https://github.com/nim-lang/Nim/issues/11811))
- Fixed "The pegs module doesn't work with generics!"
([#14718](https://github.com/nim-lang/Nim/issues/14718))
- Fixed "Defer is not properly working for asynchronous procedures."
([#13899](https://github.com/nim-lang/Nim/issues/13899))
- Fixed "Add an ARC test with threads in a loop"
([#14690](https://github.com/nim-lang/Nim/issues/14690))
- Fixed "[goto exceptions] {.noReturn.} pragma is not detected in a case expression"
([#14458](https://github.com/nim-lang/Nim/issues/14458))
- Fixed "[exceptions:goto] C compiler error with dynlib pragma calling a proc"
([#14240](https://github.com/nim-lang/Nim/issues/14240))
- Fixed "Cannot borrow var float64 in infix assignment"
([#14440](https://github.com/nim-lang/Nim/issues/14440))
- Fixed "lib/pure/memfiles.nim: compilation error with --taintMode:on"
([#14760](https://github.com/nim-lang/Nim/issues/14760))
- Fixed "newWideCString allocates a multiple of the memory needed"
([#14750](https://github.com/nim-lang/Nim/issues/14750))
- Fixed "Nim source archive install: 'install.sh' fails with error: cp: cannot stat 'bin/nim-gdb': No such file or directory"
([#14748](https://github.com/nim-lang/Nim/issues/14748))
- Fixed "`nim cpp -r tests/exception/t9657` hangs"
([#10343](https://github.com/nim-lang/Nim/issues/10343))
- Fixed "Detect tool fails on FreeBSD"
([#14715](https://github.com/nim-lang/Nim/issues/14715))
- Fixed "compiler crash: `findUnresolvedStatic` "
([#14802](https://github.com/nim-lang/Nim/issues/14802))
- Fixed "seq namespace (?) regression"
([#4796](https://github.com/nim-lang/Nim/issues/4796))
- Fixed "Possible out of bounds string access in std/colors parseColor and isColor"
([#14839](https://github.com/nim-lang/Nim/issues/14839))
- Fixed "compile error on latest devel with orc and ssl"
([#14647](https://github.com/nim-lang/Nim/issues/14647))
- Fixed "[minor] `$` wrong for type tuple"
([#13432](https://github.com/nim-lang/Nim/issues/13432))
- Fixed "Documentation missing on devel asyncftpclient"
([#14846](https://github.com/nim-lang/Nim/issues/14846))
- Fixed "nimpretty is confused with a trailing comma in enum definition"
([#14401](https://github.com/nim-lang/Nim/issues/14401))
- Fixed "Output arguments get ignored when compiling with --app:staticlib"
([#12745](https://github.com/nim-lang/Nim/issues/12745))
- Fixed "[ARC] destructive move destroys the object too early"
([#14396](https://github.com/nim-lang/Nim/issues/14396))
- Fixed "highlite.getNextToken() crashes if the buffer string is "echo "\"""
([#14830](https://github.com/nim-lang/Nim/issues/14830))
- Fixed "Memory corruption with --gc:arc with a seq of objects with an empty body."
([#14472](https://github.com/nim-lang/Nim/issues/14472))
- Fixed "Stropped identifiers don't work as field names in tuple literals"
([#14911](https://github.com/nim-lang/Nim/issues/14911))
- Fixed "Please revert my commit"
([#14930](https://github.com/nim-lang/Nim/issues/14930))
- Fixed "[ARC] C compiler error with inline iterators and imports"
([#14864](https://github.com/nim-lang/Nim/issues/14864))
- Fixed "AsyncHttpClient segfaults with gc:orc, possibly memory corruption"
([#14402](https://github.com/nim-lang/Nim/issues/14402))
- Fixed "[ARC] Template with a block evaluating to a GC'd value results in a compiler crash"
([#14899](https://github.com/nim-lang/Nim/issues/14899))
- Fixed "[ARC] Weird issue with if expressions and templates"
([#14900](https://github.com/nim-lang/Nim/issues/14900))
- Fixed "xmlparser does not compile on devel"
([#14805](https://github.com/nim-lang/Nim/issues/14805))
- Fixed "returning lent T from a var T param gives codegen errors or SIGSEGV"
([#14878](https://github.com/nim-lang/Nim/issues/14878))
- Fixed "[ARC] Weird issue with if expressions and templates"
([#14900](https://github.com/nim-lang/Nim/issues/14900))
- Fixed "threads:on + gc:orc + unittest = C compiler errors"
([#14865](https://github.com/nim-lang/Nim/issues/14865))
- Fixed "mitems, mpairs doesn't work at compile time anymore"
([#12129](https://github.com/nim-lang/Nim/issues/12129))
- Fixed "strange result from executing code in const expression"
([#10465](https://github.com/nim-lang/Nim/issues/10465))
- Fixed "Same warning printed 3 times"
([#11009](https://github.com/nim-lang/Nim/issues/11009))
- Fixed "type alias for generic typeclass doesn't work"
([#4668](https://github.com/nim-lang/Nim/issues/4668))
- Fixed "exceptions:goto Bug devel codegen lvalue NIM_FALSE=NIM_FALSE"
([#14925](https://github.com/nim-lang/Nim/issues/14925))
- Fixed "the --useVersion:1.0 no longer works in devel"
([#14912](https://github.com/nim-lang/Nim/issues/14912))
- Fixed "template declaration of iterator doesn't compile"
([#4722](https://github.com/nim-lang/Nim/issues/4722))
- Fixed "Compiler crash on type inheritance with static generic parameter and equality check"
([#12571](https://github.com/nim-lang/Nim/issues/12571))
- Fixed "Nim crashes while handling a cast in async circumstances."
([#13815](https://github.com/nim-lang/Nim/issues/13815))
- Fixed "[ARC] Internal compiler error when calling an iterator from an inline proc "
([#14383](https://github.com/nim-lang/Nim/issues/14383))
- Fixed ""Cannot instantiate" error when template uses generic type"
([#5926](https://github.com/nim-lang/Nim/issues/5926))
- Fixed "Different raises behaviour for newTerminal between Linux and Windows"
([#12759](https://github.com/nim-lang/Nim/issues/12759))
- Fixed "Expand on a type (that defines a proc type) in error message "
([#6608](https://github.com/nim-lang/Nim/issues/6608))
- Fixed "unittest require quits program with an exit code of 0"
([#14475](https://github.com/nim-lang/Nim/issues/14475))
- Fixed "Range type: Generics vs concrete type, semcheck difference."
([#8426](https://github.com/nim-lang/Nim/issues/8426))
- Fixed "[Macro] Type mismatch when parameter name is the same as a field"
([#13253](https://github.com/nim-lang/Nim/issues/13253))
- Fixed "Generic instantiation failure when converting a sequence of circular generic types to strings"
([#10396](https://github.com/nim-lang/Nim/issues/10396))
- Fixed "initOptParser ignores argument after value option with empty value."
([#13086](https://github.com/nim-lang/Nim/issues/13086))
- Fixed "[ARC] proc with both explicit and implicit return results in a C compiler error"
([#14985](https://github.com/nim-lang/Nim/issues/14985))
- Fixed "Alias type forgets implicit generic params depending on order"
([#14990](https://github.com/nim-lang/Nim/issues/14990))
- Fixed "[ARC] sequtils.insert has different behaviour between ARC/refc"
([#14994](https://github.com/nim-lang/Nim/issues/14994))
- Fixed "The documentation for "hot code reloading" references a non-existent npm package"
([#13621](https://github.com/nim-lang/Nim/issues/13621))
- Fixed "existsDir deprecated but breaking `dir` undeclared"
([#15006](https://github.com/nim-lang/Nim/issues/15006))
- Fixed "uri.decodeUrl crashes on incorrectly formatted input"
([#14082](https://github.com/nim-lang/Nim/issues/14082))
- Fixed "testament incorrectly reports time for tests, leading to wrong conclusions"
([#14822](https://github.com/nim-lang/Nim/issues/14822))
- Fixed "Calling peekChar with Stream returned from osproc.outputStream generate runtime error"
([#14906](https://github.com/nim-lang/Nim/issues/14906))
- Fixed "localPassC pragma should come *after* other flags"
([#14194](https://github.com/nim-lang/Nim/issues/14194))
- Fixed ""Could not load" dynamic library at runtime because of hidden dependency"
([#2408](https://github.com/nim-lang/Nim/issues/2408))
- Fixed "--gc:arc generate invalid code for {.global.} (`«nimErr_» in NIM_UNLIKELY`)"
([#14480](https://github.com/nim-lang/Nim/issues/14480))
- Fixed "Using `^` from stdlib/math along with converters gives a match for types that aren't SomeNumber"
([#15033](https://github.com/nim-lang/Nim/issues/15033))
- Fixed "[ARC] Weird exception behaviour from doAssertRaises"
([#15026](https://github.com/nim-lang/Nim/issues/15026))
- Fixed "[ARC] Compiler crash declaring a finalizer proc directly in 'new'"
([#15044](https://github.com/nim-lang/Nim/issues/15044))
- Fixed "[ARC] C compiler error when creating a var of a const seq"
([#15036](https://github.com/nim-lang/Nim/issues/15036))
- Fixed "code with named arguments in proc of winim/com can not been compiled"
([#15056](https://github.com/nim-lang/Nim/issues/15056))
- Fixed "javascript backend produces javascript code with syntax error in object syntax"
([#14534](https://github.com/nim-lang/Nim/issues/14534))
- Fixed "--gc:arc should be ignored in JS mode."
([#14684](https://github.com/nim-lang/Nim/issues/14684))
- Fixed "arc: C compilation error with imported global code using a closure iterator"
([#12990](https://github.com/nim-lang/Nim/issues/12990))
- Fixed "[ARC] Crash when modifying a string with mitems iterator"
([#15052](https://github.com/nim-lang/Nim/issues/15052))
- Fixed "[ARC] SIGSEGV when calling a closure as a tuple field in a seq"
([#15038](https://github.com/nim-lang/Nim/issues/15038))
- Fixed "pass varargs[seq[T]] to iterator give empty seq "
([#12576](https://github.com/nim-lang/Nim/issues/12576))
- Fixed "Compiler crashes when using string as object variant selector with else branch"
([#14189](https://github.com/nim-lang/Nim/issues/14189))
- Fixed "JS compiler error related to implicit return and return var type"
([#11354](https://github.com/nim-lang/Nim/issues/11354))
- Fixed "`nkRecWhen` causes internalAssert in semConstructFields"
([#14698](https://github.com/nim-lang/Nim/issues/14698))
- Fixed "Memory leaks with async (closure iterators?) under ORC"
([#15076](https://github.com/nim-lang/Nim/issues/15076))
- Fixed "strutil.insertSep() fails on negative numbers"
([#11352](https://github.com/nim-lang/Nim/issues/11352))
- Fixed "Constructing a uint64 range on a 32-bit machine leads to incorrect codegen"
([#14616](https://github.com/nim-lang/Nim/issues/14616))
- Fixed "heapqueue pushpop() proc doesn't compile"
([#14139](https://github.com/nim-lang/Nim/issues/14139))
- Fixed "[ARC] SIGSEGV when trying to swap in a literal/const string"
([#15112](https://github.com/nim-lang/Nim/issues/15112))
- Fixed "Defer and --gc:arc"
([#15071](https://github.com/nim-lang/Nim/issues/15071))
- Fixed "internal error: compiler/semobjconstr.nim(324, 20) example"
([#15111](https://github.com/nim-lang/Nim/issues/15111))
- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant"
([#15122](https://github.com/nim-lang/Nim/issues/15122))
- Fixed "[ARC] SIGSEGV with tuple assignment caused by cursor inference"
([#15130](https://github.com/nim-lang/Nim/issues/15130))
- Fixed "Issue with --gc:arc at compile time"
([#15129](https://github.com/nim-lang/Nim/issues/15129))
- Fixed "Writing an empty string to an AsyncFile raises an IndexDefect"
([#15148](https://github.com/nim-lang/Nim/issues/15148))
- Fixed "Compiler is confused about call convention of function with nested closure"
([#5688](https://github.com/nim-lang/Nim/issues/5688))
- Fixed "Nil check on each field fails in generic function"
([#15101](https://github.com/nim-lang/Nim/issues/15101))
- Fixed "{.nimcall.} convention won't avoid the creation of closures"
([#8473](https://github.com/nim-lang/Nim/issues/8473))
- Fixed "smtp.nim(161, 40) Error: type mismatch: got <typeof(nil)> but expected 'SslContext = void'"
([#15177](https://github.com/nim-lang/Nim/issues/15177))
- Fixed "[strscans] scanf doesn't match a single character with $+ if it's the end of the string"
([#15064](https://github.com/nim-lang/Nim/issues/15064))
- Fixed "Crash and incorrect return values when using readPasswordFromStdin on Windows."
([#15207](https://github.com/nim-lang/Nim/issues/15207))
- Fixed "Possible capture error with fieldPairs and genericParams"
([#15221](https://github.com/nim-lang/Nim/issues/15221))
- Fixed "The StmtList processing of template parameters can lead to unexpected errors"
([#5691](https://github.com/nim-lang/Nim/issues/5691))
- Fixed "[ARC] C compiler error when passing a var openArray to a sink openArray"
([#15035](https://github.com/nim-lang/Nim/issues/15035))
- Fixed "Inconsistent unsigned -> signed RangeDefect usage across integer sizes"
([#15210](https://github.com/nim-lang/Nim/issues/15210))
- Fixed "toHex results in RangeDefect exception when used with large uint64"
([#15257](https://github.com/nim-lang/Nim/issues/15257))
- Fixed "Arc sink arg crash"
([#15238](https://github.com/nim-lang/Nim/issues/15238))
- Fixed "SQL escape in db_mysql is not enough"
([#15219](https://github.com/nim-lang/Nim/issues/15219))
- Fixed "Mixing 'return' with expressions is allowed in 1.2"
([#15280](https://github.com/nim-lang/Nim/issues/15280))
- Fixed "os.getFileInfo() causes ICE with --gc:arc on Windows"
([#15286](https://github.com/nim-lang/Nim/issues/15286))
- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant"
([#15122](https://github.com/nim-lang/Nim/issues/15122))
- Fixed "Documentation regression jsre module missing"
([#15183](https://github.com/nim-lang/Nim/issues/15183))
- Fixed "CountTable.smallest/largest() on empty table either asserts or gives bogus answer"
([#15021](https://github.com/nim-lang/Nim/issues/15021))
- Fixed "[Regression] Parser regression"
([#15305](https://github.com/nim-lang/Nim/issues/15305))
- Fixed "[ARC] SIGSEGV with tuple unpacking caused by cursor inference"
([#15147](https://github.com/nim-lang/Nim/issues/15147))
- Fixed "LwIP/FreeRTOS compile error - missing SIGPIPE and more "
([#15302](https://github.com/nim-lang/Nim/issues/15302))
- Fixed "Memory leaks with async (closure iterators?) under ORC"
([#15076](https://github.com/nim-lang/Nim/issues/15076))
- Fixed "Bug compiling with --gc:arg or --gc:orc"
([#15325](https://github.com/nim-lang/Nim/issues/15325))
- Fixed "memory corruption in tmarshall.nim"
([#9754](https://github.com/nim-lang/Nim/issues/9754))
- Fixed "typed macros break generic proc definitions"
([#15326](https://github.com/nim-lang/Nim/issues/15326))
- Fixed "nim doc2 ignores --docSeeSrcUrl parameter"
([#6071](https://github.com/nim-lang/Nim/issues/6071))
- Fixed "The decodeData Iterator from cgi module crash"
([#15369](https://github.com/nim-lang/Nim/issues/15369))
- Fixed "|| iterator generates invalid code when compiling with --debugger:native"
([#9710](https://github.com/nim-lang/Nim/issues/9710))
- Fixed "Wrong number of variables"
([#15360](https://github.com/nim-lang/Nim/issues/15360))
- Fixed "Coercions with distinct types should traverse pointer modifiers transparently."
([#7165](https://github.com/nim-lang/Nim/issues/7165))
- Fixed "Error with distinct generic TableRef"
([#6060](https://github.com/nim-lang/Nim/issues/6060))
- Fixed "Support images in nim docgen"
([#6430](https://github.com/nim-lang/Nim/issues/6430))
- Fixed "Regression. Double sem check for procs."
([#15389](https://github.com/nim-lang/Nim/issues/15389))
- Fixed "uri.nim url with literal ipv6 address is printed wrong, and cannot parsed again"
([#15333](https://github.com/nim-lang/Nim/issues/15333))
- Fixed "[ARC] Object variant gets corrupted with cursor inference"
([#15361](https://github.com/nim-lang/Nim/issues/15361))
- Fixed "`nim doc ..` compiler crash (regression 0.19.6 => 1.0)"
([#14474](https://github.com/nim-lang/Nim/issues/14474))
- Fixed "cannot borrow result; what it borrows from is potentially mutated"
([#15403](https://github.com/nim-lang/Nim/issues/15403))
- Fixed "memory corruption for seq.add(seq) with gc:arc and d:useMalloc "
([#14983](https://github.com/nim-lang/Nim/issues/14983))
- Fixed "DocGen HTML output appears improperly when encountering text immediately after/before inline monospace; in some cases won't compile"
([#11537](https://github.com/nim-lang/Nim/issues/11537))
- Fixed "Deepcopy in arc crashes"
([#15405](https://github.com/nim-lang/Nim/issues/15405))
- Fixed "pop pragma takes invalid input"
([#15430](https://github.com/nim-lang/Nim/issues/15430))
- Fixed "tests/stdlib/tgetprotobyname fails on NetBSD"
([#15452](https://github.com/nim-lang/Nim/issues/15452))
- Fixed "defer doesnt work with block, break and await"
([#15243](https://github.com/nim-lang/Nim/issues/15243))
- Fixed "tests/stdlib/tssl failing on NetBSD"
([#15493](https://github.com/nim-lang/Nim/issues/15493))
- Fixed "strictFuncs doesn't seem to catch simple ref mutation"
([#15508](https://github.com/nim-lang/Nim/issues/15508))
- Fixed "Sizeof of case object is incorrect. Showstopper"
([#15516](https://github.com/nim-lang/Nim/issues/15516))
- Fixed "[ARC] Internal error when trying to use a parallel for loop"
([#15512](https://github.com/nim-lang/Nim/issues/15512))
- Fixed "[ARC] Type-bound assign op is not being generated"
([#15510](https://github.com/nim-lang/Nim/issues/15510))
- Fixed "[ARC] Crash when adding openArray proc argument to a local seq"
([#15511](https://github.com/nim-lang/Nim/issues/15511))
- Fixed "VM: const case object gets some fields zeroed out at runtime"
([#13081](https://github.com/nim-lang/Nim/issues/13081))
- Fixed "regression(1.2.6 => devel): VM: const case object field access gives: 'sons' is not accessible"
([#15532](https://github.com/nim-lang/Nim/issues/15532))
- Fixed "Csources: huge size increase (x2.3) in 0.20"
([#12027](https://github.com/nim-lang/Nim/issues/12027))
- Fixed "Out of date error message for GC options"
([#15547](https://github.com/nim-lang/Nim/issues/15547))
- Fixed "dbQuote additional escape regression"
([#15560](https://github.com/nim-lang/Nim/issues/15560))

View File

@@ -17,17 +17,21 @@ export int128
type
TCallingConvention* = enum
ccNimCall = "nimcall" # nimcall, also the default
ccStdCall = "stdcall" # procedure is stdcall
ccCDecl = "cdecl" # cdecl
ccSafeCall = "safecall" # safecall
ccSysCall = "syscall" # system call
ccInline = "inline" # proc should be inlined
ccNoInline = "noinline" # proc should not be inlined
ccFastCall = "fastcall" # fastcall (pass parameters in registers)
ccThisCall = "thiscall" # thiscall (parameters are pushed right-to-left)
ccClosure = "closure" # proc has a closure
ccNoConvention = "noconv" # needed for generating proper C procs sometimes
ccDefault, # proc has no explicit calling convention
ccStdCall, # procedure is stdcall
ccCDecl, # cdecl
ccSafeCall, # safecall
ccSysCall, # system call
ccInline, # proc should be inlined
ccNoInline, # proc should not be inlined
ccFastCall, # fastcall (pass parameters in registers)
ccClosure, # proc has a closure
ccNoConvention # needed for generating proper C procs sometimes
const
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
"closure", "noconv"]
type
TNodeKind* = enum # order is extremely important, because ranges are used
@@ -214,7 +218,7 @@ type
nkEnumFieldDef, # `ident = expr` in an enumeration
nkArgList, # argument list
nkPattern, # a special pattern; used for matching
nkHiddenTryStmt, # a hidden try statement
nkHiddenTryStmt, # token used for interpretation
nkClosure, # (prc, env)-pair (internally used for code gen)
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
@@ -225,7 +229,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 46 flags!
TSymFlag* = enum # 42 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -286,11 +290,9 @@ type
sfTemplateParam # symbol is a template parameter
sfCursor # variable/field is a cursor, see RFC 177 for details
sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation
sfNeverRaises # proc can never raise an exception, not even OverflowDefect
sfNeverRaises # proc can never raise an exception, not even OverflowError
# or out-of-memory
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
sfSingleUsedTemp # For temporaries that we know will only be used once
sfNoalias # 'noalias' annotation, means C's 'restrict'
TSymFlags* = set[TSymFlag]
@@ -309,6 +311,10 @@ const
# the compiler will avoid printing such names
# in user messages.
sfHoisted* = sfForward
# an expression was hoised to an anonymous variable.
# the flag is applied to the var/let symbol
sfNoForward* = sfRegister
# forward declarations are not required (per module)
sfReorder* = sfForward
@@ -427,9 +433,8 @@ type
# instantiation and prior to this it has the potential to
# be any type.
tyOptDeprecated
# 'out' parameter. Comparable to a 'var' parameter but every
# path must assign a value to it before it can be read from.
tyOpt
# Builtin optional type
tyVoid
# now different from tyEmpty, hurray!
@@ -549,10 +554,6 @@ type
# If it has one, t.destructor is not nil.
tfAcyclic # object type was annotated as .acyclic
tfIncompleteStruct # treat this type as if it had sizeof(pointer)
tfCompleteStruct
# (for importc types); type is fully specified, allowing to compute
# sizeof, alignof, offsetof at CT
tfExplicitCallConv
TTypeFlags* = set[TTypeFlag]
@@ -609,7 +610,7 @@ var
type
TMagic* = enum # symbols that require compiler magic:
mNone,
mDefined, mDeclared, mDeclaredInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait,
mIs, mOf, mAddr, mType, mTypeOf,
mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic,
@@ -652,8 +653,8 @@ type
mSwap, mIsNil, mArrToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy,
mDefault, mUnown, mIsolate, mAccessEnv, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mDefault, mUnown, mAccessEnv, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal,
mInt, mInt8, mInt16, mInt32, mInt64,
@@ -677,7 +678,7 @@ type
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
mInstantiationInfo, mGetTypeInfo,
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
mSymIsInstantiationOf, mNodeId
@@ -807,7 +808,7 @@ type
PInstantiation* = ref TInstantiation
TScope* {.acyclic.} = object
TScope* = object
depthLevel*: int
symbols*: TStrTable
parent*: PScope
@@ -871,7 +872,7 @@ type
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to save space)
when hasFFI:
cname*: string # resolved C declaration name in importc decl, e.g.:
cname*: string # resolved C declaration name in importc decl, eg:
# proc fun() {.importc: "$1aux".} => cname = funaux
constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl pragma in the hope
@@ -1026,7 +1027,6 @@ const
nkFloatLiterals* = {nkFloatLit..nkFloat128Lit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef}
procDefs* = nkLambdaKinds + declarativeDefs
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
@@ -1114,49 +1114,12 @@ proc newNode*(kind: TNodeKind): PNode =
writeStackTrace()
inc gNodeId
proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
result = PNode(kind: kind, info: info)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
result = PNode(kind: kind, info: info)
if children > 0:
newSeq(result.sons, children)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result = newNode(kind)
result.info = info
result.typ = typ
proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode =
result = newNode(kind)
if children.len > 0:
result.info = children[0].info
result.sons = @children
proc newTreeI*(kind: TNodeKind; info: TLineInfo; children: varargs[PNode]): PNode =
result = newNodeI(kind, info)
if children.len > 0:
result.info = children[0].info
result.sons = @children
proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[PNode]): PNode =
result = newNodeIT(kind, info, typ)
if children.len > 0:
result.info = children[0].info
result.sons = @children
template previouslyInferred*(t: PType): PType =
if t.sons.len > 1: t.lastSon else: nil
@@ -1257,6 +1220,43 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result.typ = sym.typ
result.info = info
proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
result = PNode(kind: kind, info: info)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
result = PNode(kind: kind, info: info)
if children > 0:
newSeq(result.sons, children)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
typ: PType = nil): PNode =
# XXX use shallowCopy here for ownership transfer:
result = PNode(kind: kind, info: info, typ: typ)
result.sons = sons
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result = newNode(kind)
result.info = info
result.typ = typ
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
@@ -1289,7 +1289,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
of tyUInt16: result = newNode(nkUInt16Lit)
of tyUInt32: result = newNode(nkUInt32Lit)
of tyUInt64: result = newNode(nkUInt64Lit)
of tyBool, tyEnum:
of tyBool,tyEnum:
# XXX: does this really need to be the kind nkIntLit?
result = newNode(nkIntLit)
of tyStatic: # that's a pre-existing bug, will fix in another PR
@@ -1353,9 +1353,9 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
writeStackTrace()
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
if a.storage == low(typeof(a.storage)): a.storage = b.storage
a.flags.incl b.flags
if a.k == low(a.k): a.k = b.k
if a.storage == low(a.storage): a.storage = b.storage
a.flags = a.flags + b.flags
if a.lode == nil: a.lode = b.lode
if a.r == nil: a.r = b.r
@@ -1380,7 +1380,7 @@ proc assignType*(dest, src: PType) =
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:
dest.sym.flags.incl src.sym.flags-{sfExported}
dest.sym.flags = dest.sym.flags + (src.sym.flags-{sfExported})
if dest.sym.annex == nil: dest.sym.annex = src.sym.annex
mergeLoc(dest.sym.loc, src.sym.loc)
else:
@@ -1399,6 +1399,9 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
proc exactReplica*(t: PType): PType = copyType(t, t.owner, true)
template requiresInit*(t: PType): bool =
t.flags * {tfRequiresInit, tfNotNil} != {}
proc copySym*(s: PSym): PSym =
result = newSym(s.kind, s.name, s.owner, s.info, s.options)
#result.ast = nil # BUGFIX; was: s.ast which made problems
@@ -1412,7 +1415,6 @@ proc copySym*(s: PSym): PSym =
result.position = s.position
result.loc = s.loc
result.annex = s.annex # BUGFIX
result.constraint = s.constraint
if result.kind in {skVar, skLet, skField}:
result.guard = s.guard
result.bitsize = s.bitsize
@@ -1485,7 +1487,8 @@ proc isGCedMem*(t: PType): bool {.inline.} =
t.kind == tyProc and t.callConv == ccClosure
proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) =
owner.flags.incl elem.flags * {tfHasMeta, tfTriggersCompileTime}
const HaveTheirOwnEmpty = {tySequence, tyOpt, tySet, tyPtr, tyRef, tyProc}
owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime})
if tfNotNil in elem.flags:
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
owner.flags.incl tfNotNil
@@ -1497,7 +1500,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) =
if mask != {} and propagateHasAsgn:
let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
if o2.kind in {tyTuple, tyObject, tyArray,
tySequence, tySet, tyDistinct, tyOpenArray, tyVarargs}:
tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}:
o2.flags.incl mask
owner.flags.incl mask
@@ -1747,7 +1750,7 @@ proc isRoutine*(s: PSym): bool {.inline.} =
proc isCompileTimeProc*(s: PSym): bool {.inline.} =
result = s.kind == skMacro or
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
s.kind == skProc and sfCompileTime in s.flags
proc isRunnableExamples*(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
@@ -1776,7 +1779,7 @@ proc isAtom*(n: PNode): bool {.inline.} =
result = n.kind >= nkNone and n.kind <= nkNilLit
proc isEmptyType*(t: PType): bool {.inline.} =
## 'void' and 'typed' types are often equivalent to 'nil' these days:
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
result = t == nil or t.kind in {tyVoid, tyTyped}
proc makeStmtList*(n: PNode): PNode =
@@ -1794,18 +1797,17 @@ proc skipStmtList*(n: PNode): PNode =
else:
result = n
proc toVar*(typ: PType; kind: TTypeKind): PType =
proc toVar*(typ: PType): PType =
## If ``typ`` is not a tyVar then it is converted into a `var <typ>` and
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.kind != kind:
result = newType(kind, typ.owner)
if typ.kind != tyVar:
result = newType(tyVar, typ.owner)
rawAddSon(result, typ)
proc toRef*(typ: PType): PType =
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
result = newType(tyRef, typ.owner)
rawAddSon(result, typ)
@@ -1832,14 +1834,8 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
proc skipColon*(n: PNode): PNode =
result = n
if n.kind == nkExprColonExpr:
result = n[1]
proc findUnresolvedStatic*(n: PNode): PNode =
# n.typ == nil: see issue #14802
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
return n
for son in n:
@@ -1856,10 +1852,6 @@ when false:
if n[i].containsNil: return true
template hasDestructor*(t: PType): bool = {tfHasAsgn, tfHasOwned} * t.flags != {}
proc hasDisabledAsgn*(t: PType): bool =
t.attachedOps[attachedAsgn] != nil and sfError in t.attachedOps[attachedAsgn].flags
template incompleteType*(t: PType): bool =
t.sym != nil and {sfForward, sfNoForward} * t.sym.flags == {sfForward}
@@ -1937,6 +1929,3 @@ proc toHumanStr*(kind: TSymKind): string =
proc toHumanStr*(kind: TTypeKind): string =
## strips leading `tk`
result = toHumanStrImpl(kind, 2)
proc skipAddr*(n: PNode): PNode {.inline.} =
(if n.kind == nkHiddenAddr: n[0] else: n)

View File

@@ -110,14 +110,14 @@ proc iiTablePut*(t: var TIITable, key, val: int)
# implementation
proc skipConvCastAndClosure*(n: PNode): PNode =
proc skipConvAndClosure*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
nkClosure:
result = result[0]
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = result[1]
else: break
@@ -345,7 +345,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
if card(n.flags) > 0:
result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)])
result.addf("$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
result.addf("$N$1\"size\": $2", [istr, rope(n.size)])
result.addf("$N$1\"align\": $2", [istr, rope(n.align)])
result.addf("$N$1\"sons\": $2", [istr, sonsRope])
@@ -591,17 +591,10 @@ proc value(this: var DebugPrinter; value: PNode) =
if this.conf != nil:
this.key "info"
this.value $lineInfoToStr(this.conf, value.info)
if value.flags != {}:
if card(value.flags) > 0:
this.key "flags"
this.value value.flags
if value.typ != nil:
this.key "typ"
this.value value.typ.kind
else:
this.key "typ"
this.value "nil"
case value.kind
of nkCharLit..nkUInt64Lit:
this.key "intVal"

View File

@@ -16,7 +16,7 @@ const
Mhalf = M div 2
type
Node[Key, Val] {.acyclic.} = ref object
Node[Key, Val] = ref object
entries: int
keys: array[M, Key]
case isInternal: bool
@@ -79,9 +79,6 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
var j = 0
if not h.isInternal:
while j < h.entries:
if eq(key, h.keys[j]):
h.vals[j] = val
return
if less(key, h.keys[j]): break
inc j
for i in countdown(h.entries, j+1):
@@ -135,7 +132,8 @@ proc `$`[Key, Val](b: BTree[Key, Val]): string =
result = ""
toString(b.root, "", result)
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = index < b.entries
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool =
result = index < b.entries
proc countSubTree[Key, Val](it: Node[Key, Val]): int =
if it.isInternal:
@@ -168,3 +166,68 @@ iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) =
yield (k, v)
proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries
when isMainModule:
import random, tables
proc main =
var st = initBTree[string, string]()
st.add("www.cs.princeton.edu", "abc")
st.add("www.princeton.edu", "128.112.128.15")
st.add("www.yale.edu", "130.132.143.21")
st.add("www.simpsons.com", "209.052.165.60")
st.add("www.apple.com", "17.112.152.32")
st.add("www.amazon.com", "207.171.182.16")
st.add("www.ebay.com", "66.135.192.87")
st.add("www.cnn.com", "64.236.16.20")
st.add("www.google.com", "216.239.41.99")
st.add("www.nytimes.com", "199.239.136.200")
st.add("www.microsoft.com", "207.126.99.140")
st.add("www.dell.com", "143.166.224.230")
st.add("www.slashdot.org", "66.35.250.151")
st.add("www.espn.com", "199.181.135.201")
st.add("www.weather.com", "63.111.66.11")
st.add("www.yahoo.com", "216.109.118.65")
assert st.getOrDefault("www.cs.princeton.edu") == "abc"
assert st.getOrDefault("www.harvardsucks.com") == ""
assert st.getOrDefault("www.simpsons.com") == "209.052.165.60"
assert st.getOrDefault("www.apple.com") == "17.112.152.32"
assert st.getOrDefault("www.ebay.com") == "66.135.192.87"
assert st.getOrDefault("www.dell.com") == "143.166.224.230"
assert(st.entries == 16)
for k, v in st:
echo k, ": ", v
when false:
var b2 = initBTree[string, string]()
const iters = 10_000
for i in 1..iters:
b2.add($i, $(iters - i))
for i in 1..iters:
let x = b2.getOrDefault($i)
if x != $(iters - i):
echo "got ", x, ", but expected ", iters - i
echo b2.entries
when true:
var b2 = initBTree[int, string]()
var t2 = initTable[int, string]()
const iters = 100_000
for i in 1..iters:
let x = rand(high(int))
if not t2.hasKey(x):
doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x
t2[x] = $x
b2.add(x, $x)
doAssert b2.entries == t2.len
echo "unique entries ", b2.entries
for k, v in t2:
doAssert $k == v
doAssert b2.getOrDefault(k) == $k
main()

View File

@@ -141,61 +141,9 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
proc reifiedOpenArray(n: PNode): bool {.inline.} =
var x = n
while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}:
x = x[0]
if x.kind == nkSym and x.sym.kind == skParam:
result = false
else:
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) =
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, destType)
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 = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
result = ("($4*)($1)+(($2)-($3))" %
[rdLoc(a), rdLoc(b), intLiteral(first), dest],
lengthExpr)
of tyOpenArray, tyVarargs:
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 = ("($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:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
result = ("($4*)(*$1)$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
lengthExpr)
else:
result = ("($4*)$1$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
lengthExpr)
else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
var a: TLoc
var q = skipConv(n)
var skipped = false
while q.kind == nkStmtListExpr and q.len > 0:
@@ -209,26 +157,47 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
for i in 0..<q.len-1:
genStmts(p, q[i])
q = q.lastSon
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result = x & ", " & y
else:
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:
result = "$1->Field0, $1->Field1" % [rdLoc(a)]
else:
result = "$1.Field0, $1.Field1" % [rdLoc(a)]
var b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, n.typ[0])
case ty.kind
of tyArray:
let first = toInt64(firstOrd(p.config, ty))
if first == 0:
result = "($4*)(($1)+($2)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
else:
result = "$1, $1Len_0" % [rdLoc(a)]
result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" %
[rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest]
of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString:
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
of tyString, tySequence:
let ntyp = skipTypes(n.typ, abstractInst)
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
let atyp = skipTypes(a.t, abstractInst)
if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and
optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
if atyp.kind == tyVar and not compileToCpp(p.module):
result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
else:
result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else:
initLocExpr(p, n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
result = "$1, $1Len_0" % [rdLoc(a)]
of tyString, tySequence:
let ntyp = skipTypes(n.typ, abstractInst)
if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and
optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if ntyp.kind == tyVar and not compileToCpp(p.module):
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
@@ -248,33 +217,22 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
# Aliasing is preferred over stack overflows.
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
else:
result = a
proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} =
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
var a: TLoc
initLocExpr(p, n[0], a)
ropecg(p.module, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rope =
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n, needsTmp)
result = genArgStringToCString(p, n)
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
result = openArrayLoc(p, param.typ, n)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
initLocExpr(p, n, a)
result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp))
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
result = addrLoc(p.config, a)
elif p.module.compileToCpp and param.typ.kind == tyVar and
n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a)
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
@@ -288,85 +246,26 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rop
result = rdLoc(a)
else:
initLocExprSingleUse(p, n, a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp))
result = rdLoc(a)
proc genArgNoParam(p: BProc, n: PNode, needsTmp = false): Rope =
proc genArgNoParam(p: BProc, n: PNode): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n, needsTmp)
result = genArgStringToCString(p, n)
else:
initLocExprSingleUse(p, n, a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp))
result = rdLoc(a)
from dfa import instrTargets, InstrTargetKind
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
for p in potentialWrites:
if instrTargets(p, n) != None:
return true
proc skipTrivialIndirections(n: PNode): PNode =
result = n
while true:
case result.kind
of {nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv}:
result = result[0]
of {nkHiddenStdConv, nkHiddenSubConv}:
result = result[1]
else: break
proc getPotentialWrites(n: PNode, mutate = false): seq[PNode] =
case n.kind:
of nkLiterals, nkIdent: discard
of nkSym:
if mutate: result.add n
of nkAsgn, nkFastAsgn:
result.add getPotentialWrites(n[0], true)
result.add getPotentialWrites(n[1], mutate)
of nkAddr, nkHiddenAddr:
result.add getPotentialWrites(n[0], true)
of nkCallKinds: #TODO: Find out why in f += 1, f is a nkSym and not a nkHiddenAddr
for s in n.sons:
result.add getPotentialWrites(s, true)
template genParamLoop(params) {.dirty.} =
if i < typ.len:
assert(typ.n[i].kind == nkSym)
let paramType = typ.n[i]
if not paramType.typ.isCompileTimeOnly:
if params != nil: params.add(~", ")
params.add(genArg(p, ri[i], paramType.sym, ri))
else:
for s in n.sons:
result.add getPotentialWrites(s, mutate)
proc getPotentialReads(n: PNode): seq[PNode] =
case n.kind:
of nkLiterals, nkIdent: discard
of nkSym: result.add n
else:
for s in n.sons:
result.add getPotentialReads(s)
proc genParams(p: BProc, ri: PNode, typ: PType): Rope =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
var potentialWrites: seq[PNode]
for i in countdown(ri.len - 1, 1):
if ri[i].skipTrivialIndirections.kind == nkSym:
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
else:
for n in getPotentialReads(ri[i]):
if not needTmp[i - 1]:
needTmp[i - 1] = potentialAlias(n, potentialWrites)
potentialWrites.add getPotentialWrites(ri[i])
if ri[i].kind == nkHiddenAddr:
# Optimization: don't use a temp, if we would only take the adress anyway
needTmp[i - 1] = false
for i in 1..<ri.len:
if i < typ.len:
assert(typ.n[i].kind == nkSym)
let paramType = typ.n[i]
if not paramType.typ.isCompileTimeOnly:
if result != nil: result.add(~", ")
result.add(genArg(p, ri[i], paramType.sym, ri, needTmp[i-1]))
else:
if result != nil: result.add(~", ")
result.add(genArgNoParam(p, ri[i], needTmp[i-1]))
if params != nil: params.add(~", ")
params.add(genArgNoParam(p, ri[i]))
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
@@ -377,13 +276,13 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
initLocExpr(p, ri[0], op)
var params: Rope
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
var params = genParams(p, ri, typ)
for i in 1..<ri.len:
genParamLoop(params)
var callee = rdLoc(op)
if p.hcrOn and ri[0].kind == nkSym:
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
@@ -391,21 +290,23 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc getRawProcType(p: BProc, t: PType): Rope =
result = getClosureType(p.module, t, clHalf)
proc addComma(r: Rope): Rope =
if r == nil: r else: r & ~", "
result = if r == nil: r else: r & ~", "
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: TLoc
initLocExpr(p, ri[0], op)
var pl: Rope
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
var pl = genParams(p, ri, typ)
for i in 1..<ri.len:
assert(typ.len == typ.n.len)
genParamLoop(pl)
template genCallPattern {.dirty.} =
if tfIterator in typ.flags:
@@ -413,7 +314,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
else:
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
let rawProc = getClosureType(p.module, typ, clHalf)
let rawProc = getRawProcType(p, typ)
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
if typ[0] != nil:
if isInvalidReturnType(p.config, typ[0]):
@@ -471,7 +372,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
assert(paramType.kind == nkSym)
if paramType.typ.isCompileTimeOnly:
result = nil
elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr:
elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr:
result = genArgNoParam(p, ri[i][0])
else:
result = genArgNoParam(p, ri[i]) #, typ.n[i].sym)
@@ -548,7 +449,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
var ri = ri[i]
while ri.kind == nkObjDownConv: ri = ri[0]
let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink})
if t.kind in {tyVar}:
if t.kind == tyVar:
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.typ.kind == tyPtr:
result = genArgNoParam(p, x)
@@ -743,33 +644,18 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
pl.add(~"];$n")
line(p, cpsStmts, pl)
proc notYetAlive(n: PNode): bool {.inline.} =
let r = getRoot(n)
result = r != nil and r.loc.lode == nil
proc isInactiveDestructorCall(p: BProc, e: PNode): bool =
#[ Consider this example.
var :tmpD_3281815
try:
if true:
return
let args_3280013 =
wasMoved_3281816(:tmpD_3281815)
`=_3280036`(:tmpD_3281815, [1])
:tmpD_3281815
finally:
`=destroy_3280027`(args_3280013)
We want to return early but the 'finally' section is traversed before
the 'let args = ...' statement. We exploit this to generate better
code for 'return'. ]#
result = e.len == 2 and e[0].kind == nkSym and
e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr)
proc genCall(p: BProc, e: PNode, d: var TLoc) =
if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
genClosureCall(p, nil, e, d)
elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags:
genInfixCall(p, nil, e, d)
elif e[0].kind == nkSym and sfNamedParamCall in e[0].sym.flags:
genNamedParamCall(p, e, d)
else:
genPrefixCall(p, nil, e, d)
postStmtActions(p)
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
return
if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
genClosureCall(p, le, ri, d)
elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags:
@@ -779,5 +665,3 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
else:
genPrefixCall(p, le, ri, d)
postStmtActions(p)
proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d)

View File

@@ -71,10 +71,8 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
p.module.s[cfsData].addf(
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, ty), result])
elif k in {tyPointer, tyNil, tyProc}:
result = rope("NIM_NIL")
else:
result = "(($1) NIM_NIL)" % [getTypeDesc(p.module, ty)]
result = rope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
let k = if ty == nil: tyString
else: skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind
@@ -128,8 +126,9 @@ proc genRawSetData(cs: TBitSet, size: int): Rope =
result = intLiteral(cast[BiggestInt](bitSetToWord(cs, size)))
proc genSetNode(p: BProc, n: PNode): Rope =
var cs: TBitSet
var size = int(getSize(p.config, n.typ))
let cs = toBitSet(p.config, n)
toBitSet(p.config, n, cs)
if size > 8:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
@@ -142,7 +141,6 @@ proc genSetNode(p: BProc, n: PNode): Rope =
result = genRawSetData(cs, size)
proc getStorageLoc(n: PNode): TStorageLoc =
## deadcode
case n.kind
of nkSym:
case n.sym.kind
@@ -268,38 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
[addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)])
else:
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
else:
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
assert d.k != locNone
# getTemp(p, d.t, d)
case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
of tySequence:
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
of tyArray:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n",
[rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))])
of tyString:
let etyp = skipTypes(a.t, abstractInst)
if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
else:
internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind)
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating
@@ -320,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
genTypeInfo(p.module, dest.t, dest.lode.info)])
of tyString:
if optSeqDestructors in p.config.globalOptions:
genGenericAsgn(p, dest, src, flags)
@@ -379,13 +349,11 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyOpenArray, tyVarargs:
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src)
elif containsGarbageCollectedRef(dest.t):
if containsGarbageCollectedRef(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
genTypeInfo(p.module, dest.t, dest.lode.info)])
else:
linefmt(p, cpsStmts,
# bug #4799, keep the nimCopyMem for a while
@@ -393,7 +361,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
"$1 = $2;$n",
[rdLoc(dest), rdLoc(src)])
of tySet:
if mapSetType(p.config, ty) == ctArray:
if mapType(p.config, ty) == ctArray:
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
else:
@@ -427,23 +395,18 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
# XXX optimize this
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
genTypeInfo(p.module, dest.t, dest.lode.info)])
of tySequence, tyString:
if optTinyRtti in p.config.globalOptions:
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
else:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)])
of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
genTypeInfo(p.module, dest.t, dest.lode.info)])
of tySet:
if mapSetType(p.config, ty) == ctArray:
if mapType(p.config, ty) == ctArray:
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
else:
@@ -712,11 +675,11 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
result = p.module.compileToCpp and
skipTypes(typ, abstractInstOwned).kind in {tyVar} and
skipTypes(typ, abstractInstOwned).kind == tyVar and
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
let mt = mapType(p.config, e[0].typ)
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
@@ -729,7 +692,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
typ = typ.lastSon
typ = typ.skipTypes(abstractInstOwned)
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
initLocExprSingleUse(p, e[0][0], d)
return
else:
@@ -752,7 +715,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
else:
internalError(p.config, e.info, "genDeref " & $typ.kind)
elif p.module.compileToCpp:
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
e.kind == nkHiddenDeref:
putIntoDest(p, d, e, rdLoc(a), a.storage)
return
@@ -762,21 +725,10 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
# See tmissingderef. So we get rid of the deref instead. The codegen
# ends up using 'memcpy' for the array assignment,
# so the '&' and '*' cancel out:
putIntoDest(p, d, e, rdLoc(a), a.storage)
putIntoDest(p, d, lodeTyp(a.t[0]), rdLoc(a), a.storage)
else:
putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage)
proc cowBracket(p: BProc; n: PNode) =
if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions:
let strCandidate = n[0]
if strCandidate.typ.skipTypes(abstractInst).kind == tyString:
var a: TLoc
initLocExpr(p, strCandidate, a)
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
proc cow(p: BProc; n: PNode) {.inline.} =
if n.kind == nkHiddenAddr: cowBracket(p, n[0])
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
@@ -784,7 +736,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e[0], a)
putIntoDest(p, d, e, "&" & a.r, a.storage)
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ):
elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ):
expr(p, e[0], d)
else:
var a: TLoc
@@ -869,7 +821,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
v.r.add(".")
v.r.add(disc.sym.loc.r)
genInExprAux(p, it, u, v, test)
let msg = genFieldDefect(field, disc.sym)
let msg = genFieldError(field, disc.sym)
let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg))
if op.magic == mNot:
linefmt(p, cpsStmts,
@@ -943,16 +895,10 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
case ty.kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(arr.lode):
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n",
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
else:
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
of tyArray:
let first = intLiteral(firstOrd(p.config, ty))
linefmt(p, cpsStmts,
@@ -969,22 +915,13 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
if not reifiedOpenArray(x):
# emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
inheritLocation(d, a)
putIntoDest(p, d, n,
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
else:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.Field1)){ #raiseIndexError2($1,$2.Field1-1); $3}$n",
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
inheritLocation(d, a)
putIntoDest(p, d, n,
ropecg(p.module, "$1.Field0[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
initLocExpr(p, y, b) # emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
inheritLocation(d, a)
putIntoDest(p, d, n,
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
@@ -994,7 +931,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
if optBoundsCheck in p.options:
if ty.kind == tyString and not defined(nimNoZeroTerminator):
if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
linefmt(p, cpsStmts,
"if ((NU)($1) > (NU)$2){ #raiseIndexError2($1,$2); $3}$n",
[rdLoc(b), lenExpr(p, a), raiseInstr(p)])
@@ -1237,12 +1174,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)"
call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
getTypeDesc(p.module, e[1].typ),
genTypeInfoV1(p.module, seqType, e.info)])
genTypeInfo(p.module, seqType, e.info)])
else:
const seqAppendPattern = "($2) #incrSeqV3($1, $3)"
call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
getTypeDesc(p.module, e[1].typ),
genTypeInfoV1(p.module, seqType, e.info)])
genTypeInfo(p.module, seqType, e.info)])
# emit the write barrier if required, but we can always move here, so
# use 'genRefAssign' for the seq.
genRefAssign(p, a, call)
@@ -1262,7 +1199,7 @@ proc genReset(p: BProc, n: PNode) =
when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)])
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
proc genDefault(p: BProc; n: PNode; d: var TLoc) =
if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
@@ -1281,19 +1218,19 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
if optTinyRtti in p.config.globalOptions:
if needsInit:
b.r = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))",
[getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)])
b.r = ropecg(p.module, "($1) #nimNewObj($2)",
[getTypeDesc(p.module, typ), sizeExpr])
else:
b.r = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))",
[getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)])
b.r = ropecg(p.module, "($1) #nimNewObjUninit($2)",
[getTypeDesc(p.module, typ), sizeExpr])
genAssignment(p, a, b, {})
else:
let ti = genTypeInfoV1(p.module, typ, a.lode.info)
let ti = genTypeInfo(p.module, typ, a.lode.info)
if bt.destructor != nil and not isTrivialProc(bt.destructor):
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
# convention at least:
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccNimCall:
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault:
localError(p.module.config, a.lode.info,
"the destructor that is turned into a finalizer needs " &
"to have the 'nimcall' calling convention")
@@ -1347,18 +1284,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
if p.config.selectedGC == gcGo:
# we need the write barrier
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
genTypeInfo(p.module, seqtype, dest.lode.info), length])
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc])
else:
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
genTypeInfo(p.module, seqtype, dest.lode.info), length])
linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc])
else:
if lenIsZero:
call.r = rope"NIM_NIL"
else:
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
genTypeInfo(p.module, seqtype, dest.lode.info), length])
genAssignment(p, dest, call, {})
proc genNewSeq(p: BProc, e: PNode) =
@@ -1367,10 +1304,9 @@ proc genNewSeq(p: BProc, e: PNode) =
initLocExpr(p, e[2], b)
if optSeqDestructors in p.config.globalOptions:
let seqtype = skipTypes(e[1].typ, abstractVarRange)
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[a.rdLoc, b.rdLoc,
getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
[a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
let lenIsZero = optNilSeqs notin p.options and
e[2].kind == nkIntLit and e[2].intVal == 0
@@ -1383,15 +1319,14 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
initLocExpr(p, e[1], a)
if optSeqDestructors in p.config.globalOptions:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype),
])
getSeqPayloadType(p.module, seqtype)])
else:
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc]))
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
gcUsage(p.config, e)
proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
@@ -1403,7 +1338,7 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
# expression not found in the cache:
inc(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true, t)])
[getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)])
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@@ -1413,7 +1348,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
result = false
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
#echo renderTree e, " ", e.isDeepConstExpr
#echo rendertree e, " ", e.isDeepConstExpr
# inheritance in C++ does not allow struct initialization so
# we skip this step here:
if not p.module.compileToCpp and optSeqDestructors notin p.config.globalOptions:
@@ -1493,7 +1428,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
let l = intLiteral(n.len)
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
[rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
@@ -1524,7 +1459,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
let L = toInt(lengthOrd(p.config, n[1].typ))
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
[rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
@@ -1561,10 +1496,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
initLocExpr(p, e[1], a)
initLocExpr(p, e[2], f)
initLoc(b, locExpr, a.lode, OnHeap)
if optTinyRtti in p.config.globalOptions:
ti = genTypeInfoV2(p.module, refType, e.info)
else:
ti = genTypeInfoV1(p.module, refType, e.info)
ti = genTypeInfo(p.module, refType, e.info)
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
@@ -1579,9 +1511,9 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
result = ropecg(p.module, "#isObj($1.m_type, $2)",
[a, genTypeInfo2Name(p.module, dest)])
else:
# unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first:
let ti = genTypeInfoV1(p.module, dest, info)
let ti = genTypeInfo(p.module, dest, info)
if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
tfObjHasKids notin dest.flags):
result = "$1.m_type == $2" % [a, ti]
@@ -1594,7 +1526,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
when false:
# former version:
result = ropecg(p.module, "#isObj($1.m_type, $2)",
[a, genTypeInfoV1(p.module, dest, info)])
[a, genTypeInfo(p.module, dest, info)])
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc
@@ -1644,12 +1576,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyEnum, tyOrdinal:
putIntoDest(p, d, e,
ropecg(p.module, "#reprEnum((NI)$1, $2)", [
rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyString:
putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
of tySet:
putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs:
var b: TLoc
case skipTypes(a.t, abstractVarRange).kind
@@ -1664,20 +1596,20 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
else: internalError(p.config, e[0].info, "genRepr()")
putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage)
genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence:
putIntoDest(p, d, e,
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyEmpty, tyVoid:
localError(p.config, e.info, "'repr' doesn't support 'void' type")
else:
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]),
[addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]),
a.storage)
gcUsage(p.config, e)
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope =
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
result = rdLoc(a)
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
@@ -1691,20 +1623,13 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope =
result.add(".Sup")
t = skipTypes(t[0], skipPtrs)
result.add ".m_type"
if optTinyRtti in p.config.globalOptions and enforceV1:
result.add "->typeInfoV1"
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
discard cgsym(p.module, "TNimType")
let t = e[1].typ
# ordinary static type information
putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info))
proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
let t = e[1].typ
if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo":
# ordinary static type information
putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info))
putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
else:
var a: TLoc
initLocExpr(p, e[1], a)
@@ -1716,7 +1641,7 @@ template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
initLocExpr(p, n[1], a)
a.r = ropecg(p.module, frmt, [rdLoc(a)])
a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR)
a.flags = a.flags - {lfIndirect} # this flag should not be propagated here (not just for HCR)
if d.k == locNone: getTemp(p, n.typ, d)
genAssignment(p, d, a, {})
gcUsage(p.config, n)
@@ -1738,12 +1663,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
else:
if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)")
else: unaryExpr(p, e, d, "$1.Field1")
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
of tyCString:
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
@@ -1797,13 +1718,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
call.r = ropecg(p.module, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
else:
const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)"
call.r = ropecg(p.module, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
genAssignment(p, a, call, {})
gcUsage(p.config, e)
@@ -1828,8 +1749,6 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
# temp = a
# a = b
# b = temp
cowBracket(p, e[1])
cowBracket(p, e[2])
var a, b, tmp: TLoc
getTemp(p, skipTypes(e[1].typ, abstractVar), tmp)
initLocExpr(p, e[1], a) # eval a
@@ -2063,30 +1982,25 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
checkUnsignedConversions notin p.config.legacyFeatures):
discard "no need to generate a check because it was disabled"
else:
let raiser =
case skipTypes(n.typ, abstractVarRange).kind
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
discard cgsym(p.module, raiser)
# This seems to be bug-compatible with Nim version 1 but what we
# should really do here is to check if uint64Value < high(int)
let n0t = n[0].typ
let boundaryCast =
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
"(NI64)"
else:
""
# emit range check:
if n0t.kind in {tyUInt, tyUInt64}:
linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), getTypeDesc(p.module, n0t)])
else:
let raiser =
case skipTypes(n.typ, abstractVarRange).kind
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
discard cgsym(p.module, raiser)
let boundaryCast =
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
"(NI64)"
else:
""
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), boundaryCast])
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), boundaryCast])
putIntoDest(p, d, n, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
@@ -2151,14 +2065,10 @@ proc skipAddr(n: PNode): PNode =
proc genWasMoved(p: BProc; n: PNode) =
var a: TLoc
let n1 = n[1].skipAddr
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
discard
else:
initLocExpr(p, n1, a)
resetLoc(p, a)
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
initLocExpr(p, n[1].skipAddr, a)
resetLoc(p, a)
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
proc genMove(p: BProc; n: PNode; d: var TLoc) =
var a: TLoc
@@ -2167,7 +2077,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
# generated by liftdestructors:
var src: TLoc
initLocExpr(p, n[2], src)
linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)])
linefmt(p, cpsStmts, "if ($1.len && $1.p != $2.p) {", [rdLoc(a), rdLoc(src)])
genStmts(p, n[3])
linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
else:
@@ -2183,20 +2093,16 @@ proc genDestroy(p: BProc; n: PNode) =
of tyString:
var a: TLoc
initLocExpr(p, arg, a)
if optThreads in p.config.globalOptions:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #deallocShared($1.p);$n" &
"}$n", [rdLoc(a)])
else:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #dealloc($1.p);$n" &
"}$n", [rdLoc(a)])
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #deallocShared($1.p);$n" &
" $1.p = NIM_NIL; $1.len = 0; }$n",
[rdLoc(a)])
of tySequence:
var a: TLoc
initLocExpr(p, arg, a)
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" &
"}$n",
" #deallocShared($1.p);$n" &
" $1.p = NIM_NIL; $1.len = 0; }$n",
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
else: discard "nothing to do"
else:
@@ -2216,20 +2122,12 @@ proc genDispose(p: BProc; n: PNode) =
if elemType.destructor != nil:
var destroyCall = newNodeI(nkCall, n.info)
genStmts(p, destroyCall)
lineFmt(p, cpsStmts, "#nimRawDispose($1, NIM_ALIGNOF($2))", [rdLoc(a), getTypeDesc(p.module, elemType)])
lineCg(p, cpsStmts, ["#nimRawDispose($#)", rdLoc(a)])
else:
# ``nimRawDisposeVirtual`` calls the ``finalizer`` which is the same as the
# destructor, but it uses the runtime type. Afterwards the memory is freed:
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon)
if d.k == locNone: getTemp(p, e.typ, d)
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
when false:
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
"'toOpenArray' is only valid within a call expression")
proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
const ToStringProcSlot = -4
let t = e[1].typ.skipTypes(abstractInst+{tyRange})
@@ -2256,7 +2154,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAddI..mPred: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d)
of mSwap: genSwap(p, e, d)
of mInc, mDec:
const opr: array[mInc..mDec, string] = ["+=", "-="]
@@ -2308,7 +2205,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate: genCall(p, e, d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
@@ -2324,29 +2220,27 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
gcUsage(p.config, e)
else:
genNewFinalize(p, e)
of mNewSeq:
if optSeqDestructors in p.config.globalOptions:
e[1] = makeAddr(e[1])
genCall(p, e, d)
else:
genNewSeq(p, e)
of mNewSeq: genNewSeq(p, e)
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
of mSizeOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)])
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
of mAlignOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)])
if not p.module.compileToCpp:
p.module.includeHeader("<stdalign.h>")
putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
of mOffsetOf:
var dotExpr: PNode
if e[1].kind == nkDotExpr:
dotExpr = e[1]
elif e[1].kind == nkCheckedFieldExpr:
dotExpr = e[1][0]
else:
internalError(p.config, e.info, "unknown ast")
block findDotExpr:
if e[1].kind == nkDotExpr:
dotExpr = e[1]
elif e[1].kind == nkCheckedFieldExpr:
dotExpr = e[1][0]
else:
internalError(p.config, e.info, "unknown ast")
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
let tname = getTypeDesc(p.module, t, skVar)
let tname = getTypeDesc(p.module, t)
let member =
if t.kind == tyTuple:
"Field" & rope(dotExpr[1].sym.position)
@@ -2407,10 +2301,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
expr(p, n, d)
of mDeepCopy:
if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
localError(p.config, e.info,
"for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
var a, b: TLoc
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
initLocExpr(p, x, a)
@@ -2421,7 +2311,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mMove: genMove(p, e, d)
of mDestroy: genDestroy(p, e)
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
of mSlice: genSlice(p, e, d)
of mSlice:
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
"'toOpenArray' is only valid within a call expression")
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
@@ -2498,7 +2390,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
inc(p.module.labels)
var tmp = "CNSTCLOSURE" & rope(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true, n.typ)])
[getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true)])
putIntoDest(p, d, n, tmp, OnStatic)
else:
var tmp, a, b: TLoc
@@ -2561,8 +2453,6 @@ proc genStmtList(p: BProc, n: PNode) =
genStmtListExprImpl:
genStmts(p, n[^1])
from parampatterns import isLValue
proc upConv(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n[0], a)
@@ -2573,7 +2463,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, dest)
else:
genTypeInfoV1(p.module, dest, n.info)
genTypeInfo(p.module, dest, n.info)
if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n",
[nilCheck, r, checkFor, raiseInstr(p)])
@@ -2581,11 +2471,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); $3}$n",
[r, checkFor, raiseInstr(p)])
if n[0].typ.kind != tyObject:
if n.isLValue:
putIntoDest(p, d, n,
"(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else:
putIntoDest(p, d, n,
putIntoDest(p, d, n,
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else:
putIntoDest(p, d, n, "(*($1*) ($2))" %
@@ -2637,7 +2523,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
# expression not found in the cache:
inc(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t, skConst), tmp, genBracedInit(p, n, isConst = true, t)])
[getTypeDesc(p.module, t), tmp, genBracedInit(p, n, isConst = true)])
if d.k == locNone:
fillLoc(d, locData, n, tmp, OnStatic)
@@ -2702,12 +2588,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else:
putLocIntoDest(p, d, sym.loc)
of skTemp:
when false:
# this is more harmful than helpful.
if sym.loc.r == nil:
# we now support undeclared 'skTemp' variables for easier
# transformations in other parts of the compiler:
assignLocalVar(p, n)
if sym.loc.r == nil:
# we now support undeclared 'skTemp' variables for easier
# transformations in other parts of the compiler:
assignLocalVar(p, n)
if sym.loc.r == nil or sym.loc.t == nil:
#echo "FAILED FOR PRCO ", p.prc.name.s
#echo renderTree(p.prc.ast, {renderIds})
@@ -2782,7 +2666,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
expr(p, n[1][0], d)
of nkObjDownConv: downConv(p, n, d)
of nkObjUpConv: upConv(p, n, d)
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
of nkChckRangeF: genRangeChck(p, n, d)
of nkChckRange64: genRangeChck(p, n, d)
of nkChckRange: genRangeChck(p, n, d)
of nkStringToCString: convStrToCStr(p, n, d)
of nkCStringToString: convCStrToStr(p, n, d)
of nkLambdaKinds:
@@ -2802,11 +2688,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkReturnStmt: genReturnStmt(p, n)
of nkBreakStmt: genBreakStmt(p, n)
of nkAsgn:
cow(p, n[1])
if nfPreventCg notin n.flags:
genAsgn(p, n, fastAsgn=false)
of nkFastAsgn:
cow(p, n[1])
if nfPreventCg notin n.flags:
# transf is overly aggressive with 'nkFastAsgn', so we work around here.
# See tests/run/tcnstseq3 for an example that would fail otherwise.
@@ -2861,8 +2745,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst, n[0].typ)
else: result = genBracedInit(p, n, isConst, n.typ)
if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst)
else: result = genBracedInit(p, n, isConst)
proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc})
@@ -2901,10 +2785,8 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
result.add getDefaultValue(p, t.sons[1], info)
result.add "}"
#result = rope"{}"
of tyOpenArray, tyVarargs:
result = rope"{NIM_NIL, 0}"
of tySet:
if mapSetType(p.config, t) == ctArray: result = rope"{}"
if mapType(p.config, t) == ctArray: result = rope"{}"
else: result = rope"0"
else:
globalError(p.config, info, "cannot create null element for: " & $t.kind)
@@ -2969,10 +2851,10 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
for i in 1..<constOrNil.len:
if constOrNil[i].kind == nkExprColonExpr:
if constOrNil[i][0].sym.name.id == field.name.id:
result.add genBracedInit(p, constOrNil[i][1], isConst, field.typ)
result.add genBracedInit(p, constOrNil[i][1], isConst)
return
elif i == field.position:
result.add genBracedInit(p, constOrNil[i], isConst, field.typ)
result.add genBracedInit(p, constOrNil[i], isConst)
return
# not found, produce default value:
result.add getDefaultValue(p, field.typ, info)
@@ -2991,10 +2873,7 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
getNullValueAuxT(p, orig, base, base.n, constOrNil, result, count, isConst, info)
result.add "}"
elif not isObjLackingTypeField(t):
if optTinyRtti in p.config.globalOptions:
result.add genTypeInfoV2(p.module, orig, obj.info)
else:
result.add genTypeInfoV1(p.module, orig, obj.info)
result.add genTypeInfo(p.module, orig, obj.info)
inc count
getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info)
# do not emit '{}' as that is not valid C:
@@ -3013,35 +2892,25 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool): Rope =
proc genConstSimpleList(p: BProc, n: PNode; isConst: bool): Rope =
result = rope("{")
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"
if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, it[0].typ)
else: result.add genBracedInit(p, it, isConst, it.typ)
result.add("}\n")
proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType): Rope =
result = rope("{")
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"
if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, tup[i])
else: result.add genBracedInit(p, it, isConst, tup[i])
result.add("}\n")
for i in 0..<n.len - 1:
result.addf("$1,$n", [genNamedConstExpr(p, n[i], isConst)])
if n.len > 0:
result.add(genNamedConstExpr(p, n[^1], isConst))
result.addf("}$n", [])
proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope]
let base = t.skipTypes(abstractInst)[0]
if n.len > 0:
# array part needs extra curlies:
data.add(", {")
for i in 0..<n.len:
if i > 0: data.addf(",$n", [])
data.add genBracedInit(p, n[i], isConst, base)
data.add genBracedInit(p, n[i], isConst)
data.add("}")
data.add("}")
result = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData,
"static $5 struct {$n" &
@@ -3054,14 +2923,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
let base = t.skipTypes(abstractInst)[0]
var data = rope"{"
for i in 0..<n.len:
if i > 0: data.addf(",$n", [])
data.add genBracedInit(p, n[i], isConst, base)
data.add genBracedInit(p, n[i], isConst)
data.add("}")
let payload = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData,
"static $5 struct {$n" &
@@ -3071,32 +2940,47 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
if isConst: "const" else: ""])
result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope =
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
case n.kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genBracedInit(p, n[1], isConst, n.typ)
when false:
# XXX The frontend doesn't keep conversions to openArray for us. :-(
# We need to change 'transformConv' first, but that is hard.
if n.typ.kind == tyOpenArray:
assert n[1].kind == nkBracket
let data = genBracedInit(p, n[1], isConst)
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0])
let arrLen = n[1].len
appcg(p.module, cfsData,
"static $5 $1 $3[$2] = $4;$n", [
ctype, arrLen, payload, data,
if isConst: "const" else: ""])
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
else:
result = genBracedInit(p, n[1], isConst)
else:
var ty = tyNone
var typ: PType = nil
if optionalType == nil:
if n.typ == nil:
if n.kind in nkStrKinds:
ty = tyString
else:
internalError(p.config, n.info, "node has no type")
else:
typ = skipTypes(optionalType, abstractInstOwned + {tyStatic})
ty = typ.kind
ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind
case ty
of tySet:
let cs = toBitSet(p.config, n)
var cs: TBitSet
toBitSet(p.config, n, cs)
result = genRawSetData(cs, int(getSize(p.config, n.typ)))
of tySequence:
if optSeqDestructors in p.config.globalOptions:
result = genConstSeqV2(p, n, typ, isConst)
result = genConstSeqV2(p, n, n.typ, isConst)
else:
result = genConstSeq(p, n, typ, isConst)
result = genConstSeq(p, n, n.typ, isConst)
of tyProc:
if typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit:
if n.typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit:
# Conversion: nimcall -> closure.
# this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
# this behaviour is needed since closure_var = nil must be
@@ -3109,30 +2993,13 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope
else:
var d: TLoc
initLocExpr(p, n[0], d)
result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)]
result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, n.typ, clHalfWithEnv), rdLoc(d)]
else:
var d: TLoc
initLocExpr(p, n, d)
result = rdLoc(d)
of tyArray, tyVarargs:
of tyArray, tyTuple, tyOpenArray, tyVarargs:
result = genConstSimpleList(p, n, isConst)
of tyTuple:
result = genConstTuple(p, n, isConst, typ)
of tyOpenArray:
if n.kind != nkBracket:
internalError(p.config, n.info, "const openArray expression is not an array construction")
let data = genConstSimpleList(p, n, isConst)
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, typ[0])
let arrLen = n.len
appcg(p.module, cfsData,
"static $5 $1 $3[$2] = $4;$n", [
ctype, arrLen, payload, data,
if isConst: "const" else: ""])
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
of tyObject:
result = genConstObjConstr(p, n, isConst)
of tyString, tyCString:

View File

@@ -48,10 +48,6 @@ const
NimMergeEndMark = "/*\tNIM_merge_END:*/"
proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
# useful for debugging and only adds at most a few lines in each file
result.add("\n/* section: ")
result.add(CFileSectionNames[fs])
result.add(" */\n")
if compilationCachePresent(conf):
result = nil
result.add("\n/*\t")
@@ -282,7 +278,7 @@ proc mergeRequired*(m: BModule): bool =
if m.s[i] != nil:
#echo "not empty: ", i, " ", m.s[i]
return true
for i in TCProcSection:
for i in low(TCProcSection)..high(TCProcSection):
if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", m.initProc.s[i]
return true
@@ -292,7 +288,7 @@ proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
var old: TMergeSections
readMergeSections(cfilename, old)
# do the merge; old section before new section:
for i in TCFileSection:
for i in low(TCFileSection)..high(TCFileSection):
m.s[i] = old.f[i] & m.s[i]
for i in TCProcSection:
for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = old.p[i] & m.initProc.s(i)

View File

@@ -200,7 +200,6 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0)
inc p.withinBlockLeaveActions
for i in 1..howManyTrys:
let tryStmt = p.nestedTryStmts.pop
if p.config.exc == excSetjmp:
@@ -218,8 +217,6 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
if finallyStmt != nil:
genStmts(p, finallyStmt[0])
dec p.withinBlockLeaveActions
# push old elements again:
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
@@ -272,7 +269,7 @@ proc genGotoVar(p: BProc; value: PNode) =
else:
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope
proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope =
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
@@ -280,7 +277,7 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope =
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ):
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
result = genBracedInit(p, value, isConst = false, v.typ)
result = genBracedInit(p, value, isConst = false)
else:
result = nil
@@ -382,13 +379,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
proc genSingleVar(p: BProc, a: PNode) =
let v = a[0].sym
if sfCompileTime in v.flags:
# fix issue #12640
# {.global, compileTime.} pragma in proc
if sfGlobal in v.flags and p.prc != nil and p.prc.kind == skProc:
discard
else:
return
if sfCompileTime in v.flags: return
genSingleVar(p, v, a[0], a[2])
proc genClosureVar(p: BProc, a: PNode) =
@@ -737,7 +728,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
initLocExprSingleUse(p, t[0], a)
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
var typ = skipTypes(t[0].typ, abstractPtrs)
# XXX For reasons that currently escape me, this is only required by the new
# C++ based exception handling:
@@ -870,10 +860,10 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
for it in b:
for i in 0..<b.len-1:
# last son is block
if (it.kind == nkRange) and
it[1].intVal - it[0].intVal > RangeExpandLimit:
if (b[i].kind == nkRange) and
b[i][1].intVal - b[i][0].intVal > RangeExpandLimit:
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
@@ -997,14 +987,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural))
if t.kind == nkHiddenTryStmt:
lineCg(p, cpsStmts, "try {$n", [])
expr(p, t[0], d)
lineCg(p, cpsStmts, "}$n", [])
else:
startBlock(p, "try {$n")
expr(p, t[0], d)
endBlock(p)
startBlock(p, "try {$n")
expr(p, t[0], d)
endBlock(p)
# First pass: handle Nim based exceptions:
lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1])
@@ -1046,7 +1031,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, typeNode.typ)
else:
genTypeInfoV1(p.module, typeNode.typ, typeNode.info)
genTypeInfo(p.module, typeNode.typ, typeNode.info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1224,10 +1209,6 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
p.nestedTryStmts.add((fin, false, Natural lab))
p.flags.incl nimErrorFlagAccessed
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
expr(p, t[0], d)
if 1 < t.len and t[1].kind == nkExceptBranch:
@@ -1261,7 +1242,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ)
else:
genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1298,7 +1279,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
# handler present or only handlers that did not match.
linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab])
endBlock(p)
raiseExit(p)
if p.prc != nil: raiseExit(p)
if hasExcept: inc p.withinTryWithExcept
proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
@@ -1364,13 +1345,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
else:
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural))
expr(p, t[0], d)
if not quirkyExceptions:
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
lineCg(p, cpsStmts, "}$n", [])
endBlock(p)
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
genRestoreFrameAfterException(p)
@@ -1400,7 +1381,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ)
else:
genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1471,7 +1452,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
else:
# ignore empty lines
result.add("\"")
result.add(x.replace("\"", "\\\""))
result.add(x)
result.add("\\n\"\n")
else:
res.add("\L")
@@ -1515,7 +1496,7 @@ proc genPragma(p: BProc, n: PNode) =
of wEmit: genEmit(p, it)
of wInjectStmt:
var p = newProc(nil, p.module)
p.options.excl {optLineTrace, optStackTrace}
p.options = p.options - {optLineTrace, optStackTrace}
genStmts(p, it[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
@@ -1525,7 +1506,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfoV1(p.module, t, a.lode.info)
discard genTypeInfo(p.module, t, a.lode.info)
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
[discriminatorTableDecl(p.module, t, field)])
@@ -1573,7 +1554,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
let le = e[0]
let ri = e[1]
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs))
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)

View File

@@ -42,12 +42,11 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
proc generateThreadLocalStorage(m: BModule) =
if m.g.nimtv != nil 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].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) =
if m.g.nimtv != nil:
let externc = if m.config.backend == backendCpp or
let externc = if m.config.cmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" "
else: ""
m.s[cfsProcs].addf(

View File

@@ -173,7 +173,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
[result, markerName, getModuleDllPath(m)])
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfoV1(m, s.loc.t, info)
discard genTypeInfo(m, s.loc.t, info)
var c: TTraversalClosure
var p = newProc(nil, m)

View File

@@ -149,7 +149,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
of 8: result = ctInt64
else: result = ctArray
proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
## Maps a Nim type to a C type
case typ.kind
of tyNone, tyTyped: result = ctVoid
@@ -157,17 +157,14 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
of tyChar: result = ctChar
of tyNil: result = ctPtr
of tySet: result = mapSetType(conf, typ)
of tyOpenArray, tyVarargs:
if kind == skParam: result = ctArray
else: result = ctStruct
of tyArray, tyUncheckedArray: result = ctArray
of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses:
doAssert typ.isResolvedUserTypeClass
return mapType(conf, typ.lastSon, kind)
return mapType(conf, typ.lastSon)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
result = mapType(conf, lastSon(typ), kind)
result = mapType(conf, lastSon(typ))
of tyEnum:
if firstOrd(conf, typ) < 0:
result = ctInt32
@@ -178,7 +175,7 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctInt32
of tyRange: result = mapType(conf, typ[0], kind)
of tyRange: result = mapType(conf, typ[0])
of tyPtr, tyVar, tyLent, tyRef:
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
@@ -195,14 +192,14 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(conf, lastSon typ, kind)
if typ.n != nil: result = mapType(conf, lastSon typ)
else: doAssert(false, "mapType")
else: doAssert(false, "mapType")
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
#else:
result = mapType(conf, typ, skResult)
result = mapType(conf, typ)
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
@@ -212,7 +209,7 @@ proc isImportedCppType(t: PType): bool =
result = (t.sym != nil and sfInfixCall in t.sym.flags) or
(x.sym != nil and sfInfixCall in x.sym.flags)
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
@@ -226,7 +223,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
if rettype == nil or (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3):
result = true
else:
case mapType(conf, rettype, skResult)
case mapType(conf, rettype)
of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyLent, tyRef, tyPtr})
@@ -242,7 +239,7 @@ const
"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_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
# returns nil if we need to declare this type
@@ -251,13 +248,8 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
result = tab.getOrDefault(sig)
proc addAbiCheck(m: BModule, t: PType, name: Rope) =
if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize):
var msg = "backend & Nim disagree on size for: "
msg.addTypeHeader(m.config, t)
var msg2 = ""
msg2.addQuoted msg # not a hostspot so extra allocation doesn't matter
m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope])
# see `testCodegenABICheck` for example error message it generates
if isDefined(m.config, "checkabi") and (let size = getSize(m.config, t); size != szUnknownSize):
m.s[cfsTypeInfo].addf("NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)])
proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
@@ -272,19 +264,19 @@ proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool =
result = true
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
result = true # requested anyway
elif retType != nil and retType.kind == tyLent:
result = true
elif (tfFinal in pt.flags) and (pt[0] == nil):
result = false # no need, because no subtyping possible
else:
result = true # ordinary objects are always passed by reference,
# otherwise casting doesn't work
of tyTuple:
result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
else:
result = false
# first parameter and return type is 'lent T'? --> use pass by pointer
if s.position == 0 and retType != nil and retType.kind == tyLent:
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
if retType != nil and retType.kind == tyLent:
result = true
else:
result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
else: result = false
proc fillResult(conf: ConfigRef; param: PNode) =
fillLoc(param.sym.loc, locParam, param, ~"Result",
@@ -337,6 +329,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
let sig = hashType typ
if cacheGetType(m.typeCache, sig) == nil:
m.typeCache[sig] = result
addAbiCheck(m, typ, result)
proc pushType(m: BModule, typ: PType) =
for i in 0..high(m.typeStack):
@@ -351,8 +344,8 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
if result == nil: result = cacheGetType(m.typeCache, sig)
proc structOrUnion(t: PType): Rope =
let cachedUnion = rope("union")
let cachedStruct = rope("struct")
let cachedUnion {.global.} = rope("union")
let cachedStruct {.global.} = rope("struct")
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: cachedUnion
else: cachedStruct
@@ -372,7 +365,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
if result != nil: return
result = getTypePre(m, typ, sig)
if result != nil: return
let concrete = typ.skipTypes(abstractInst)
let concrete = typ.skipTypes(abstractInst + {tyOpt})
case concrete.kind
of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ, sig)
@@ -384,7 +377,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
doAssert m.forwTypeCache[sig] == result
else: internalError(m.config, "getTypeForward(" & $typ.kind & ')')
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope =
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
## like getTypeDescAux but creates only a *weak* dependency. In other words
## we know we only need a pointer to it so we only generate a struct forward
## declaration:
@@ -392,7 +385,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and t.kind == tyGenericInst:
result = getTypeDescAux(m, t, check, kind)
result = getTypeDescAux(m, t, check)
else:
result = getTypeForward(m, t, hashType(t))
pushType(m, t)
@@ -422,18 +415,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
result = getTypeForward(m, t, sig) & seqStar(m)
pushType(m, t)
else:
result = getTypeDescAux(m, t, check, kind)
result = getTypeDescAux(m, t, check)
proc getSeqPayloadType(m: BModule; t: PType): Rope =
var check = initIntSet()
result = getTypeDescWeak(m, t, check, skParam) & "_Content"
result = getTypeDescWeak(m, t, check) & "_Content"
#result = getTypeForward(m, t, hashType(t)) & "_Content"
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
let sig = hashType(t)
let result = cacheGetType(m.typeCache, sig)
if result == nil:
discard getTypeDescAux(m, t, check, skVar)
discard getTypeDescAux(m, t, check)
else:
# little hack for now to prevent multiple definitions of the same
# Seq_Content:
@@ -442,7 +435,7 @@ $3ifndef $2_Content_PP
$3define $2_Content_PP
struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];};
$3endif$N
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"])
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])
proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
@@ -458,7 +451,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
rettype = ~"void"
else:
rettype = getTypeDescAux(m, t[0], check, skResult)
rettype = getTypeDescAux(m, t[0], check)
for i in 1..<t.n.len:
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
var param = t.n[i].sym
@@ -467,17 +460,15 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param),
param.paramStorageLoc)
if ccgIntroducedPtr(m.config, param, t[0]):
params.add(getTypeDescWeak(m, param.typ, check, skParam))
params.add(getTypeDescWeak(m, param.typ, check))
params.add(~"*")
incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown
elif weakDep:
params.add(getTypeDescWeak(m, param.typ, check, skParam))
params.add(getTypeDescWeak(m, param.typ, check))
else:
params.add(getTypeDescAux(m, param.typ, check, skParam))
params.add(getTypeDescAux(m, param.typ, check))
params.add(~" ")
if sfNoalias in param.flags:
params.add(~"NIM_NOALIAS ")
params.add(param.loc.r)
# declare the len field for open arrays:
var arr = param.typ
@@ -494,10 +485,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
var arr = t[0]
if params != nil: params.add(", ")
if mapReturnType(m.config, t[0]) != ctArray:
params.add(getTypeDescWeak(m, arr, check, skResult))
params.add(getTypeDescWeak(m, arr, check))
params.add("*")
else:
params.add(getTypeDescAux(m, arr, check, skResult))
params.add(getTypeDescAux(m, arr, check))
params.addf(" Result", [])
if t.callConv == ccClosure and declareEnvironment:
if params != nil: params.add(", ")
@@ -566,21 +557,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let noAlias = if sfNoalias in field.flags: ~" NIM_NOALIAS" else: nil
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
result.addf("$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check, skField), sname])
[getTypeDescAux(m, fieldType.elemType, check), sname])
elif fieldType.kind == tySequence:
# we need to use a weak dependency here for trecursive_table.
result.addf("$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias])
result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
elif field.bitsize != 0:
result.addf("$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias])
result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias])
result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
@@ -615,14 +604,11 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
appcg(m, result, " {$n", [])
else:
if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
appcg(m, result, " {$n#TNimType* m_type;$n", [])
hasField = true
elif m.compileToCpp:
appcg(m, result, " : public $1 {$n",
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
@@ -635,7 +621,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
hasField = true
else:
appcg(m, result, " {$n $1 Sup;$n",
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
hasField = true
else:
result.addf(" {$n", [name])
@@ -655,7 +641,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
var desc: Rope = nil
for i in 0..<typ.len:
desc.addf("$1 Field$2;$n",
[getTypeDescAux(m, typ[i], check, skField), rope(i)])
[getTypeDescAux(m, typ[i], check), rope(i)])
if desc == nil: result.add("char dummy;\L")
else: result.add(desc)
result.add("};\L")
@@ -689,22 +675,8 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
result = if result.kind == tyGenericInst: result[1]
else: result.elemType
proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope =
let sig = hashType(t)
if kind == skParam:
result = getTypeDescWeak(m, t[0], check, kind) & "*"
else:
result = cacheGetType(m.typeCache, sig)
if result == nil:
result = getTypeName(m, t, sig)
m.typeCache[sig] = result
let elemType = getTypeDescWeak(m, t[0], check, kind)
m.s[cfsTypes].addf("typedef struct {$n$2* Field0;$nNI Field1;$n} $1;$n",
[result, elemType])
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope =
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
# returns only the type's name
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
if containsOrIncl(check, t.id):
if not (isImportedCppType(origTyp) or isImportedCppType(t)):
@@ -715,22 +687,17 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
if t.sym != nil: useHeader(m, t.sym)
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp)
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
result = getTypePre(m, t, sig)
if result != nil and t.kind != tyOpenArray:
if result != nil:
excl(check, t.id)
return
case t.kind
of tyRef, tyPtr, tyVar, tyLent:
var star = if t.kind in {tyVar} and tfVarIsPtr notin origTyp.flags and
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
compileToCpp(m): "&" else: "*"
var et = origTyp.skipTypes(abstractInst).lastSon
var etB = et.skipTypes(abstractInst)
if mapType(m.config, t, kind) == ctPtrToArray and (etB.kind != tyOpenArray or kind == skParam):
if mapType(m.config, t) == ctPtrToArray:
if etB.kind == tySet:
et = getSysType(m.g.graph, unknownLineInfo, tyUInt8)
else:
@@ -740,7 +707,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst:
result = getTypeDescAux(m, et, check, kind) & star
result = getTypeDescAux(m, et, check) & star
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType et)
@@ -748,7 +715,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
m.typeCache[sig] = result
of tySequence:
if optSeqDestructors in m.config.globalOptions:
result = getTypeDescWeak(m, et, check, kind) & star
result = getTypeDescWeak(m, et, check) & star
m.typeCache[sig] = result
else:
# no restriction! We have a forward declaration for structs
@@ -758,10 +725,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
pushType(m, et)
else:
# else we have a strong dependency :-(
result = getTypeDescAux(m, et, check, kind) & star
result = getTypeDescAux(m, et, check) & star
m.typeCache[sig] = result
of tyOpenArray, tyVarargs:
result = getOpenArrayDesc(m, t, check, kind)
result = getTypeDescWeak(m, t[0], check) & "*"
m.typeCache[sig] = result
of tyEnum:
result = cacheGetType(m.typeCache, sig)
if result == nil:
@@ -807,7 +775,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
[result, rettype, desc])
of tySequence:
if optSeqDestructors in m.config.globalOptions:
result = getTypeDescWeak(m, t, check, kind)
result = getTypeDescWeak(m, t, check)
else:
# we cannot use getTypeForward here because then t would be associated
# with the name of the struct, not with the pointer to the struct:
@@ -828,11 +796,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
if m.compileToCpp:
appcg(m, m.s[cfsSeqTypes],
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
"};$n", [getTypeDescAux(m, t[0], check), result])
else:
appcg(m, m.s[cfsSeqTypes],
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
"};$n", [getTypeDescAux(m, t[0], check), result])
else:
result = rope("TGenericSeq")
result.add(seqStar(m))
@@ -840,7 +808,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t[0], check, kind)
let foo = getTypeDescAux(m, t[0], check)
m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
of tyArray:
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
@@ -848,9 +816,10 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t[1], check, kind)
let foo = getTypeDescAux(m, t[1], check)
m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
[foo, result, rope(n)])
else: addAbiCheck(m, t, result)
of tyObject, tyTuple:
if isImportedCppType(t) and origTyp.kind == tyGenericInst:
let cppName = getTypeName(m, t, sig)
@@ -864,7 +833,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
internalAssert m.config, ty.n != nil
result.add ty.n.renderTree
else:
result.add getTypeDescAux(m, ty, check, kind)
result.add getTypeDescAux(m, ty, check)
while i < cppName.data.len:
if cppName.data[i] == '\'':
@@ -911,8 +880,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
m.s[cfsTypes].add(recdesc)
elif tfIncompleteStruct notin t.flags:
discard # addAbiCheck(m, t, result) # already handled elsewhere
elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
of tySet:
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType
@@ -925,16 +893,16 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
[result, rope(getSize(m.config, t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
result = getTypeDescAux(m, lastSon(t), check, kind)
result = getTypeDescAux(m, lastSon(t), check)
else:
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
result = nil
# fixes bug #145:
excl(check, t.id)
proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope =
proc getTypeDesc(m: BModule, typ: PType): Rope =
var check = initIntSet()
result = getTypeDescAux(m, typ, check, kind)
result = getTypeDescAux(m, typ, check)
type
TClosureTypeKind = enum ## In C closures are mapped to 3 different things.
@@ -966,9 +934,8 @@ proc finishTypeDescriptions(m: BModule) =
if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence:
seqV2ContentType(m, t, check)
else:
discard getTypeDescAux(m, t, check, skParam)
discard getTypeDescAux(m, t, check)
inc(i)
m.typeStack.setLen 0
template cgDeclFrmt*(s: PSym): string =
s.constraint.strVal
@@ -1013,7 +980,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
# ------------------ type info generation -------------------------------------
proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope
proc getNimNode(m: BModule): Rope =
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes)
@@ -1033,14 +1000,11 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
let nameHcr = tiNameForHcr(m, name)
var size: Rope
if tfIncompleteStruct in typ.flags:
size = rope"void*"
else:
size = getTypeDesc(m, origType, skVar)
if tfIncompleteStruct in typ.flags: size = rope"void*"
else: size = getTypeDesc(m, origType)
m.s[cfsTypeInit3].addf(
"$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n",
[nameHcr, size, rope(nimtypeKind), base]
)
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
[nameHcr, size, rope(nimtypeKind), base])
# compute type flags for GC optimization
var flags = 0
if not containsGarbageCollectedRef(typ): flags = flags or 1
@@ -1076,7 +1040,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
base = rope("0")
else:
base = genTypeInfoV1(m, x, info)
base = genTypeInfo(m, x, info)
else:
base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base, info)
@@ -1134,8 +1098,8 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
m.s[cfsTypeInit3].addf("$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, origType, skVar), field.loc.r,
genTypeInfoV1(m, field.typ, info),
"$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
genTypeInfo(m, field.typ, info),
makeCString(field.name.s),
tmp, rope(L)])
m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)])
@@ -1171,8 +1135,8 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
internalError(m.config, n.info, "genObjectFields")
m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, origType, skVar),
field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)])
"$1.name = $5;$n", [expr, getTypeDesc(m, origType),
field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
else: internalError(m.config, n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
@@ -1207,7 +1171,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo)
"$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, origType, skVar), rope(i), genTypeInfoV1(m, a, info)])
[tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)])
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(typ.len), tmp])
else:
@@ -1264,7 +1228,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
[tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info)
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info)
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1282,14 +1246,13 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r])
proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) =
let nr = rope(name)
proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) =
if m.hcrOn:
m.s[cfsData].addf("static $2* $1;$n", [str, nr])
m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n",
[str, getModuleDllPath(m, ownerModule), nr])
m.s[cfsData].addf("static TNimType* $1;$n", [str])
m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
[str, getModuleDllPath(m, ownerModule)])
else:
m.s[cfsData].addf("extern $2 $1;$n", [str, nr])
m.s[cfsData].addf("extern TNimType $1;$n", [str])
proc genTypeInfo2Name(m: BModule; t: PType): Rope =
var res = "|"
@@ -1322,26 +1285,21 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
# convention at least:
if theProc.typ == nil or theProc.typ.callConv != ccNimCall:
if theProc.typ == nil or theProc.typ.callConv != ccDefault:
localError(m.config, info,
theProc.name.s & " needs to have the 'nimcall' calling convention")
genProc(m, theProc)
result = theProc.loc.r
when false:
if not canFormAcycle(t) and op == attachedTrace:
echo "ayclic but has this =trace ", t, " ", theProc.ast
else:
when false:
if op == attachedTrace and m.config.selectedGC == gcOrc and
containsGarbageCollectedRef(t):
# unfortunately this check is wrong for an object type that only contains
# .cursor fields like 'Node' inside 'cycleleak'.
if op == attachedTrace and m.config.selectedGC == gcOrc and
containsGarbageCollectedRef(t):
when false:
# re-enable this check
internalError(m.config, info, "no attached trace proc found")
result = rope("NIM_NIL")
proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
var typeName: Rope
if t.kind == tyObject:
if incompleteType(t):
@@ -1351,68 +1309,20 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
else:
typeName = rope("NIM_NIL")
discard cgsym(m, "TNimTypeV2")
m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
discard cgsym(m, "TNimType")
m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name])
let destroyImpl = genHook(m, t, info, attachedDestructor)
let traceImpl = genHook(m, t, info, attachedTrace)
let disposeImpl = genHook(m, t, info, attachedDispose)
var flags = 0
if not canFormAcycle(t): flags = flags or 1
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6; $1.flags = $7;", [
m.s[cfsTypeInit3].addf("$1.destructor = (void*)$2; $1.size = sizeof($3);$n" &
"$1.name = $4;$n" &
"$1.traceImpl = (void*)$5;$n" &
"$1.disposeImpl = (void*)$6;$n", [
name, destroyImpl, getTypeDesc(m, t), typeName,
traceImpl, disposeImpl, rope(flags)])
traceImpl, disposeImpl])
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType)
result = m.typeInfoMarkerV2.getOrDefault(sig)
if result != nil:
return prefixTI.rope & result & ")".rope
let marker = m.g.typeInfoMarkerV2.getOrDefault(sig)
if marker.str != nil:
discard cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", marker.str, marker.owner)
# also store in local type section:
m.typeInfoMarkerV2[sig] = marker.str
return prefixTI.rope & marker.str & ")".rope
result = "NTIv2$1_" % [rope($sig)]
m.typeInfoMarkerV2[sig] = result
let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
# make sure the type info is created in the owner module
assert m.g.modules[owner.position] != nil
discard genTypeInfoV2(m.g.modules[owner.position], origType, info)
# reference the type info as extern here
discard cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", result, owner)
return prefixTI.rope & result & ")".rope
m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
genTypeInfoV2Impl(m, t, origType, result, info)
result = prefixTI.rope & result & ")".rope
proc openArrayToTuple(m: BModule; t: PType): PType =
result = newType(tyTuple, t.owner)
let p = newType(tyPtr, t.owner)
let a = newType(tyUncheckedArray, t.owner)
a.add t.lastSon
p.add a
result.add p
result.add getSysType(m.g.graph, t.owner.info, tyInt)
proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
@@ -1427,7 +1337,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
if marker.str != nil:
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
declareNimType(m, "TNimType", marker.str, marker.owner)
declareNimType(m, marker.str, marker.owner)
# also store in local type section:
m.typeInfoMarker[sig] = marker.str
return prefixTI.rope & marker.str & ")".rope
@@ -1439,68 +1349,63 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
if owner != m.module:
# make sure the type info is created in the owner module
assert m.g.modules[owner.position] != nil
discard genTypeInfoV1(m.g.modules[owner.position], origType, info)
discard genTypeInfo(m.g.modules[owner.position], origType, info)
# reference the type info as extern here
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
declareNimType(m, "TNimType", result, owner)
declareNimType(m, result, owner)
return prefixTI.rope & result & ")".rope
m.g.typeInfoMarker[sig] = (str: result, owner: owner)
case t.kind
of tyEmpty, tyVoid: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyStatic:
if t.n != nil: result = genTypeInfoV1(m, lastSon t, info)
else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert m.config, t.isResolvedUserTypeClass
return genTypeInfoV1(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
if optTinyRtti in m.config.globalOptions:
genTypeInfoV2(m, t, origType, result, info)
else:
case t.kind
of tyEmpty, tyVoid: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
else:
let x = fakeClosureType(m, t.owner)
genTupleInfo(m, x, x, result, info)
of tySequence:
genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}:
let markerProc = genTraverseProc(m, origType, sig)
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
of tyRef:
genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}:
let markerProc = genTraverseProc(m, origType, sig)
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
of tyArray: genArrayInfo(m, t, result, info)
of tySet: genSetInfo(m, t, result, info)
of tyEnum: genEnumInfo(m, t, result, info)
of tyObject:
genObjectInfo(m, t, origType, result, info)
of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, origType, result, info)
of tyOpenArray:
let x = openArrayToTuple(m, t)
genTupleInfo(m, x, origType, result, info)
else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t, info)
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert m.config, t.isResolvedUserTypeClass
return genTypeInfo(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
else:
let x = fakeClosureType(m, t.owner)
genTupleInfo(m, x, x, result, info)
of tySequence:
genTypeInfoAux(m, t, t, result, info)
if optSeqDestructors notin m.config.globalOptions:
if m.config.selectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig)
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
of tyRef:
genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig)
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
of tyArray: genArrayInfo(m, t, result, info)
of tySet: genSetInfo(m, t, result, info)
of tyEnum: genEnumInfo(m, t, result, info)
of tyObject:
genObjectInfo(m, t, origType, result, info)
of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, origType, result, info)
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
if t.attachedOps[attachedDeepCopy] != nil:
genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result)
elif origType.attachedOps[attachedDeepCopy] != nil:
genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result)
if optTinyRtti in m.config.globalOptions and t.kind == tyObject and sfImportc notin t.sym.flags:
let v2info = genTypeInfoV2(m, origType, info)
addf(m.s[cfsTypeInit3], "$1->typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [
v2info, result])
result = prefixTI.rope & result & ")".rope
proc genTypeSection(m: BModule, n: PNode) =

View File

@@ -279,7 +279,7 @@ proc genProc(m: BModule, prc: PSym)
proc raiseInstr(p: BProc): Rope
template compileToCpp(m: BModule): untyped =
m.config.backend == backendCpp or sfCompileToCpp in m.module.flags
m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels)
@@ -310,19 +310,14 @@ include ccgtypes
# ------------------------------ Manager of temporaries ------------------
template mapTypeChooser(n: PNode): TSymKind =
(if n.kind == nkSym: n.sym.kind else: skVar)
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
result = a.r
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
result = "(&" & result & ")"
proc byRefLoc(p: BProc; a: TLoc): Rope =
result = a.r
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not
p.module.compileToCpp:
result = "(&" & result & ")"
@@ -360,10 +355,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
while s.kind == tyObject and s[0] != nil:
r.add(".Sup")
s = skipTypes(s[0], skipPtrs)
if optTinyRtti in p.config.globalOptions:
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)])
else:
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc
@@ -372,14 +364,14 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
linefmt(p, cpsStmts,
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType)])
else:
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
genAssignment(p, a, tmp, {})
else:
# worst case for performance:
var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a)
linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)])
if isException(t):
var r = rdLoc(a)
@@ -395,7 +387,7 @@ proc genRefAssign(p: BProc, dest, src: TLoc)
proc isComplexValueType(t: PType): bool {.inline.} =
let t = t.skipTypes(abstractInst + tyUserTypeClasses)
result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or
result = t.kind in {tyArray, tySet, tyTuple, tyObject} or
(t.kind == tyProc and t.callConv == ccClosure)
include ccgreset
@@ -416,11 +408,13 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)])
else:
if optNilCheck in p.options:
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", [addrLoc(p.config, loc)])
if loc.storage != OnStack and containsGcRef:
specializeReset(p, loc)
when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)])
[addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
@@ -428,8 +422,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
# array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc)
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
[addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
@@ -446,14 +439,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
genRefAssign(p, loc, nilLoc)
else:
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
getTypeDesc(p.module, typ)])
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
# avoid it:
if not isImportedCppType(typ):
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
[addrLoc(p.config, loc), getTypeDesc(p.module, typ)])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@@ -471,25 +464,17 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
when false:
# XXX Introduce a compiler switch in order to detect these easily.
if getSize(p.config, t) > 1024 * 1024:
if p.prc != nil:
echo "ENORMOUS TEMPORARY! ", p.config $ p.prc.info
else:
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
writeStackTrace()
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -511,13 +496,12 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
result.add getTypeDesc(p.module, s.typ, skVar)
result.add getTypeDesc(p.module, s.typ)
if s.constraint.isNil:
if sfRegister in s.flags: result.add(" register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# decl.add(" GC_GUARD")
if sfVolatile in s.flags: result.add(" volatile")
if sfNoalias in s.flags: result.add(" NIM_NOALIAS")
result.add(" ")
result.add(s.loc.r)
else:
@@ -565,7 +549,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
internalError(p.config, n.info, ".threadvar variables cannot have a value")
else:
var decl: Rope = nil
var td = getTypeDesc(p.module, s.loc.t, skVar)
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
@@ -578,7 +562,6 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
if value != nil:
decl.addf(" $1 = $2;$n", [s.loc.r, value])
else:
@@ -706,13 +689,13 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
[loadlib, genStringLiteral(m, lib.path)])
else:
var p = newProc(nil, m)
p.options.excl optStackTrace
p.options = p.options - {optStackTrace}
p.flags.incl nimErrorFlagDisabled
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
[getTypeDesc(m, lib.path.typ), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
@@ -752,7 +735,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last[1]
internalAssert(m.config, last.kind == nkStrLit)
@@ -766,8 +749,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -779,9 +762,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
@@ -1100,11 +1083,11 @@ proc genProcAux(m: BModule, prc: PSym) =
proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
result = (sfCompileToCpp in m.module.flags and
sfCompileToCpp notin sym.getModule().flags and
m.config.backend != backendCpp) or (
m.config.cmd != cmdCompileToCpp) or (
sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and
sym.flags * {sfImportc, sfExportc} != {} and
sym.magic == mNone and
m.config.backend == backendCpp)
m.config.cmd == cmdCompileToCpp)
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
@@ -1200,44 +1183,21 @@ proc requestConstImpl(p: BProc, sym: PSym) =
useHeader(m, sym)
if sym.loc.k == locNone:
fillLoc(sym.loc, locData, sym.ast, mangleName(p.module, sym), OnStatic)
if m.hcrOn: incl(sym.loc.flags, lfIndirect)
if lfNoDecl in sym.loc.flags: return
# declare implementation:
var q = findPendingModule(m, sym)
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
assert q.initProc.module == q
# add a suffix for hcr - will later init the global pointer with this data
let actualConstName = if m.hcrOn: sym.loc.r & "_const" else: sym.loc.r
q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), actualConstName,
genBracedInit(q.initProc, sym.ast, isConst = true, sym.typ)])
if m.hcrOn:
# generate the global pointer with the real name
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r])
# register it (but ignore the boolean result of hcrRegisterGlobal)
q.initProc.procSec(cpsLocals).addf(
"\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
[getModuleDllPath(q, sym), sym.loc.r, rdLoc(sym.loc)])
# always copy over the contents of the actual constant with the _const
# suffix ==> this means that the constant is reloadable & updatable!
q.initProc.procSec(cpsLocals).add(ropecg(q,
"\t#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
[sym.loc.r, actualConstName, rdLoc(sym.loc)]))
[getTypeDesc(q, sym.typ), sym.loc.r, genBracedInit(q.initProc, sym.ast, isConst = true)])
# declare header:
if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
if m.hcrOn:
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]);
m.initProc.procSec(cpsLocals).addf(
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)])
else:
let headerDecl = "extern NIM_CONST $1 $2;$n" %
[getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]
m.s[cfsData].add(headerDecl)
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
let headerDecl = "extern NIM_CONST $1 $2;$n" %
[getTypeDesc(m, sym.loc.t), sym.loc.r]
m.s[cfsData].add(headerDecl)
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
proc isActivated(prc: PSym): bool = prc.typ != nil
@@ -1274,16 +1234,15 @@ proc genVarPrototype(m: BModule, n: PNode) =
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t))
if m.hcrOn: m.s[cfsVars].add("*")
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile")
if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS")
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
@@ -1589,7 +1548,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if sfSystemModule in m.module.flags:
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
@@ -1641,10 +1600,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
prc.typ.sym = nil
if not containsOrIncl(m.declaredThings, prc.id):
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)])
result = "\t$1 = ($2) $3($4, $5);$n" %
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
[tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
proc genInitCode(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
@@ -1694,10 +1653,6 @@ proc genInitCode(m: BModule) =
writeSection(preInitProc, cpsInit, m.hcrOn)
writeSection(preInitProc, cpsStmts)
prc.addf("}/* preInitProc end */$N", [])
when false:
m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals)
m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit)
m.initProc.blocks[0].sections[cpsStmts].prepend m.preInitProc.s(cpsStmts)
# add new scope for following code, because old vcc compiler need variable
# be defined at the top of the block
@@ -1809,6 +1764,11 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
if moduleIsEmpty:
result = nil
proc newPreInitProc(m: BModule): BProc =
result = newProc(nil, m)
# little hack so that unique temporaries are generated:
result.labels = 100_000
proc initProcOptions(m: BModule): TOptions =
let opts = m.config.options
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
@@ -1829,9 +1789,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.sigConflicts = initCountTable[SigHash]()
result.initProc = newProc(nil, result)
result.initProc.options = initProcOptions(result)
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
result.preInitProc = newPreInitProc(result)
initNodeTable(result.dataCache)
result.typeStack = @[]
result.typeNodesName = getTempName(result)
@@ -1861,10 +1819,7 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend)
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
injectG()
result = newModule(g, module, graph.config)
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
@@ -1904,7 +1859,7 @@ proc writeHeader(m: BModule) =
proc getCFile(m: BModule): AbsoluteFile =
let ext =
if m.compileToCpp: ".nim.cpp"
elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m"
elif m.config.cmd == cmdCompileToOC or sfCompileToObjc in m.module.flags: ".nim.m"
else: ".nim.c"
result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
@@ -2059,7 +2014,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil:
discard cgsym(m, "nimTestErrorFlag")
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
if {optGenStaticLib, optGenDynLib} * m.config.globalOptions == {}:
for i in countdown(high(graph.globalDestructors), 0):
n.add graph.globalDestructors[i]
if passes.skipCodegen(m.config, n): return
@@ -2100,8 +2055,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
let disp = generateMethodDispatchers(graph)
for x in disp: genProcAux(m, x.sym)
let mm = m
m.g.modulesClosed.add mm
m.g.modulesClosed.add m
proc genForwardedProcs(g: BModuleList) =
# Forward declared proc:s lack bodies when first encountered, so they're given

View File

@@ -11,7 +11,7 @@
import
ast, ropes, options, intsets,
tables, ndi, lineinfos, pathutils, modulegraphs, sets
tables, ndi, lineinfos, pathutils, modulegraphs
type
TLabel* = Rope # for the C generator a label is just a rope
@@ -25,7 +25,7 @@ type
# this is needed for strange type generation
# reasons
cfsFieldInfo, # section for field information
cfsTypeInfo, # section for type information (ag ABI checks)
cfsTypeInfo, # section for type information
cfsProcHeaders, # section for C procs prototypes
cfsData, # section for C constant data
cfsVars, # section for C variable declarations
@@ -97,7 +97,6 @@ type
# requires 'T x = T()' to become 'T x; x = T()'
# (yes, C++ is weird like that)
withinTryWithExcept*: int # required for goto based exception handling
withinBlockLeaveActions*: int # complex to explain
sigConflicts*: CountTable[string]
TTypeSeq* = seq[PType]
@@ -122,7 +121,6 @@ type
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
generatedHeader*: BModule
typeInfoMarker*: TypeCacheWithOwner
typeInfoMarkerV2*: TypeCacheWithOwner
config*: ConfigRef
graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use
@@ -147,16 +145,11 @@ type
# without extension)
tmpBase*: Rope # base for temp identifier generation
typeCache*: TypeCache # cache the generated types
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
# would be ideal but for some reason enums
# don't seem to get cached so it'd generate
# 1 ABI check per occurence in code
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: seq[string] # needed headers to include
typeInfoMarker*: TypeCache # needed for generating type information
typeInfoMarkerV2*: TypeCache
initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
@@ -192,8 +185,8 @@ proc newProc*(prc: PSym, module: BModule): BProc =
new(result)
result.prc = prc
result.module = module
result.options = if prc != nil: prc.options
else: module.config.options
if prc != nil: result.options = prc.options
else: result.options = module.config.options
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]

View File

@@ -113,7 +113,7 @@ proc createDispatcher(s: PSym): PSym =
excl(disp.flags, sfExported)
disp.typ = copyType(disp.typ, disp.typ.owner, false)
# we can't inline the dispatcher itself (for now):
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil

View File

@@ -392,10 +392,6 @@ proc hasYieldsInExpressions(n: PNode): bool =
return true
else:
result = n.hasYields
of nkCast:
for i in 1..<n.len:
if n[i].hasYieldsInExpressions:
return true
else:
for c in n:
if c.hasYieldsInExpressions:
@@ -489,6 +485,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
var tmp: PSym
var s: PNode
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
@@ -607,12 +604,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
result.add(n)
result.add(ctx.newEnvVarAccess(tmp))
elif n[0].kind == nkStmtListExpr:
result = newNodeI(nkStmtList, n.info)
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
result.add(n)
of nkCallKinds, nkChckRange, nkChckRangeF, nkChckRange64:
var ns = false
@@ -699,7 +690,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv,
nkDerefExpr, nkHiddenDeref:
var ns = false
for i in ord(n.kind == nkCast)..<n.len:
for i in 0..<n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
@@ -751,6 +742,8 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
result.add(n)
of nkWhileStmt:
var ns = false
var condNeedsSplit = false
n[0] = ctx.lowerStmtListExprs(n[0], condNeedsSplit)
var bodyNeedsSplit = false

View File

@@ -7,33 +7,20 @@
# distribution, for details about the copyright.
#
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix
## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix
import
options, idents, nimconf, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, os, pathutils, parseopt
lineinfos, modulegraphs, condsyms, os, pathutils
from strutils import normalize
proc prependCurDir*(f: AbsoluteFile): AbsoluteFile =
when defined(unix):
if os.isAbsolute(f.string): result = f
else: result = AbsoluteFile("./" & f.string)
else:
result = f
proc addCmdPrefix*(result: var string, kind: CmdLineKind) =
# consider moving this to std/parseopt
case kind
of cmdLongOption: result.add "--"
of cmdShortOption: result.add "-"
of cmdArgument, cmdEnd: discard
type
NimProg* = ref object
suggestMode*: bool
supportsStdinFile*: bool
processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef)
mainCommand*: proc(graph: ModuleGraph)
proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
condsyms.initDefines(conf.symbols)
@@ -55,28 +42,37 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
else:
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir())
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef;
graph: ModuleGraph): bool =
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
if self.suggestMode:
conf.command = "nimsuggest"
loadConfigs(DefaultConfig, cache, conf) # load all config files
if not self.suggestMode:
block:
let scriptFile = conf.projectFull.changeFileExt("nims")
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile == conf.projectFull:
if conf.command == "":
conf.command = "e"
return false
elif conf.command.normalize == "e":
return false
if not self.suggestMode:
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile == conf.projectFull:
if conf.command == "":
conf.command = "e"
return false
elif conf.command.normalize == "e":
return false
# now process command line arguments again, because some options in the
# command line can overwrite the config file's settings
extccomp.initVars(conf)
# XXX This is hacky. We need to find a better way.
case conf.command
of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp
else:
discard
self.processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
let graph = newModuleGraph(cache, conf)
graph.suggestMode = self.suggestMode
self.mainCommand(graph)
return true

View File

@@ -53,14 +53,15 @@ const
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} =
result = ""
for f in T:
if result.len > 0: result.add "|"
result.add $f
var x = ""
for f in low(T)..high(T):
if x.len > 0: x.add "|"
x.add $f
x
const
Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)]
Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)]
proc getCommandLineDesc(conf: ConfigRef): string =
result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
@@ -97,7 +98,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
CPU[conf.target.hostCPU].name, CompileDate]),
{msgStdout})
const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip
const gitHash = gorge("git log -n 1 --format=%H").strip
when gitHash.len == 40:
msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
@@ -145,24 +146,24 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC
proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case arg.normalize
of "", "on": conf.options.incl op
of "off": conf.options.excl op
of "","on": conf.options = conf.options + op
of "off": conf.options = conf.options - op
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo): bool =
result = false
case arg.normalize
of "on": conf.options.incl op
of "off": conf.options.excl op
of "on": conf.options = conf.options + op
of "off": conf.options = conf.options - op
of "list": result = true
else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case arg.normalize
of "", "on": conf.globalOptions.incl op
of "off": conf.globalOptions.excl op
of "", "on": conf.globalOptions = conf.globalOptions + op
of "off": conf.globalOptions = conf.globalOptions - op
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
@@ -175,7 +176,7 @@ proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info:
proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var id = "" # arg = key:val or [key]:val; with val=on|off
var i = 0
var n = hintMin
var isBracket = false
@@ -189,20 +190,18 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
if i < arg.len and arg[i] == ']': inc(i)
else: invalidCmdLineOption(conf, pass, orig, info)
if i == arg.len: discard
elif i < arg.len and (arg[i] in {':', '='}): inc(i)
if i < arg.len and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(conf, pass, orig, info)
if state == wHint:
let x = findStr(hintMin..hintMax, id, errUnknown)
if x != errUnknown: n = TNoteKind(x)
let x = findStr(lineinfos.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin))
else: localError(conf, info, "unknown hint: " & id)
else:
let x = findStr(warnMin..warnMax, id, errUnknown)
if x != errUnknown: n = TNoteKind(x)
let x = findStr(lineinfos.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: localError(conf, info, "unknown warning: " & id)
var val = substr(arg, i).normalize
if val == "": val = "on"
let val = substr(arg, i).normalize
if val notin ["on", "off"]:
localError(conf, info, errOnOrOffExpectedButXFound % arg)
elif n notin conf.cmdlineNotes or pass == passCmd1:
@@ -210,18 +209,12 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
incl(conf.modifiedyNotes, n)
case val
of "on":
if state == wWarningAsError:
incl(conf.warningAsErrors, n)
else:
incl(conf.notes, n)
incl(conf.mainPackageNotes, n)
incl(conf.notes, n)
incl(conf.mainPackageNotes, n)
of "off":
if state == wWarningAsError:
excl(conf.warningAsErrors, n)
else:
excl(conf.notes, n)
excl(conf.mainPackageNotes, n)
excl(conf.foreignPackageNotes, n)
excl(conf.notes, n)
excl(conf.mainPackageNotes, n)
excl(conf.foreignPackageNotes, n)
proc processCompile(conf: ConfigRef; filename: string) =
var found = findFile(conf, filename)
@@ -229,10 +222,10 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found"
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjump', 'cpp' or 'quirky' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
case switch.normalize
@@ -298,7 +291,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
of "infchecks": result = contains(conf.options, optInfCheck)
of "nanchecks": result = contains(conf.options, optNaNCheck)
of "nilchecks": result = false # not a thing
of "nilchecks": result = contains(conf.options, optNilCheck)
of "objchecks": result = contains(conf.options, optObjCheck)
of "fieldchecks": result = contains(conf.options, optFieldCheck)
of "rangechecks": result = contains(conf.options, optRangeCheck)
@@ -319,6 +312,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
of "patterns", "trmacros": result = contains(conf.options, optTrMacros)
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs": result = contains(conf.options, optNilSeqs)
of "oldast": result = contains(conf.options, optOldAst)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
@@ -391,19 +385,6 @@ proc handleStdinInput*(conf: ConfigRef) =
if conf.outDir.isEmpty:
conf.outDir = getNimcacheDir(conf)
proc specialDefine(conf: ConfigRef, key: string) =
# Keep this syncronized with the default config/nim.cfg!
if cmpIgnoreStyle(key, "nimQuirky") == 0:
conf.exc = excQuirky
elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0:
conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize}
conf.globalOptions.excl {optExcessiveStackTrace, optCDebug}
conf.options.incl optOptimizeSpeed
if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0:
conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir}
conf.globalOptions.excl {optCDebug}
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
var
@@ -445,28 +426,23 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "outdir":
expectArg(conf, switch, arg, pass, info)
conf.outDir = processPath(conf, arg, info, notRelativeToProj=true)
of "usenimcache":
processOnOffSwitchG(conf, {optUseNimcache}, arg, pass, info)
of "docseesrcurl":
expectArg(conf, switch, arg, pass, info)
conf.docSeeSrcUrl = arg
of "docroot":
conf.docRoot = if arg.len == 0: docRootDefault else: arg
of "backend", "b":
let backend = parseEnum(arg.normalize, TBackend.default)
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
conf.backend = backend
of "doccmd": conf.docCmd = arg
conf.docRoot = if arg.len == 0: "@default" else: arg
of "mainmodule", "m":
discard "allow for backwards compatibility, but don't do anything"
of "define", "d":
expectArg(conf, switch, arg, pass, info)
if {':', '='} in arg:
splitSwitch(conf, arg, key, val, pass, info)
specialDefine(conf, key)
if cmpIgnoreStyle(key, "nimQuirky") == 0:
conf.exc = excQuirky
defineSymbol(conf.symbols, key, val)
else:
specialDefine(conf, arg)
if cmpIgnoreStyle(arg, "nimQuirky") == 0:
conf.exc = excQuirky
defineSymbol(conf.symbols, arg)
of "undef", "u":
expectArg(conf, switch, arg, pass, info)
@@ -494,13 +470,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "forcebuild", "f":
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
of "project":
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
processOnOffSwitchG(conf, {optWholeProject}, arg, pass, info)
of "gc":
if conf.backend == backendJs or conf.command == "js":
# for: bug #16033
# This might still be imperfect, in rarse corner cases
# (where command is reset in nimscript, maybe).
return
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
case arg.normalize
@@ -517,6 +488,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc":
conf.selectedGC = gcArc
if conf.cmd != cmdCompileToCpp:
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcarc")
incl conf.globalOptions, optSeqDestructors
@@ -526,6 +499,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nimV2")
of "orc":
conf.selectedGC = gcOrc
if conf.cmd != cmdCompileToCpp:
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcorc")
incl conf.globalOptions, optSeqDestructors
@@ -554,7 +529,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf)
of "hints":
if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
@@ -596,13 +570,25 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else:
undefSymbol(conf.symbols, "hotcodereloading")
undefSymbol(conf.symbols, "useNimRtl")
of "oldnewlines":
case arg.normalize
of "", "on":
conf.oldNewlines = true
defineSymbol(conf.symbols, "nimOldNewlines")
of "off":
conf.oldNewlines = false
undefSymbol(conf.symbols, "nimOldNewlines")
else:
localError(conf, info, errOnOrOffExpectedButXFound % arg)
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info)
of "oldast": processOnOffSwitch(conf, {optOldAst}, arg, pass, info)
of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
of "floatchecks":
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
of "nilchecks": discard "no such thing anymore"
of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
@@ -882,9 +868,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "expandmacro":
expectArg(conf, switch, arg, pass, info)
conf.macrosToExpand[arg] = "T"
of "expandarc":
expectArg(conf, switch, arg, pass, info)
conf.arcToExpand[arg] = "T"
of "oldgensym":
processOnOffSwitchG(conf, {optNimV019}, arg, pass, info)
of "useversion":
expectArg(conf, switch, arg, pass, info)
case arg
@@ -895,26 +880,14 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "NimPatch", "100")
# old behaviors go here:
defineSymbol(conf.symbols, "nimOldRelativePathBehavior")
undefSymbol(conf.symbols, "nimDoesntTrackDefects")
ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect}
conf.globalOptions.incl optNimV1Emulation
of "1.2":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "2")
# always be compatible with 1.2.100:
defineSymbol(conf.symbols, "NimPatch", "100")
conf.globalOptions.incl optNimV12Emulation
else:
localError(conf, info, "unknown Nim version; currently supported values are: {1.0}")
of "benchmarkvm":
processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
of "profilevm":
processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info)
of "sinkinference":
processOnOffSwitch(conf, {optSinkInference}, arg, pass, info)
of "cursorinference":
# undocumented, for debugging purposes only:
processOnOffSwitch(conf, {optCursorInference}, arg, pass, info)
of "panics":
processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
if optPanics in conf.globalOptions:
@@ -922,14 +895,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "sourcemap":
conf.globalOptions.incl optSourcemap
conf.options.incl optLineDir
of "deepcopy":
processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info)
# processOnOffSwitchG(conf, {optSourcemap, opt}, arg, pass, info)
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
handleStdinInput(conf)
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
else: invalidCmdLineOption(conf, pass, switch, info)
template gCmdLineInfo*(): untyped = newLineInfo(commandLineIdx, 1, 1)
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
var cmd, arg: string
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)

View File

@@ -13,7 +13,7 @@ import
strtabs
from options import Feature
from lineinfos import hintMin, hintMax, warnMin, warnMax
from lineinfos import HintsToStr, WarningsToStr
proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
symbols[symbol] = value
@@ -86,13 +86,13 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimMacrosSizealignof")
defineSymbol("nimNoZeroExtendMagic")
defineSymbol("nimMacrosGetNodeId")
for f in Feature:
for f in low(Feature)..high(Feature):
defineSymbol("nimHas" & $f)
for s in warnMin..warnMax:
defineSymbol("nimHasWarning" & $s)
for s in hintMin..hintMax:
defineSymbol("nimHasHint" & $s)
for s in WarningsToStr:
defineSymbol("nimHasWarning" & s)
for s in HintsToStr:
defineSymbol("nimHasHint" & s)
defineSymbol("nimFixedOwned")
defineSymbol("nimHasStyleChecks")
@@ -102,7 +102,6 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimnomagic64")
defineSymbol("nimNewShiftOps")
defineSymbol("nimHasCursor")
defineSymbol("nimAlignPragma")
defineSymbol("nimHasExceptionsQuery")
defineSymbol("nimHasIsNamedTuple")
defineSymbol("nimHashOrdinalFixed")
@@ -117,10 +116,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewIntegerOps")
defineSymbol("nimHasInvariant")
defineSymbol("nimHasStacktraceMsgs")
defineSymbol("nimDoesntTrackDefects")
defineSymbol("nimHasLentIterators")
defineSymbol("nimHasDeclaredMagic")
defineSymbol("nimHasStacktracesModule")
defineSymbol("nimHasEffectTraitsModule")
defineSymbol("nimHasCastPragmaBlocks")
defineSymbol("nimHasJsBigIntBackend")

View File

@@ -51,10 +51,7 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
rope(project.splitFile.name), b.dotGraph],
changeFileExt(project, "dot"))
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module

View File

@@ -29,7 +29,7 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, types, intsets, lineinfos, renderer, asciitables
import ast, types, intsets, lineinfos, renderer
from patterns import sameTrees
@@ -57,11 +57,14 @@ type
Con = object
code: ControlFlowGraph
inTryStmt: int
inCall, inTryStmt: int
blocks: seq[TBlock]
owner: PSym
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
proc debugInfo(info: TLineInfo): string =
result = $info.line #info.toFilename & ":" & $info.line
proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
# for debugging purposes
# first iteration: compute all necessary labels:
var jumpTargets = initIntSet()
@@ -82,14 +85,17 @@ proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
result.add "L"
result.addInt c[i].dest+i
result.add("\t#")
result.add($c[i].n.info.line)
result.add(debugInfo(c[i].n.info))
result.add("\n")
inc i
if i in jumpTargets: result.add("L" & $i & ": End\n")
# consider calling `asciitables.alignTable`
proc echoCfg*(c: ControlFlowGraph; start = 0; last = -1) {.deprecated.} =
proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} =
## echos the ControlFlowGraph for debugging purposes.
echo codeListing(c, start, last).alignTable
var buf = ""
codeListing(c, buf, start, last)
echo buf
proc forkI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)
@@ -267,20 +273,22 @@ duplicate the 'join' instructions on breaks and return exits!
]#
proc genLabel(c: Con): TPosition = TPosition(c.code.len)
template checkedDistance(dist): int =
doAssert low(int) div 2 + 1 < dist and dist < high(int) div 2
dist
proc genLabel(c: Con): TPosition =
result = TPosition(c.code.len)
proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
c.code.add Instr(n: n, kind: goto, dest: checkedDistance(p.int - c.code.len))
let dist = p.int - c.code.len
doAssert(low(int) div 2 + 1 < dist and dist < high(int) div 2)
c.code.add Instr(n: n, kind: goto, dest: dist)
proc patch(c: var Con, p: TPosition) =
# patch with current index
c.code[p.int].dest = checkedDistance(c.code.len - p.int)
let p = p.int
let diff = c.code.len - p
doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2)
c.code[p].dest = diff
proc gen(c: var Con; n: PNode)
proc gen(c: var Con; n: PNode) # {.noSideEffect.}
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition]
@@ -294,8 +302,8 @@ proc popBlock(c: var Con; oldLen: int) =
c.patch e
c.blocks.setLen(oldLen)
template withBlock(labl: PSym; body: untyped) =
let oldLen = c.blocks.len
template withBlock(labl: PSym; body: untyped) {.dirty.} =
var oldLen {.gensym.} = c.blocks.len
c.blocks.add TBlock(isTryBlock: false, label: labl)
body
popBlock(c, oldLen)
@@ -358,9 +366,11 @@ when true:
endings[i] = c.forkI(n)
c.gen(n[1])
for i in countdown(endings.high, 0):
c.patch(endings[i])
let endPos = endings[i]
c.patch(endPos)
else:
proc genWhile(c: var Con; n: PNode) =
# lab1:
# cond, tmp
@@ -375,9 +385,10 @@ else:
c.jmpBack(n, lab1)
else:
c.gen(n[0])
forkT(n):
c.gen(n[1])
c.jmpBack(n, lab1)
let lab2 = c.forkI(n)
c.gen(n[1])
c.jmpBack(n, lab1)
c.patch(lab2)
template forkT(n, body) =
let lab1 = c.forkI(n)
@@ -423,14 +434,16 @@ proc genIf(c: var Con, n: PNode) =
]#
var endings: seq[TPosition] = @[]
for i in 0..<n.len:
let it = n[i]
var it = n[i]
c.gen(it[0])
if it.len == 2:
forkT(it[1]):
c.gen(it[1])
endings.add c.gotoI(it[1])
let elsePos = forkI(c, it[1])
c.gen(it[1])
endings.add(c.gotoI(it[1]))
c.patch(elsePos)
for i in countdown(endings.high, 0):
c.patch(endings[i])
let endPos = endings[i]
c.patch(endPos)
proc genAndOr(c: var Con; n: PNode) =
# asgn dest, a
@@ -460,13 +473,16 @@ proc genCase(c: var Con; n: PNode) =
c.gen(n[0])
for i in 1..<n.len:
let it = n[i]
if it.len == 1 or (i == n.len-1 and isExhaustive):
if it.len == 1:
c.gen(it[0])
elif i == n.len-1 and isExhaustive:
# treat the last branch as 'else' if this is an exhaustive case statement.
c.gen(it.lastSon)
else:
forkT(it.lastSon):
c.gen(it.lastSon)
endings.add c.gotoI(it.lastSon)
let elsePos = c.forkI(it.lastSon)
c.gen(it.lastSon)
endings.add(c.gotoI(it.lastSon))
c.patch(elsePos)
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
@@ -490,6 +506,7 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
proc genBreak(c: var Con; n: PNode) =
if n[0].kind == nkSym:
#echo cast[int](n[0].sym)
for i in countdown(c.blocks.high, 0):
if not c.blocks[i].isTryBlock and c.blocks[i].label == n[0].sym:
genBreakOrRaiseAux(c, i, n)
@@ -508,6 +525,7 @@ proc genTry(c: var Con; n: PNode) =
c.blocks.add TBlock(isTryBlock: true, finale: if n[^1].kind == nkFinally: n[^1] else: newNode(nkEmpty))
inc c.inTryStmt
#let elsePos = c.forkI(n)
c.gen(n[0])
dec c.inTryStmt
@@ -516,14 +534,20 @@ proc genTry(c: var Con; n: PNode) =
c.blocks.setLen oldLen
#c.patch(elsePos)
for i in 1..<n.len:
let it = n[i]
if it.kind != nkFinally:
forkT(it):
c.gen(it.lastSon)
endings.add c.gotoI(it)
let endExcept = c.forkI(it)
c.gen(it.lastSon)
endings.add(c.gotoI(it))
c.patch(endExcept)
for i in countdown(endings.high, 0):
c.patch(endings[i])
let endPos = endings[i]
c.patch(endPos)
# join the 'elsePos' forkI instruction:
#c.joinI(c.blocks[^1].forks.pop(), n)
let fin = lastSon(n)
if fin.kind == nkFinally:
@@ -573,43 +597,59 @@ proc skipConvDfa*(n: PNode): PNode =
result = result[1]
else: break
proc aliases*(obj, field: PNode): bool =
var n = field
var obj = obj
proc genUse(c: var Con; orig: PNode) =
var n = orig
while true:
case obj.kind
of {nkObjDownConv, nkObjUpConv, nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref}:
obj = obj[0]
of PathKinds1:
obj = obj[1]
else: break
while true:
if sameTrees(obj, n): return true
case n.kind
of PathKinds0:
of PathKinds0 - {nkBracketExpr}:
n = n[0]
of nkBracketExpr:
gen(c, n[1])
n = n[0]
of PathKinds1:
n = n[1]
else: break
if n.kind in nkCallKinds:
gen(c, n)
if n.kind == nkSym and n.sym.kind in InterestingSyms:
c.code.add Instr(n: orig, kind: use)
type InstrTargetKind* = enum
None, Full, Partial
proc aliases*(obj, field: PNode): bool =
var n = field
var obj = obj
while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv,
nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref}:
obj = obj[0]
while true:
if sameTrees(obj, n): return true
case n.kind
of PathKinds0, PathKinds1:
n = n[0]
else:
break
proc instrTargets*(insloc, loc: PNode): InstrTargetKind =
if sameTrees(insloc, loc) or insloc.aliases(loc):
Full # x -> x; x -> x.f
elif loc.aliases(insloc):
Partial # x.f -> x
else: None
proc useInstrTargets*(ins: Instr; loc: PNode): bool =
assert ins.kind == use
result = sameTrees(ins.n, loc) or
ins.n.aliases(loc) or loc.aliases(ins.n)
# We can come here if loc is 'x.f' and ins.n is 'x' or the other way round.
# use x.f; question: does it affect the full 'x'? No.
# use x; question does it affect 'x.f'? Yes.
proc defInstrTargets*(ins: Instr; loc: PNode): bool =
assert ins.kind == def
result = sameTrees(ins.n, loc) or ins.n.aliases(loc)
# We can come here if loc is 'x.f' and ins.n is 'x' or the other way round.
# def x.f; question: does it affect the full 'x'? No.
# def x; question: does it affect the 'x.f'? Yes.
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
var n = orig
while true:
case n.kind
of PathKinds0 - {nkBracketExpr, nkHiddenDeref, nkDerefExpr}:
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr:
n = n[0]
of PathKinds1:
n = n[1]
of nkBracketExpr:
# in a[i] the 'i' must be known
if n.len > 1 and n[1].kind in {nkCharLit..nkUInt64Lit}:
@@ -622,13 +662,14 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
# bug #14159, we cannot reason about sinkParam[].location as it can
# still be shared for tyRef.
n = n[0]
return n.kind == nkSym and n.sym.owner == owner and
(n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned})
else: break
return n.kind == nkSym and n.sym.owner == owner and (
n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned})
else:
break
# XXX Allow closure deref operations here if we know
# the owner controlled the closure allocation?
result = n.kind == nkSym and n.sym.owner == owner and
{sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and
owner.kind != skModule and
(n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar)
# Note: There is a different move analyzer possible that checks for
# consume(param.key); param.key = newValue for all paths. Then code like
@@ -641,42 +682,43 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
# free the old data and all is lost! Lesson: Don't be too smart, trust the
# lower level C++ optimizer to specialize this code.
proc skipTrivials(c: var Con, n: PNode): PNode =
result = n
proc genDef(c: var Con; n: PNode) =
var m = n
# XXX do something about this duplicated logic here.
while true:
case result.kind
of PathKinds0 - {nkBracketExpr}:
result = result[0]
case m.kind
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr:
m = m[0]
of nkBracketExpr:
gen(c, result[1])
result = result[0]
of PathKinds1:
result = result[1]
else: break
proc genUse(c: var Con; orig: PNode) =
let n = c.skipTrivials(orig)
gen(c, m[1])
m = m[0]
of nkHiddenDeref, nkDerefExpr:
m = m[0]
else:
break
if n.kind == nkSym and n.sym.kind in InterestingSyms:
c.code.add Instr(n: orig, kind: use)
elif n.kind in nkCallKinds:
c.code.add Instr(n: n, kind: def)
elif isAnalysableFieldAccess(n, c.owner):
c.code.add Instr(n: n, kind: def)
else:
# bug #13314: An assignment to t5.w = -5 is a usage of 't5'
# we still need to gather the use information:
gen(c, n)
proc genDef(c: var Con; orig: PNode) =
let n = c.skipTrivials(orig)
if n.kind == nkSym and n.sym.kind in InterestingSyms:
c.code.add Instr(n: orig, kind: def)
proc genCall(c: var Con; n: PNode) =
gen(c, n[0])
var t = n[0].typ
if t != nil: t = t.skipTypes(abstractInst)
inc c.inCall
for i in 1..<n.len:
gen(c, n[i])
when false:
if t != nil and i < t.len and t[i].kind == tyOut:
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
if t != nil and i < t.len and t[i].kind == tyVar:
# This is wrong! Pass by var is a 'might def', not a 'must def'
# like the other defs we emit. This is not good enough for a move
# optimizer.
genDef(c, n[i])
# every call can potentially raise:
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
@@ -685,11 +727,13 @@ proc genCall(c: var Con; n: PNode) =
# goto exceptionHandler (except or finally)
# lab1:
# join F1
forkT(n):
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
break
let endGoto = c.forkI(n)
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
break
c.patch(endGoto)
dec c.inCall
proc genMagic(c: var Con; n: PNode; m: TMagic) =
case m
@@ -733,7 +777,7 @@ proc gen(c: var Con; n: PNode) =
# "uses" 'i'. But we are only talking about builtin array indexing so
# it doesn't matter and 'x = 34' is NOT a usage of 'x'.
genDef(c, n[0])
of PathKinds0 - {nkObjDownConv, nkObjUpConv}:
of PathKinds0 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}:
genUse(c, n)
of nkIfStmt, nkIfExpr: genIf(c, n)
of nkWhenStmt:
@@ -750,12 +794,13 @@ proc gen(c: var Con; n: PNode) =
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkYieldStmt:
for x in n: gen(c, x)
of nkPragmaBlock: gen(c, n.lastSon)
of nkDiscardStmt, nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
gen(c, n[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv:
gen(c, n[1])
of nkStringToCString, nkCStringToString: gen(c, n[0])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
of nkDefer:
doAssert false, "dfa construction pass requires the elimination of 'defer'"
else: discard
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
@@ -764,7 +809,4 @@ proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
withBlock(s):
gen(c, body)
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc):
result = c.code # will move
else:
shallowCopy(result, c.code)
shallowCopy(result, c.code)

View File

@@ -17,28 +17,19 @@ import
packages/docutils/rst, packages/docutils/rstgen,
json, xmltree, cgi, trees, types,
typesrenderer, astalgo, lineinfos, intsets,
pathutils, trees, tables, nimpaths, renderverbatim, osproc
from std/private/globs import nativeToUnixPath
pathutils, trees
const
exportSection = skField
docCmdSkip = "skip"
htmldocsDir = RelativeDir"htmldocs"
type
TSections = array[TSymKind, Rope]
ExampleGroup = ref object
## a group of runnableExamples with same rdoccmd
rdoccmd: string ## from 1st arg in `runnableExamples(rdoccmd): body`
docCmd: string ## from user config, e.g. --doccmd:-d:foo
code: string ## contains imports; each import contains `body`
index: int ## group index
TDocumentor = object of rstgen.RstGenerator
modDesc: Rope # module description
module: PSym
modDeprecationMsg: Rope
toc, toc2, section: TSections
tocTable: array[TSymKind, Table[string, Rope]]
toc, section: TSections
indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
@@ -50,12 +41,22 @@ type
exampleCounter: int
emitted: IntSet # we need to track which symbols have been emitted
# already. See bug #3655
destFile*: AbsoluteFile
thisDir*: AbsoluteDir
exampleGroups: OrderedTable[string, ExampleGroup]
wroteSupportFiles*: bool
examples: string
wroteCss*: bool
PDoc* = ref TDocumentor ## Alias to type less.
proc nativeToUnix(path: string): string =
doAssert not path.isAbsolute # absolute files need more care for the drive
when DirSep == '\\':
result = replace(path, '\\', '/')
else: result = path
proc docOutDir(conf: ConfigRef, subdir: RelativeDir = RelativeDir""): AbsoluteDir =
if not conf.outDir.isEmpty: conf.outDir else: conf.projectPath / subdir
proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): RelativeFile =
## returns a relative file that will be appended to outDir
let file2 = $file
@@ -64,7 +65,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re
proc nimbleDir(): AbsoluteDir =
getNimbleFile(conf, file2).parentDir.AbsoluteDir
case conf.docRoot:
of docRootDefault:
of "@default": # using `@` instead of `$` to avoid shell quoting complications
result = getRelativePathFromConfigPath(conf, file)
let dir = nimbleDir()
if not dir.isEmpty:
@@ -80,20 +81,17 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re
result = getRelativePathFromConfigPath(conf, file)
if result.isEmpty: bail()
elif conf.docRoot.len > 0:
# we're (currently) requiring `isAbsolute` to avoid confusion when passing
# a relative path (would it be relative wrt $PWD or to projectfile)
conf.globalAssert conf.docRoot.isAbsolute, arg=conf.docRoot
conf.globalAssert conf.docRoot.dirExists, arg=conf.docRoot
# needed because `canonicalizePath` called on `file`
result = file.relativeTo conf.docRoot.expandFilename.AbsoluteDir
doAssert conf.docRoot.isAbsolute, conf.docRoot # or globalError
doAssert conf.docRoot.existsDir, conf.docRoot
result = relativeTo(file, conf.docRoot.AbsoluteDir)
else:
bail()
if isAbsolute(result.string):
result = file.string.splitPath()[1].RelativeFile
if isTitle:
result = result.string.nativeToUnixPath.RelativeFile
result = result.string.nativeToUnix.RelativeFile
else:
result = result.string.replace("..", dotdotMangle).RelativeFile
result = result.string.replace("..", "@@").RelativeFile ## refs #13223
doAssert not result.isEmpty
doAssert not isAbsolute(result.string)
@@ -141,7 +139,7 @@ template declareClosures =
result = options.findFile(conf, s).string
if result.len == 0:
result = getCurrentDir() / s
if not fileExists(result): result = ""
if not existsFile(result): result = ""
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
@@ -152,9 +150,13 @@ proc parseRst(text, filename: string,
docgenFindFile, compilerMsgHandler)
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
ext: string, guessTarget: bool): AbsoluteFile =
if optWholeProject in conf.globalOptions or guessTarget:
let d = conf.outDir
ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile =
if optWholeProject in conf.globalOptions:
let d = conf.docOutDir(dir)
createDir(d)
result = d / changeFileExt(filename, ext)
elif guessTarget:
let d = conf.docOutDir
createDir(d)
result = d / changeFileExt(filename, ext)
elif not conf.outFile.isEmpty:
@@ -168,7 +170,6 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.module = module
result.conf = conf
result.cache = cache
result.outDir = conf.outDir.string
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown},
docgenFindFile, compilerMsgHandler)
@@ -195,7 +196,6 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
initStrTable result.types
result.onTestSnippet =
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) =
if conf.docCmd == docCmdSkip: return
inc(gen.id)
var d = TDocumentor(gen)
var outp: AbsoluteFile
@@ -214,24 +214,16 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
# Include the current file if we're parsing a nim file
let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")]
writeFile(outp, importStmt & content)
proc interpSnippetCmd(cmd: string): string =
# backward compatibility hacks; interpolation commands should explicitly use `$`
if cmd.startsWith "nim ": result = "$nim " & cmd[4..^1]
else: result = cmd
result = result.replace("$1", "$options") % [
"nim", os.getAppFilename().quoteShell,
"backend", $d.conf.backend,
"options", outp.quoteShell,
]
let cmd = cmd.interpSnippetCmd
rawMessage(conf, hintExecuting, cmd)
let (output, gotten) = execCmdEx(cmd)
if gotten != status:
rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output])
let c = if cmd.startsWith("nim "): os.getAppFilename() & cmd.substr(3)
else: cmd
let c2 = c % quoteShell(outp)
rawMessage(conf, hintExecuting, c2)
if execShellCmd(c2) != status:
rawMessage(conf, errGenerated, "executing of external program failed: " & c2)
result.emitted = initIntSet()
result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
result.thisDir = result.destFile.AbsoluteFile.splitFile.dir
result.destFile = getOutFile2(conf, presentationPath(conf, filename),
outExt, htmldocsDir, false)
result.thisDir = result.destFile.splitFile.dir
template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if conf.cmd != cmdRst2tex: dest.addf(xml, args)
@@ -303,13 +295,11 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
proc genComment(d: PDoc, n: PNode): string =
result = ""
var dummyHasToc: bool
if n.comment.len > 0:
let comment = n.comment
when false:
# RFC: to preseve newlines in comments, this would work:
comment = comment.replace("\n", "\n\n")
renderRstToOut(d[], parseRst(comment, toFullPath(d.conf, n.info), toLinenumber(n.info),
toColumn(n.info), (var dummy: bool; dummy), d.options, d.conf), result)
renderRstToOut(d[], parseRst(n.comment, toFullPath(d.conf, n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options, d.conf), result)
proc genRecCommentAux(d: PDoc, n: PNode): Rope =
if n == nil: return nil
@@ -341,10 +331,11 @@ proc getPlainDocstring(n: PNode): string =
## You need to call this before genRecComment, whose side effects are removal
## of comments from the tree. The proc will recursively scan and return all
## the concatenated ``##`` comments of the node.
if n == nil: result = ""
elif startsWith(n.comment, "##"):
result = ""
if n == nil: return
if startsWith(n.comment, "##"):
result = n.comment
else:
if result.len < 1:
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -355,7 +346,8 @@ proc belongsToPackage(conf: ConfigRef; module: PSym): bool =
proc externalDep(d: PDoc; module: PSym): string =
if optWholeProject in d.conf.globalOptions or d.conf.docRoot.len > 0:
let full = AbsoluteFile toFullPath(d.conf, FileIndex module.position)
let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, sfMainModule notin module.flags)
let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt,
htmldocsDir, sfMainModule notin module.flags)
result = relativeTo(tmp, d.thisDir, '/').string
else:
result = extractFilename toFullPath(d.conf, FileIndex module.position)
@@ -368,7 +360,6 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
var kind = tkEof
var tokenPos = 0
var procTokenPos = 0
template escLit(): untyped = rope(esc(d.target, literal))
while true:
getNextTok(r, kind, literal)
inc tokenPos
@@ -377,7 +368,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
break
of tkComment:
dispA(d.conf, result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[escLit])
[rope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh:
if kind in {tkProc, tkMethod, tkIterator, tkMacro, tkTemplate, tkFunc, tkConverter}:
procTokenPos = tokenPos
@@ -385,53 +376,53 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
[rope(literal)])
of tkOpr:
dispA(d.conf, result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[escLit])
[rope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit:
dispA(d.conf, result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [escLit])
"\\spanStringLit{$1}", [rope(esc(d.target, literal))])
of tkCharLit:
dispA(d.conf, result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[escLit])
[rope(esc(d.target, literal))])
of tkIntLit..tkUInt64Lit:
dispA(d.conf, result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [escLit])
"\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
of tkFloatLit..tkFloat128Lit:
dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [escLit])
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
of tkSymbol:
let s = getTokSym(r)
# -2 because of the whitespace in between:
if procTokenPos == tokenPos-2 and procLink != nil:
dispA(d.conf, result, "<a href=\"#$2\"><span class=\"Identifier\">$1</span></a>",
"\\spanIdentifier{$1}", [escLit, procLink])
"\\spanIdentifier{$1}", [rope(esc(d.target, literal)), procLink])
elif s != nil and s.kind in {skType, skVar, skLet, skConst} and
sfExported in s.flags and s.owner != nil and
belongsToPackage(d.conf, s.owner) and d.target == outHtml:
let external = externalDep(d, s.owner)
result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>",
[rope changeFileExt(external, "html"), rope literal,
escLit]
rope(esc(d.target, literal))]
else:
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [escLit])
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid:
result.add(literal)
of tkCurlyDotLe:
template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
if renderRunnableExamples in renderFlags: fun "$1"
else: fun: "<span>" & # This span is required for the JS to work properly
dispA(d.conf, result, "<span>" & # This span is required for the JS to work properly
"""<span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span>
</span>
<span class="pragmawrap">
<span class="Other">$1</span>
<span class="pragma">""".replace("\n", "") # Must remove newlines because wrapped in a <pre>
<span class="pragma">""".replace("\n", ""), # Must remove newlines because wrapped in a <pre>
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkCurlyDotRi:
template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
if renderRunnableExamples in renderFlags: fun "$1"
else: fun """
dispA(d.conf, result, """
</span>
<span class="Other">$1</span>
</span>""".replace("\n", "")
</span>""".replace("\n", ""),
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
@@ -439,73 +430,51 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
tkBracketLeColon:
dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[escLit])
[rope(esc(d.target, literal))])
proc exampleOutputDir(d: PDoc): AbsoluteDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) =
proc testExample(d: PDoc; ex: PNode) =
if d.conf.errorCounter > 0: return
let outputDir = d.exampleOutputDir
let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
createDir(outputDir)
inc d.exampleCounter
let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
"_examples" & $d.exampleCounter & ".nim"))
#let nimcache = outp.changeFileExt"" & "_nimcache"
renderModule(ex, d.filename, outp.string, conf = d.conf)
if rdoccmd notin d.exampleGroups: d.exampleGroups[rdoccmd] = ExampleGroup(rdoccmd: rdoccmd, docCmd: d.conf.docCmd, index: d.exampleGroups.len)
d.exampleGroups[rdoccmd].code.add "import r\"$1\"\n" % outp.string
d.examples.add "import r\"" & outp.string & "\"\n"
proc runAllExamples(d: PDoc) =
# This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however
# using `-d:js` (etc) cannot work properly, e.g. would fail with `importjs`
# since semantics are affected by `config.backend`, not by isDefined(d.conf, "js")
let outputDir = d.exampleOutputDir
for _, group in d.exampleGroups:
if group.docCmd == docCmdSkip: continue
let outp = outputDir / RelativeFile("$1_group$2_examples.nim" % [d.filename.splitFile.name, $group.index])
group.code = "# autogenerated by docgen\n# source: $1\n# rdoccmd: $2\n$3" % [d.filename, group.rdoccmd, group.code]
writeFile(outp, group.code)
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
# via command line
let cmd = "$nim $backend -r --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
"nim", os.getAppFilename(),
"backend", $d.conf.backend,
"path", quoteShell(d.conf.projectPath),
"nimcache", quoteShell(outputDir),
"file", quoteShell(outp),
"rdoccmd", group.rdoccmd,
"docCmd", group.docCmd,
]
if os.execShellCmd(cmd) != 0:
quit "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, $group[], cmd]
else:
# keep generated source file `outp` to allow inspection.
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
if d.examples.len == 0: return
let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
"_examples.nim"))
writeFile(outp, d.examples)
let backend = if isDefined(d.conf, "js"): "js"
elif isDefined(d.conf, "cpp"): "cpp"
elif isDefined(d.conf, "objc"): "objc"
else: "c"
if os.execShellCmd(os.getAppFilename() & " " & backend &
" --warning[UnusedImport]:off" &
" --path:" & quoteShell(d.conf.projectPath) &
" --nimcache:" & quoteShell(outputDir) &
" -r " & quoteShell(outp)) != 0:
quit "[Examples] failed: see " & outp.string
else:
# keep generated source file `outp` to allow inspection.
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
removeFile(outp.changeFileExt(ExeExt))
proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] =
## returns `rdoccmd` and source code for this runnableExamples
var rdoccmd = ""
if n.len < 2 or n.len > 3: globalError(d.conf, n.info, "runnableExamples invalid")
if n.len == 3:
let n1 = n[1]
# xxx this should be evaluated during sempass
if n1.kind notin nkStrKinds: globalError(d.conf, n1.info, "string litteral expected")
rdoccmd = n1.strVal
proc prepareExamples(d: PDoc; n: PNode) =
var docComment = newTree(nkCommentStmt)
let loc = d.conf.toFileLineCol(n.info)
docComment.comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd]
docComment.comment = "autogenerated by docgen from " & loc
var runnableExamples = newTree(nkStmtList,
docComment,
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
runnableExamples.info = n.info
let ret = extractRunnableExamplesSource(d.conf, n)
for a in n.lastSon: runnableExamples.add a
# we could also use `ret` instead here, to keep sources verbatim
writeExample(d, runnableExamples, rdoccmd)
result = (rdoccmd, ret)
testExample(d, runnableExamples)
when false:
proc extractImports(n: PNode; result: PNode) =
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
@@ -519,101 +488,36 @@ proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] =
for imp in imports: runnableExamples.add imp
runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
type RunnableState = enum
rsStart
rsComment
rsRunnable
rsDone
proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: RunnableState): RunnableState =
##[
Simple state machine to tell whether we render runnableExamples and doc comments.
This is to ensure that we can interleave runnableExamples and doc comments freely;
the logic is easy to change but currently a doc comment following another doc comment
will not render, to avoid rendering in following case:
proc fn* =
runnableExamples: discard
## d1
runnableExamples: discard
## d2
## internal explanation # <- this one should be out; it's part of rest of function body and would likey not make sense in doc comment
discard # some code
]##
proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
if n.info.fileIndex != orig.info.fileIndex: return
case n.kind
of nkCommentStmt:
if state in {rsStart, rsRunnable}:
dest.add genRecComment(d, n)
return rsComment
of nkCallKinds:
if isRunnableExamples(n[0]) and
n.len >= 2 and n.lastSon.kind == nkStmtList and state in {rsStart, rsComment, rsRunnable}:
let (rdoccmd, code) = prepareExample(d, n)
var msg = "Example:"
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
n.len >= 2 and n.lastSon.kind == nkStmtList:
prepareExamples(d, n)
dispA(d.conf, dest, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\\textbf{$1}\n", [msg.rope])
"\n\\textbf{$1}\n", [rope"Examples:"])
inc d.listingCounter
let id = $d.listingCounter
dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"])
var dest2 = ""
renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex)
dest.add dest2
# this is a rather hacky way to get rid of the initial indentation
# that the renderer currently produces:
var i = 0
var body = n.lastSon
if body.len == 1 and body.kind == nkStmtList and
body.lastSon.kind == nkStmtList:
body = body.lastSon
for b in body:
if i > 0: dest.add "\n"
inc i
nodeToHighlightedHtml(d, b, dest, {}, nil)
dest.add(d.config.getOrDefault"doc.listing_end" % id)
return rsRunnable
else: discard
return rsDone
# change this to `rsStart` if you want to keep generating doc comments
# and runnableExamples that occur after some code in routine
for i in 0..<n.safeLen:
getAllRunnableExamplesRec(d, n[i], orig, dest)
proc getRoutineBody(n: PNode): PNode =
##[
nim transforms these quite differently:
proc someType*(): int =
## foo
result = 3
=>
result =
## foo
3;
proc someType*(): int =
## foo
3
=>
## foo
result = 3;
so we normalize the results to get to the statement list containing the
(0 or more) doc comments and runnableExamples.
]##
result = n[bodyPos]
# This won't be transformed: result.id = 10. Namely result[0].kind != nkSym.
if result.kind == nkAsgn and result[0].kind == nkSym and
n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym:
doAssert result.len == 2
result = result[1]
proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var Rope) =
var n = n
var state = rsStart
template fn(n2) =
state = getAllRunnableExamplesImpl(d, n2, dest, state)
dest.add genComment(d, n).rope
case n.kind
of routineDefs:
n = n.getRoutineBody
case n.kind
of nkCommentStmt, nkCallKinds: fn(n)
else:
for i in 0..<n.safeLen:
fn(n[i])
if state == rsDone: return
else: fn(n)
proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
getAllRunnableExamplesRec(d, n, n, dest)
proc isVisible(d: PDoc; n: PNode): bool =
result = false
@@ -717,7 +621,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
of skTemplate: result.add(".t")
of skConverter: result.add(".c")
else: discard
if n.safeLen > paramsPos and n[paramsPos].kind == nkFormalParams:
if n.len > paramsPos and n[paramsPos].kind == nkFormalParams:
let params = renderParamTypes(n[paramsPos])
if params.len > 0:
result.add(defaultParamSeparator)
@@ -788,12 +692,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
var result: Rope = nil
var literal, plainName = ""
var kind = tkEof
var comm: Rope = nil
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var comm = genRecComment(d, n) # call this here for the side-effect!
getAllRunnableExamples(d, n, comm)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
@@ -851,7 +751,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope,
deprecationMsgRope]))
let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string
let external = d.destFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string
var attype: Rope
if k in routineKinds and nameNode.kind == nkSym:
@@ -868,13 +768,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
xmltree.escape(getPlainDocstring(e).docstringSummary))
d.toc[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
["name", "header_plain", "itemSymOrIDEnc"],
[nameRope, plainNameRope, symbolOrIdEncRope]))
d.tocTable[k].mgetOrPut(cleanPlainSymbol, nil).add(ropeFormatNamedVars(
d.conf, getConfigVar(d.conf, "doc.item.tocTable"),
["name", "header_plain", "itemSymOrID", "itemSymOrIDEnc"],
[nameRope, plainNameRope, rope(symbolOrId.replace(",", ",<wbr>")), symbolOrIdEncRope]))
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"],
[rope(getName(d, nameNode, d.splitAfter)), result, comm,
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope, attype]))
# Ironically for types the complexSymbol is *cleaner* than the plainName
# because it doesn't include object fields or documentation comments. So we
@@ -951,7 +849,7 @@ proc traceDeps(d: PDoc, it: PNode) =
if d.section[k] != nil: d.section[k].add(", ")
dispA(d.conf, d.section[k],
"<a class=\"reference external\" href=\"$2\">$1</a>",
"$1", [rope esc(d.target, external.prettyLink),
"$1", [rope esc(d.target, changeFileExt(external, "")),
rope changeFileExt(external, "html")])
proc exportSym(d: PDoc; s: PSym) =
@@ -961,22 +859,18 @@ proc exportSym(d: PDoc; s: PSym) =
if d.section[k] != nil: d.section[k].add(", ")
dispA(d.conf, d.section[k],
"<a class=\"reference external\" href=\"$2\">$1</a>",
"$1", [rope esc(d.target, external.prettyLink),
"$1", [rope esc(d.target, changeFileExt(external, "")),
rope changeFileExt(external, "html")])
elif s.kind != skModule and s.owner != nil:
let module = originatingModule(s)
if belongsToPackage(d.conf, module):
let
complexSymbol = complexName(s.kind, s.ast, s.name.s)
symbolOrIdRope = rope(d.newUniquePlainSymbol(complexSymbol))
external = externalDep(d, module)
let external = externalDep(d, module)
if d.section[k] != nil: d.section[k].add(", ")
# XXX proper anchor generation here
dispA(d.conf, d.section[k],
"<a href=\"$2#$3\"><span class=\"Identifier\">$1</span></a>",
"<a href=\"$2#$1\"><span class=\"Identifier\">$1</span></a>",
"$1", [rope esc(d.target, s.name.s),
rope changeFileExt(external, "html"),
symbolOrIdRope])
rope changeFileExt(external, "html")])
proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n[namePos].sym
@@ -1001,8 +895,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
# set the type so that the following analysis doesn't screw up:
effects[i].typ = real[i].typ
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects])
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n[namePos].sym
@@ -1014,8 +908,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
effects.add params[i]
if effects.len > 0:
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(cache, pragmaName), n.info), effects])
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1079,7 +973,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
if it.kind == nkSym:
if d.module != nil and d.module == it.sym.owner:
generateDoc(d, it.sym.ast, orig, kForceExport)
elif it.sym.ast != nil:
else:
exportSym(d, it.sym)
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
@@ -1176,7 +1070,7 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
generateTags(d, lastSon(n[0]), r)
else: discard
proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skField, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs",
"Methods", "Iterators", "Converters", "Macros", "Templates", "Exports"
@@ -1186,23 +1080,17 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
var tocSource = d.toc
if groupedToc:
for p in d.tocTable[kind].keys:
d.toc2[kind].add ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc2"), [
"sectionid", "sectionTitle", "sectionTitleID", "content", "plainName"], [
ord(kind).rope, title, rope(ord(kind) + 50), d.tocTable[kind][p], p.rope])
tocSource = d.toc2
d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).rope, title, rope(ord(kind) + 50), tocSource[kind]])
ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): Rope =
rope($relativeTo(outDir / linkto, destFile.splitFile().dir, '/'))
const nimdocOutCss = "nimdoc.out.css"
# `out` to make it easier to use with gitignore in user's repos
proc genOutFile(d: PDoc, groupedToc = false): Rope =
proc cssHref(outDir: AbsoluteDir, destFile: AbsoluteFile): Rope =
rope($relativeTo(outDir / nimdocOutCss.RelativeFile, destFile.splitFile().dir, '/'))
proc genOutFile(d: PDoc): Rope =
var
code, content: Rope
title = ""
@@ -1210,42 +1098,36 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope =
var tmp = ""
renderTocEntries(d[], j, 1, tmp)
var toc = tmp.rope
for i in TSymKind:
var shouldSort = i in {skProc, skFunc} and groupedToc
genSection(d, i, shouldSort)
for i in low(TSymKind)..high(TSymKind):
genSection(d, i)
toc.add(d.toc[i])
if toc != nil:
toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
for i in TSymKind: code.add(d.section[i])
for i in low(TSymKind)..high(TSymKind): code.add(d.section[i])
# Extract the title. Non API modules generate an entry in the index table.
if d.meta[metaTitle].len != 0:
title = d.meta[metaTitle]
let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnixPath
let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnix
setIndexTerm(d[], external, "", title)
else:
# Modules get an automatic title for the HTML, but no entry in the index.
# better than `extractFilename(changeFileExt(d.filename, ""))` as it disambiguates dups
title = $presentationPath(d.conf, AbsoluteFile d.filename, isTitle = true).changeFileExt("")
var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection")
let bodyname = if d.hasToc and not d.isPureRst:
groupsection.setLen 0
"doc.body_toc_group"
let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
elif d.hasToc: "doc.body_toc"
else: "doc.body_no_toc"
content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title",
"tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"],
"tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg"],
[title.rope, toc, d.modDesc, rope(getDateStr()),
rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile.AbsoluteFile, theindexFname.RelativeFile), groupsection.rope])
rope(getClockStr()), code, d.modDeprecationMsg])
if optCompileOnly notin d.conf.globalOptions:
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [
"nimdoccss", "dochackjs", "title", "tableofcontents", "moduledesc", "date", "time",
"nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics", "deprecationMsg"],
[relLink(d.conf.outDir, d.destFile.AbsoluteFile, nimdocOutCss.RelativeFile),
relLink(d.conf.outDir, d.destFile.AbsoluteFile, docHackJsFname.RelativeFile),
title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()),
[cssHref(d.conf.outDir, d.destFile), title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()),
content, d.meta[metaAuthor].rope, d.meta[metaVersion].rope, d.analytics.rope, d.modDeprecationMsg])
else:
code = content
@@ -1253,39 +1135,38 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope =
proc generateIndex*(d: PDoc) =
if optGenIndex in d.conf.globalOptions:
let dir = d.conf.outDir
let dir = d.conf.docOutDir(htmldocsDir)
createDir(dir)
let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt)
writeIndexFile(d[], dest.string)
proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
if d.module == nil or sfMainModule in d.module.flags: # nil for e.g. for commandRst2Html
if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html
if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.docOutDir
if d.conf.outFile.isEmpty:
d.conf.outFile = outfile.relativeTo(d.conf.outDir)
if isAbsolute(d.conf.outFile.string):
d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile
proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
proc writeOutput*(d: PDoc, useWarning = false) =
runAllExamples(d)
var content = genOutFile(d, groupedToc)
var content = genOutFile(d)
if optStdout in d.conf.globalOptions:
writeRope(stdout, content)
else:
template outfile: untyped = d.destFile.AbsoluteFile
#let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt)
template outfile: untyped = d.destFile
#let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, htmldocsDir)
let dir = outfile.splitFile.dir
createDir(dir)
updateOutfile(d, outfile)
if not writeRope(content, outfile):
rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile,
outfile.string)
elif not d.wroteSupportFiles: # nimdoc.css + dochack.js
let nimr = $d.conf.getPrefixDir()
copyFile(docCss.interp(nimr = nimr), $d.conf.outDir / nimdocOutCss)
if optGenIndex in d.conf.globalOptions:
let docHackJs2 = getDocHacksJs(nimr, nim = getAppFilename())
copyFile(docHackJs2, $d.conf.outDir / docHackJs2.lastPathPart)
d.wroteSupportFiles = true
elif not d.wroteCss:
let cssSource = $d.conf.getPrefixDir() / "doc" / "nimdoc.css"
let cssDest = $dir / nimdocOutCss
copyFile(cssSource, cssDest)
d.wroteCss = true
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
@@ -1300,20 +1181,18 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
write(stdout, $content)
else:
var f: File
if open(f, d.destFile, fmWrite):
if open(f, d.destFile.string, fmWrite):
write(f, $content)
close(f)
updateOutfile(d, d.destFile.AbsoluteFile)
updateOutfile(d, d.destFile)
else:
localError(d.conf, newLineInfo(d.conf, AbsoluteFile d.filename, -1, -1),
warnUser, "unable to open file \"" & d.destFile &
warnUser, "unable to open file \"" & d.destFile.string &
"\" for writing")
proc handleDocOutputOptions*(conf: ConfigRef) =
if optWholeProject in conf.globalOptions:
# Backward compatibility with previous versions
# xxx this is buggy when user provides `nim doc --project -o:sub/bar.html main`,
# it'd write to `sub/bar.html/main.html`
conf.outDir = AbsoluteDir(conf.outDir / conf.outFile)
proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
@@ -1388,20 +1267,18 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
if not writeRope(content, filename):
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
var content = mergeIndexes(dir).rope
proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
var content = mergeIndexes(conf.projectFull.string).rope
var outFile = outFile
if outFile.isEmpty: outFile = theindexFname.RelativeFile.changeFileExt("")
var outFile = RelativeFile"theindex"
if conf.outFile != RelativeFile"":
outFile = conf.outFile
let filename = getOutFile(conf, outFile, HtmlExt)
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), [
"nimdoccss", "dochackjs",
"title", "tableofcontents", "moduledesc", "date", "time",
"nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
[relLink(conf.outDir, filename, nimdocOutCss.RelativeFile),
relLink(conf.outDir, filename, docHackJsFname.RelativeFile),
rope"Index", nil, nil, rope(getDateStr()),
[cssHref(conf.outDir, filename), rope"Index", nil, nil, rope(getDateStr()),
rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available

View File

@@ -29,7 +29,6 @@ proc shouldProcess(g: PGen): bool =
template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
let groupedToc = true
if shouldProcess(g):
body
try:
@@ -39,7 +38,7 @@ template closeImpl(body: untyped) {.dirty.} =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
writeOutput(g.doc, useWarning)
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:

View File

@@ -17,8 +17,6 @@ when defined(windows):
const libcDll = "msvcrt.dll"
elif defined(linux):
const libcDll = "libc.so(.6|.5|)"
elif defined(openbsd):
const libcDll = "/usr/lib/libc.so(.95.1|)"
elif defined(bsd):
const libcDll = "/lib/libc.so.7"
elif defined(osx):
@@ -104,7 +102,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI =
case cc
of ccNimCall: result = DEFAULT_ABI
of ccDefault: result = DEFAULT_ABI
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:

View File

@@ -21,7 +21,6 @@ type
# new symbol
config: ConfigRef
ic: IdentCache
instID: int
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
@@ -54,8 +53,8 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
#if x.kind == skParam and x.owner.kind == skModule:
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
if sfGenSym in s.flags:
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions:
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
if c.instLines: actual.info else: templ.info)
else:
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
@@ -167,7 +166,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef;
ic: IdentCache; instID: ref int;
ic: IdentCache;
fromHlo=false): PNode =
inc(conf.evalTemplateCounter)
if conf.evalTemplateCounter > evalTemplateLimit:
@@ -182,7 +181,6 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.config = conf
ctx.ic = ic
initIdTable(ctx.mapping)
ctx.instID = instID[]
let body = tmpl.getBody
#echo "instantion of ", renderTree(body, {renderIds})
@@ -205,5 +203,3 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
#if ctx.debugActive:
# echo "instantion of ", renderTree(result, {renderIds})
dec(conf.evalTemplateCounter)
# The instID must be unique for every template instantiation, so we increment it here
inc instID[]

View File

@@ -143,16 +143,16 @@ compiler vcc:
result = (
name: "vcc",
objExt: "obj",
optSpeed: " /Ogityb2 ",
optSize: " /O1 ",
optSpeed: " /Ogityb2 /G7 ",
optSize: " /O1 /G7 ",
compilerExe: "cl",
cppCompiler: "cl",
compileTmpl: "/c$vccplatform $options $include /nologo /Fo$objfile $file",
buildGui: " /SUBSYSTEM:WINDOWS user32.lib ",
compileTmpl: "/c$vccplatform $options $include /Fo$objfile $file",
buildGui: " /link /SUBSYSTEM:WINDOWS ",
buildDll: " /LD",
buildLib: "lib /OUT:$libfile $objfiles",
linkerExe: "cl",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /nologo $options",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui $options",
includeCmd: " /I",
linkDirCmd: " /LIBPATH:",
linkLibCmd: " $1.lib",
@@ -170,7 +170,6 @@ compiler clangcl:
result.compilerExe = "clang-cl"
result.cppCompiler = "clang-cl"
result.linkerExe = "clang-cl"
result.linkTmpl = "-fuse-ld=lld " & result.linkTmpl
# Intel C/C++ Compiler
compiler icl:
@@ -186,6 +185,32 @@ compiler icc:
result.compilerExe = "icc"
result.linkerExe = "icc"
# Local C Compiler
compiler lcc:
result = (
name: "lcc",
objExt: "obj",
optSpeed: " -O -p6 ",
optSize: " -O -p6 ",
compilerExe: "lcc",
cppCompiler: "",
compileTmpl: "$options $include -Fo$objfile $file",
buildGui: " -subsystem windows",
buildDll: " -dll",
buildLib: "", # XXX: not supported yet
linkerExe: "lcclnk",
linkTmpl: "$options $buildgui $builddll -O $exefile $objfiles",
includeCmd: " -I",
linkDirCmd: "", # XXX: not supported yet
linkLibCmd: "", # XXX: not supported yet
debug: " -g5 ",
pic: "",
asmStmtFrmt: "_asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
produceAsm: "",
cppXsupport: "",
props: {})
# Borland C Compiler
compiler bcc:
result = (
@@ -213,6 +238,58 @@ compiler bcc:
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
hasAttribute})
# Digital Mars C Compiler
compiler dmc:
result = (
name: "dmc",
objExt: "obj",
optSpeed: " -ff -o -6 ",
optSize: " -ff -o -6 ",
compilerExe: "dmc",
cppCompiler: "",
compileTmpl: "-c $options $include -o$objfile $file",
buildGui: " -L/exet:nt/su:windows",
buildDll: " -WD",
buildLib: "", # XXX: not supported yet
linkerExe: "dmc",
linkTmpl: "$options $buildgui $builddll -o$exefile $objfiles",
includeCmd: " -I",
linkDirCmd: "", # XXX: not supported yet
linkLibCmd: "", # XXX: not supported yet
debug: " -g ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$3$n$1 $2",
produceAsm: "",
cppXsupport: "",
props: {hasCpp})
# Watcom C Compiler
compiler wcc:
result = (
name: "wcc",
objExt: "obj",
optSpeed: " -ox -on -6 -d0 -fp6 -zW ",
optSize: "",
compilerExe: "wcl386",
cppCompiler: "",
compileTmpl: "-c $options $include -fo=$objfile $file",
buildGui: " -bw",
buildDll: " -bd",
buildLib: "", # XXX: not supported yet
linkerExe: "wcl386",
linkTmpl: "$options $buildgui $builddll -fe=$exefile $objfiles ",
includeCmd: " -i=",
linkDirCmd: "", # XXX: not supported yet
linkLibCmd: "", # XXX: not supported yet
debug: " -d2 ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
produceAsm: "",
cppXsupport: "",
props: {hasCpp})
# Tiny C Compiler
compiler tcc:
result = (
@@ -239,16 +316,43 @@ compiler tcc:
cppXsupport: "",
props: {hasSwitchRange, hasComputedGoto, hasGnuAsm})
# Your C Compiler
compiler envcc:
# Pelles C Compiler
compiler pcc:
# Pelles C
result = (
name: "env",
name: "pcc",
objExt: "obj",
optSpeed: " -Ox ",
optSize: " -Os ",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $options $include -Fo$objfile $file",
buildGui: " -SUBSYSTEM:WINDOWS",
buildDll: " -DLL",
buildLib: "", # XXX: not supported yet
linkerExe: "cc",
linkTmpl: "$options $buildgui $builddll -OUT:$exefile $objfiles",
includeCmd: " -I",
linkDirCmd: "", # XXX: not supported yet
linkLibCmd: "", # XXX: not supported yet
debug: " -Zi ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
produceAsm: "",
cppXsupport: "",
props: {})
# Your C Compiler
compiler ucc:
result = (
name: "ucc",
objExt: "o",
optSpeed: " -O3 ",
optSize: " -O1 ",
compilerExe: "",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $ccenvflags $options $include -o $objfile $file",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "",
buildDll: " -shared ",
buildLib: "", # XXX: not supported yet
@@ -263,7 +367,7 @@ compiler envcc:
structStmtFmt: "$1 $2",
produceAsm: "",
cppXsupport: "",
props: {hasGnuAsm})
props: {})
const
CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
@@ -271,16 +375,23 @@ const
nintendoSwitchGCC(),
llvmGcc(),
clang(),
lcc(),
bcc(),
dmc(),
wcc(),
vcc(),
tcc(),
envcc(),
pcc(),
ucc(),
icl(),
icc(),
clangcl()]
hExt* = ".h"
proc libNameTmpl(conf: ConfigRef): string {.inline.} =
result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a"
proc nameToCC*(name: string): TSystemCC =
## Returns the kind of compiler referred to by `name`, or ccNone
## if the name doesn't refer to any known compiler.
@@ -303,14 +414,15 @@ proc isVSCompatible*(conf: ConfigRef): bool =
proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
# for niminst support
var fullSuffix = suffix
case conf.backend
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
of backendC: discard
of backendInvalid:
# during parsing of cfg files; we don't know the backend yet, no point in
# guessing wrong thing
return ""
let fullSuffix =
if conf.cmd == cmdCompileToCpp:
".cpp" & suffix
elif conf.cmd == cmdCompileToOC:
".objc" & suffix
elif conf.cmd == cmdCompileToJS:
".js" & suffix
else:
suffix
if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and
optCompileOnly notin conf.globalOptions:
@@ -331,7 +443,7 @@ proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
conf.linkOptions = ""
conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
for c in CC: undefSymbol(conf.symbols, c.name)
for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
proc addOpt(dest: var string, src: string) =
@@ -353,7 +465,7 @@ proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
proc initVars*(conf: ConfigRef) =
# we need to define the symbol here, because ``CC`` may have never been set!
for c in CC: undefSymbol(conf.symbols, c.name)
for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always"))
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
@@ -429,6 +541,7 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string =
result = conf.compileOptions
addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile))
for option in conf.compileOptionsCmd:
if strutils.find(result, option, 0) < 0:
@@ -449,8 +562,6 @@ proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string
let key = nimname & ".always"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile))
proc getCompileOptions(conf: ConfigRef): string =
result = cFileSpecificOptions(conf, "__dummy__", "__dummy__")
@@ -478,25 +589,13 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} =
(conf.target.hostOS == osWindows)
proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool =
conf.backend == backendCpp and not cfile.string.endsWith(".c")
proc envFlags(conf: ConfigRef): string =
result = if conf.backend == backendCpp:
getEnv("CXXFLAGS")
else:
getEnv("CFLAGS")
conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c")
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
if compiler == ccEnv:
result = if useCpp(conf, cfile):
getEnv("CXX")
else:
getEnv("CC")
else:
result = if useCpp(conf, cfile):
CC[compiler].cppCompiler
else:
CC[compiler].compilerExe
result = if useCpp(conf, cfile):
CC[compiler].cppCompiler
else:
CC[compiler].compilerExe
if result.len == 0:
rawMessage(conf, errGenerated,
"Compiler '$1' doesn't support the requested target" %
@@ -532,7 +631,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif optMixedMode in conf.globalOptions and conf.backend != backendCpp: CC[compiler].cppCompiler
elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: getCompilerExe(conf, compiler, AbsoluteFile"")
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
@@ -541,11 +640,6 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
# We produce files like module.nim.cpp, so the absolute Nim filename is not
# cfile.name but `cfile.cname.changeFileExt("")`:
var options = cFileSpecificOptions(conf, cfile.nimname, cfile.cname.changeFileExt("").string)
if useCpp(conf, cfile.cname):
# needs to be prepended so that --passc:-std=c++17 can override default.
# we could avoid allocation by making cFileSpecificOptions inplace
options = CC[c].cppXsupport & ' ' & options
var exe = getConfigVar(conf, c, ".exe")
if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
@@ -554,6 +648,9 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
ospNeedsPIC in platform.OS[conf.target.targetOS].props:
options.add(' ' & CC[c].pic)
if useCpp(conf, cfile.cname):
options.add(' ' & CC[c].cppXsupport)
if cfile.customArgs != "":
options.add ' '
options.add cfile.customArgs
@@ -594,8 +691,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
"dfile", dfile,
"file", cfsh, "objfile", quoteShell(objfile), "options", options,
"include", includeCmd, "nim", getPrefixDir(conf).string,
"lib", conf.libpath.string,
"ccenvflags", envFlags(conf)])
"lib", conf.libpath.string])
if optProduceAsm in conf.globalOptions:
if CC[conf.cCompiler].produceAsm.len > 0:
@@ -615,8 +711,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
"options", options, "include", includeCmd,
"nim", quoteShell(getPrefixDir(conf)),
"lib", quoteShell(conf.libpath),
"vccplatform", vccplatform(conf),
"ccenvflags", envFlags(conf)])
"vccplatform", vccplatform(conf)])
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
result = secureHash(
@@ -627,7 +722,8 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
getCompileCFileCmd(conf, cfile))
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good
if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM, cmdNone}:
return false
var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
var currentHash = footprint(conf, cfile)
@@ -662,7 +758,14 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) =
proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
objfiles: string, isDllBuild: bool): string =
if optGenStaticLib in conf.globalOptions:
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output),
var libname: string
if not conf.outFile.isEmpty:
libname = conf.outFile.string.expandTilde
if not libname.isAbsolute():
libname = getCurrentDir() / libname
else:
libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname),
"objfiles", objfiles]
else:
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
@@ -759,16 +862,19 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
(ose.msg & " " & $ose.errorCode))
raise
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
when defined(macosx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
result.add "dsymutil " & $(output).quoteShell
proc execLinkCmd(conf: ConfigRef; linkCmd: string) =
tryExceptOSErrorMessage(conf, "invocation of external linker program failed."):
execExternalProgram(conf, linkCmd, hintLinking)
proc maybeRunDsymutil(conf: ConfigRef; exe: AbsoluteFile) =
when defined(osx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
let cmd = "dsymutil " & $(exe).quoteShell
conf.extraCmds.add cmd
tryExceptOSErrorMessage(conf, "invocation of dsymutil failed."):
execExternalProgram(conf, cmd, hintExecuting)
proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) =
let runCb = proc (idx: int, p: Process) =
let exitCode = p.peekExitCode
@@ -839,7 +945,6 @@ proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string
extraCmds: seq[string]
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
@@ -910,7 +1015,6 @@ proc callCCompiler*(conf: ConfigRef) =
let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput
else: AbsoluteFile(conf.projectName)
linkCmd = getLinkCmd(conf, mainOutput, objfiles)
extraCmds = getExtraCmds(conf, mainOutput)
if optCompileOnly notin conf.globalOptions:
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
if linkCmd.len > MaxCmdLen:
@@ -920,8 +1024,7 @@ proc callCCompiler*(conf: ConfigRef) =
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd)
for cmd in extraCmds:
execExternalProgram(conf, cmd, hintExecuting)
maybeRunDsymutil(conf, mainOutput)
else:
linkCmd = ""
if optGenScript in conf.globalOptions:
@@ -995,16 +1098,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
var buf = newStringOfCap(50)
let jsonFile = conf.getNimcacheDir / RelativeFile(conf.projectName & ".json")
conf.jsonBuildFile = jsonFile
let output = conf.absOutFile
var f: File
if open(f, jsonFile.string, fmWrite):
lit "{\L"
lit "\"outputFile\": "
str $output
lit ",\L\"compile\":[\L"
lit "{\"compile\":[\L"
cfiles(conf, f, buf, conf.toCompile, false)
lit "],\L\"link\":[\L"
var objfiles = ""
@@ -1012,10 +1109,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink)
lit "],\L\"linkcmd\": "
str getLinkCmd(conf, output, objfiles)
str getLinkCmd(conf, conf.absOutFile, objfiles)
lit ",\L\"extraCmds\": "
lit $(%* getExtraCmds(conf, conf.absOutFile))
lit $(%* conf.extraCmds)
lit ",\L\"stdinInput\": "
lit $(%* conf.projectIsStdin)
@@ -1072,17 +1169,6 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
let jsonFile = toGeneratedFile(conf, projectfile, "json")
try:
let data = json.parseFile(jsonFile.string)
let output = data["outputFile"].getStr
createDir output.parentDir
let outputCurrent = $conf.absOutFile
if output != outputCurrent:
# previously, any specified output file would be silently ignored;
# simply copying won't work in some cases, for example with `extraCmds`,
# so we just make it an error, user should use same command for jsonscript
# as was used with --compileOnly.
globalError(conf, gCmdLineInfo, "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % [outputCurrent, output, jsonFile.string])
let toCompile = data["compile"]
doAssert toCompile.kind == JArray
var cmds: TStringSeq

View File

@@ -199,8 +199,8 @@ proc parseLine(p: var TTmplParser) =
inc(j)
llStreamWrite(p.outp, "\\n\"")
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile,
call: PNode; conf: ConfigRef): PLLStream =
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
@@ -214,9 +214,9 @@ proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line
p.info.line = p.info.line + 1'u16
while llStreamReadLine(p.inp, p.x):
inc p.info.line
p.info.line = p.info.line + 1'u16
parseLine(p)
newLine(p)
result = p.outp

89
compiler/forloops.nim Normal file
View File

@@ -0,0 +1,89 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements for loop detection for better C code generation.
import ast, astalgo
const
someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
mLeI, mLeF64, mLeU, mLeEnum,
mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtEnum,
mLtCh, mLtB, mLtPtr}
proc isCounter(s: PSym): bool {.inline.} =
s.kind in {skResult, skVar, skLet, skTemp} and
{sfGlobal, sfAddrTaken} * s.flags == {}
proc isCall(n: PNode): bool {.inline.} =
n.kind in nkCallKinds and n[0].kind == nkSym
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
proc getCounter(lastStmt: PNode): PSym =
if lastStmt.isCall:
let op = lastStmt.sym
if op.magic in {mDec, mInc} or
((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
if op[1].kind == nkSym and isCounter(op[1].sym):
result = op[1].sym
proc counterInTree(n, loop: PNode; counter: PSym): bool =
# prune the search tree: within the loop the counter may be used:
if n == loop: return
case n.kind
of nkSym:
if n.sym == counter: return true
of nkVarSection, nkLetSection:
# definitions are fine!
for it in n:
if counterInTree(it.lastSon): return true
else:
for i in 0..<n.safeLen:
if counterInTree(n[i], loop, counter): return true
proc copyExcept(n: PNode, x, dest: PNode) =
if x == n: return
if n.kind in {nkStmtList, nkStmtListExpr}:
for i in 0..<n.len: copyExcept(n[i], x, dest)
else:
dest.add n
type
ForLoop* = object
counter*: PSym
init*, cond*, increment*, body*: PNode
proc extractForLoop*(loop, fullTree: PNode): ForLoop =
## returns 'counter == nil' if the while loop 'n' is not a for loop:
assert loop.kind == nkWhileStmt
let cond == loop[0]
if not cond.isCall: return
if cond[0].sym.magic notin someCmp: return
var lastStmt = loop[1]
while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
lastStmt = lastStmt.lastSon
let counter = getCounter(lastStmt)
if counter.isNil or counter.ast.isNil: return
template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
if cond[1] =~ counter or cond[2] =~ counter:
# ok, now check 'counter' is not used *after* the loop
if counterInTree(fullTree, loop, counter): return
# ok, success, fill in the fields:
result.counter = counter
result.init = counter.ast
result.cond = cond
result.increment = lastStmt
result.body = newNodeI(nkStmtList, loop[1].info)
copyExcept(loop[1], lastStmt, result.body)

View File

@@ -46,7 +46,7 @@ proc isLet(n: PNode): bool =
if n.sym.kind in {skLet, skTemp, skForVar}:
result = true
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
abstractInst).kind notin {tyVar}:
abstractInst).kind != tyVar:
result = true
proc isVar(n: PNode): bool =
@@ -84,8 +84,8 @@ proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
type
Operators* = object
opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym
opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym
opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym
opAdd, opSub, opMul, opDiv, opLen: PSym
proc initOperators*(g: ModuleGraph): Operators =
result.opLe = createMagic(g, "<=", mLeI)
@@ -156,12 +156,12 @@ proc neg(n: PNode; o: Operators): PNode =
result[0] = newSymNode(o.opNot)
result[1] = n
proc buildCall*(op: PSym; a: PNode): PNode =
proc buildCall(op: PSym; a: PNode): PNode =
result = newNodeI(nkCall, a.info, 2)
result[0] = newSymNode(op)
result[1] = a
proc buildCall*(op: PSym; a, b: PNode): PNode =
proc buildCall(op: PSym; a, b: PNode): PNode =
result = newNodeI(nkInfix, a.info, 3)
result[0] = newSymNode(op)
result[1] = a
@@ -464,7 +464,7 @@ proc hasSubTree(n, x: PNode): bool =
for i in 0..n.safeLen-1:
if hasSubTree(n[i], x): return true
proc invalidateFacts*(s: var seq[PNode], n: PNode) =
proc invalidateFacts*(m: var TModel, n: PNode) =
# We are able to guard local vars (as opposed to 'let' variables)!
# 'while p != nil: f(p); p = p.next'
# This is actually quite easy to do:
@@ -482,11 +482,8 @@ proc invalidateFacts*(s: var seq[PNode], n: PNode) =
# The same mechanism could be used for more complex data stored on the heap;
# procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
# could CSE these expressions then and help C's optimizer.
for i in 0..high(s):
if s[i] != nil and s[i].hasSubTree(n): s[i] = nil
proc invalidateFacts*(m: var TModel, n: PNode) =
invalidateFacts(m.s, n)
for i in 0..high(m.s):
if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:

View File

@@ -110,8 +110,8 @@ proc newIdentCache*(): IdentCache =
result.idDelegator = result.getIdent":delegator"
result.emptyIdent = result.getIdent("")
# initialize the keywords:
for s in succ(low(TSpecialWord))..high(TSpecialWord):
result.getIdent($s, hashIgnoreStyle($s)).id = ord(s)
for s in succ(low(specialWords))..high(specialWords):
result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
proc whichKeyword*(id: PIdent): TSpecialWord =
if id.id < 0: result = wInvalid

View File

@@ -187,9 +187,10 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let it = transformImportAs(c, it)
let m = myImportModule(c, it, importStmtResult)
if m != nil:
var emptySet: IntSet
# ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m, it.info) # add symbol to symbol table of module
importAllSymbols(c, m)
importAllSymbolsExcept(c, m, emptySet)
#importForwarded(c, m.ast, emptySet, m)
proc evalImport*(c: PContext, n: PNode): PNode =

View File

@@ -1,18 +0,0 @@
##[
This module only exists to generate docs for the compiler.
## links
* [main docs](../lib.html)
* [compiler user guide](../nimc.html)
* [Internals of the Nim Compiler](../intern.html)
]##
#[
note: this is named `index` so that navigating to https://nim-lang.github.io/Nim/compiler/
will work.
xxx this should also import other modules, not transitively imported by `compiler/nim.nim`,
eg `evalffi`, otherwise these aren't shown. A glob could be used at CT.
]#
import nim

File diff suppressed because it is too large Load Diff

View File

@@ -35,8 +35,9 @@ App: Console
License: "copying.txt"
[Config]
Files: "config/*.cfg"
Files: "config/config.nims"
Files: "config/nim.cfg"
Files: "config/nimdoc.cfg"
Files: "config/nimdoc.tex.cfg"
[Documentation]
; Files: "doc/*.html"

View File

@@ -373,8 +373,8 @@ proc `*`*(lhs,rhs: Int128): Int128 =
let b00 = cast[uint64](rhs.udata[0])
result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00)
result += toInt128(a32 * b00) shl 32
result += toInt128(a00 * b32) shl 32
result = result + toInt128(a32 * b00) shl 32
result = result + toInt128(a00 * b32) shl 32
proc `*=`*(a: var Int128, b: Int128) =
a = a * b
@@ -427,7 +427,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
for i in 0..shift:
quotient = quotient shl 1
if dividend >= denominator:
dividend -= denominator
dividend = dividend - denominator
quotient = bitor(quotient, One)
denominator = denominator shr 1
@@ -592,3 +592,190 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
return maskUInt64(arg)
else:
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")
when isMainModule:
let (a,b) = divMod(Ten,Ten)
doAssert $One == "1"
doAssert $Ten == "10"
doAssert $Zero == "0"
let c = parseDecimalInt128("12345678989876543210123456789")
doAssert $c == "12345678989876543210123456789"
var d : array[39, Int128]
d[0] = parseDecimalInt128("1")
d[1] = parseDecimalInt128("10")
d[2] = parseDecimalInt128("100")
d[3] = parseDecimalInt128("1000")
d[4] = parseDecimalInt128("10000")
d[5] = parseDecimalInt128("100000")
d[6] = parseDecimalInt128("1000000")
d[7] = parseDecimalInt128("10000000")
d[8] = parseDecimalInt128("100000000")
d[9] = parseDecimalInt128("1000000000")
d[10] = parseDecimalInt128("10000000000")
d[11] = parseDecimalInt128("100000000000")
d[12] = parseDecimalInt128("1000000000000")
d[13] = parseDecimalInt128("10000000000000")
d[14] = parseDecimalInt128("100000000000000")
d[15] = parseDecimalInt128("1000000000000000")
d[16] = parseDecimalInt128("10000000000000000")
d[17] = parseDecimalInt128("100000000000000000")
d[18] = parseDecimalInt128("1000000000000000000")
d[19] = parseDecimalInt128("10000000000000000000")
d[20] = parseDecimalInt128("100000000000000000000")
d[21] = parseDecimalInt128("1000000000000000000000")
d[22] = parseDecimalInt128("10000000000000000000000")
d[23] = parseDecimalInt128("100000000000000000000000")
d[24] = parseDecimalInt128("1000000000000000000000000")
d[25] = parseDecimalInt128("10000000000000000000000000")
d[26] = parseDecimalInt128("100000000000000000000000000")
d[27] = parseDecimalInt128("1000000000000000000000000000")
d[28] = parseDecimalInt128("10000000000000000000000000000")
d[29] = parseDecimalInt128("100000000000000000000000000000")
d[30] = parseDecimalInt128("1000000000000000000000000000000")
d[31] = parseDecimalInt128("10000000000000000000000000000000")
d[32] = parseDecimalInt128("100000000000000000000000000000000")
d[33] = parseDecimalInt128("1000000000000000000000000000000000")
d[34] = parseDecimalInt128("10000000000000000000000000000000000")
d[35] = parseDecimalInt128("100000000000000000000000000000000000")
d[36] = parseDecimalInt128("1000000000000000000000000000000000000")
d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
for i in 0..<d.len:
for j in 0..<d.len:
doAssert(cmp(d[i], d[j]) == cmp(i,j))
if i + j < d.len:
doAssert d[i] * d[j] == d[i+j]
if i - j >= 0:
doAssert d[i] div d[j] == d[i-j]
var sum: Int128
for it in d:
sum += it
doAssert $sum == "111111111111111111111111111111111111111"
for it in d.mitems:
it = -it
for i in 0..<d.len:
for j in 0..<d.len:
doAssert(cmp(d[i], d[j]) == -cmp(i,j))
if i + j < d.len:
doAssert d[i] * d[j] == -d[i+j]
if i - j >= 0:
doAssert d[i] div d[j] == -d[i-j]
doAssert $high(Int128) == "170141183460469231731687303715884105727"
doAssert $low(Int128) == "-170141183460469231731687303715884105728"
var ma = 100'i64
var mb = 13
doAssert toInt128(ma) * toInt128(0) == toInt128(0)
doAssert toInt128(-ma) * toInt128(0) == toInt128(0)
# sign correctness
doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb))
doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb))
doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb))
doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb))
doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb))
doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb))
doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb))
doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb))
doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma))
doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma))
doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma))
doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma))
let e = parseDecimalInt128("70997106675279150998592376708984375")
let strArray = [
# toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3)
"000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6",
"0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc",
"00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd",
"000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d",
"0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23",
"00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2",
"000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b",
"0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864",
"00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186",
"000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018",
"0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601",
"00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60",
"000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6",
"0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e",
"00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46",
"000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4",
"0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd",
"00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c",
"000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4",
"0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a",
"00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05",
"000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0",
"0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf",
"00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da",
"000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d",
"0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58",
"00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5",
"000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b",
"0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001",
"00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
"00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
"00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
]
for i in 0 ..< 128:
let str1 = toHex(e shr i)
let str2 = strArray[i]
doAssert str1 == str2
let strArray2 = [
"000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8",
"00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80",
"0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800",
"dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000",
"ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000",
"c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000",
"6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000",
"d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000",
"782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000",
"82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000",
"2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000",
"d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000",
"266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000",
"66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000",
"6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000",
"a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000",
"37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000",
"7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000",
"300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000",
"00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000",
"0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000",
"c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000",
"32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000",
"2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000",
"591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000",
"91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000",
"1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000",
"eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000",
"ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000",
"e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000",
"37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000",
"70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000",
]
for i in 0 ..< 128:
let str1 = toHex(e shl i)
let str2 = strArray2[i]
doAssert str1 == str2

View File

@@ -1,126 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implementation of the check that `recover` needs, see
## https://github.com/nim-lang/RFCs/issues/244 for more details.
import
ast, types, renderer, idents, intsets
proc canAlias(arg, ret: PType; marker: var IntSet): bool
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
case n.kind
of nkRecList:
for i in 0..<n.len:
result = canAliasN(arg, n[i], marker)
if result: return
of nkRecCase:
assert(n[0].kind == nkSym)
result = canAliasN(arg, n[0], marker)
if result: return
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
result = canAliasN(arg, lastSon(n[i]), marker)
if result: return
else: discard
of nkSym:
result = canAlias(arg, n.sym.typ, marker)
else: discard
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
if containsOrIncl(marker, ret.id):
return false
if ret.kind in {tyPtr, tyPointer}:
# unsafe so we don't care:
return false
if compareTypes(arg, ret, dcEqIgnoreDistinct):
return true
case ret.kind
of tyObject:
if isFinal(ret):
result = canAliasN(arg, ret.n, marker)
if not result and ret.len > 0 and ret[0] != nil:
result = canAlias(arg, ret[0], marker)
else:
result = true
of tyTuple:
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
of tyArray, tySequence, tyDistinct, tyGenericInst,
tyAlias, tyInferred, tySink, tyLent, tyOwned, tyRef:
result = canAlias(arg, ret.lastSon, marker)
of tyProc:
result = ret.callConv == ccClosure
else:
result = false
proc isValueOnlyType(t: PType): bool =
# t doesn't contain pointers and references
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent}
result = not types.searchTypeFor(t, wrap)
proc canAlias*(arg, ret: PType): bool =
if isValueOnlyType(arg):
# can alias only with unsafeAddr(arg.x) and we don't care if it is not safe
result = false
else:
var marker = initIntSet()
result = canAlias(arg, ret, marker)
proc checkIsolate*(n: PNode): bool =
if types.containsTyRef(n.typ):
# XXX Maybe require that 'n.typ' is acyclic. This is not much
# worse than the already exisiting inheritance and closure restrictions.
case n.kind
of nkCharLit..nkNilLit:
result = true
of nkCallKinds:
if n[0].typ.flags * {tfGcSafe, tfNoSideEffect} == {}:
return false
for i in 1..<n.len:
if checkIsolate(n[i]):
discard "fine, it is isolated already"
else:
let argType = n[i].typ
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
if argType.canAlias(n.typ):
return false
result = true
of nkIfStmt, nkIfExpr:
for it in n:
result = checkIsolate(it.lastSon)
if not result: break
of nkCaseStmt, nkObjConstr:
for i in 1..<n.len:
result = checkIsolate(n[i].lastSon)
if not result: break
of nkBracket, nkTupleConstr, nkPar:
for it in n:
result = checkIsolate(it)
if not result: break
of nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv:
result = checkIsolate(n[1])
of nkObjUpConv, nkObjDownConv, nkDotExpr:
result = checkIsolate(n[0])
of nkStmtList, nkStmtListExpr:
if n.len > 0:
result = checkIsolate(n[^1])
else:
result = false
else:
# unanalysable expression:
result = false
else:
# no ref, no cry:
result = true

View File

@@ -14,28 +14,27 @@ The JS code generator contains only 2 tricks:
Trick 1
-------
Some locations (for example 'var int') require "fat pointers" (`etyBaseIndex`)
Some locations (for example 'var int') require "fat pointers" (``etyBaseIndex``)
which are pairs (array, index). The derefence operation is then 'array[index]'.
Check `mapType` for the details.
Check ``mapType`` for the details.
Trick 2
-------
It is preferable to generate '||' and '&&' if possible since that is more
idiomatic and hence should be friendlier for the JS JIT implementation. However
code like `foo and (let bar = baz())` cannot be translated this way. Instead
the expressions need to be transformed into statements. `isSimpleExpr`
code like ``foo and (let bar = baz())`` cannot be translated this way. Instead
the expressions need to be transformed into statements. ``isSimpleExpr``
implements the required case distinction.
"""
import
ast, trees, magicsys, options,
nversion, msgs, idents, types,
ropes, passes, ccgutils, wordrecg, renderer,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap
ast, strutils, trees, magicsys, options,
nversion, msgs, idents, types, tables,
ropes, math, passes, ccgutils, wordrecg, renderer,
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap, json, sets
import json, sets, math, tables, intsets, strutils
from modulegraphs import ModuleGraph, PPassContext
@@ -87,7 +86,6 @@ type
generatedSyms: IntSet
typeInfoGenerated: IntSet
unique: int # for temp identifier generation
inSystem: bool
PProc = ref TProc
TProc = object
@@ -161,14 +159,6 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
extraIndent: int(procDef != nil))
if procDef != nil: result.prc = procDef[namePos].sym
proc initProcOptions(module: BModule): TOptions =
result = module.config.options
if PGlobals(module.graph.backend).inSystem:
result.excl(optStackTrace)
proc newInitProc(globals: PGlobals, module: BModule): PProc =
result = newProc(globals, module, nil, initProcOptions(module))
proc declareGlobal(p: PProc; id: int; r: Rope) =
if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
p.locals.addf("global $1;$n", [r])
@@ -194,7 +184,7 @@ proc mapType(typ: PType): TJSTypeKind =
of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table
of tyString, tySequence: result = etySeq
of tyString, tySequence, tyOpt: result = etySeq
of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs, tyUncheckedArray:
result = etyObject
of tyNil: result = etyNull
@@ -211,11 +201,12 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone
of tyProc: result = etyProc
of tyCString: result = etyString
of tyOptDeprecated: doAssert false
proc mapType(p: PProc; typ: PType): TJSTypeKind =
result = mapType(typ)
var mangled = initSet[string]()
proc mangleName(m: BModule, s: PSym): Rope =
proc validJsName(name: string): bool =
result = true
@@ -249,7 +240,11 @@ proc mangleName(m: BModule, s: PSym): Rope =
while i < s.name.s.len:
let c = s.name.s[i]
case c
of 'A'..'Z', 'a'..'z', '_', '0'..'9':
of 'A'..'Z':
if i > 0 and s.name.s[i-1] in {'a'..'z'}:
x.add '_'
x.add(chr(c.ord - 'A'.ord + 'a'.ord))
of 'a'..'z', '_', '0'..'9':
x.add c
else:
x.add("HEX" & toHex(ord(c), 2))
@@ -266,6 +261,11 @@ proc mangleName(m: BModule, s: PSym): Rope =
result.add(rope(s.id))
s.loc.r = result
# TODO: optimize
let s = $result
if '_' in s:
mangled.incl(s)
proc escapeJSString(s: string): string =
result = newStringOfCap(s.len + s.len shr 2)
result.add("\"")
@@ -466,48 +466,7 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
else:
(a: a, tmp: b)
proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
var
a = x.rdLoc
b = a
if needsTemp(p, n):
# if we have tmp just use it
if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
b = "$1[0][$1[1]]" % [x.tmpLoc]
result = (a: a, tmp: b)
elif x.tmpLoc != nil and n.kind == nkBracketExpr:
# genArrayAddr
var
address, index: TCompRes
first: Int128
gen(p, n[0], address)
gen(p, n[1], index)
let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
let typ = skipTypes(n[0].typ, abstractPtrs)
if typ.kind == tyArray:
first = firstOrd(p.config, typ[0])
if optBoundsCheck in p.options:
useMagic(p, "chckIndx")
if first == 0: # save a couple chars
index.res = "chckIndx($1, 0, ($2).length-1)" % [index.res, tmp1]
else:
index.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [
index.res, rope(first), tmp1]
elif first != 0:
index.res = "($1)-($2)" % [index.res, rope(first)]
else:
discard # index.res = index.res
let (n1, tmp2) = maybeMakeTemp(p, n[1], index)
result = (a: "$1[$2]" % [m1, n1], tmp: "$1[$2]" % [tmp1, tmp2])
# could also put here: nkDotExpr -> genFieldAccess, nkCheckedFieldExpr -> genCheckedFieldOp
# but the uses of maybeMakeTempAssignable don't need them
else:
result = (a: a, tmp: b)
else:
result = (a: a, tmp: b)
template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
reassign = false) =
template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
# $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
# if $3 or $4 are present they will be substituted with temps for
# lhs and rhs respectively
@@ -519,11 +478,8 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
var
a, tmp = x.rdLoc
b, tmp2 = y.rdLoc
when reassign:
(a, tmp) = maybeMakeTempAssignable(p, n[1], x)
else:
when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y)
when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y)
r.res = frmt % [a, b, tmp, tmp2]
r.kind = resExpr
@@ -540,13 +496,13 @@ template unsignedTrimmer(size: BiggestInt): Rope =
size.unsignedTrimmerJS
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
reassign: static[bool] = false) =
reassign = false) =
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
when reassign:
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
if reassign:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
else:
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
@@ -585,10 +541,11 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
gen(p, n[1], r)
xLoc = r.rdLoc
template applyFormat(frmt) =
r.res = frmt % [xLoc, yLoc]
template applyFormat(frmtA, frmtB) =
if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
template applyFormat(frmtA, frmtB: string) =
if i == 0:
r.res = frmtA % [xLoc, yLoc]
else:
r.res = frmtB % [xLoc, yLoc]
case op:
of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
@@ -603,16 +560,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
of mShrI: applyFormat("", "")
of mShlI:
if n[1].typ.size <= 4:
applyFormat("($1 << $2)", "($1 << $2)")
else:
applyFormat("($1 * Math.pow(2,$2))", "($1 * Math.pow(2,$2))")
of mAshrI:
if n[1].typ.size <= 4:
applyFormat("($1 >> $2)", "($1 >> $2)")
else:
applyFormat("Math.floor($1 / Math.pow(2,$2))", "Math.floor($1 / Math.pow(2,$2))")
of mShlI: applyFormat("($1 << $2)", "($1 << $2)")
of mAshrI: applyFormat("($1 >> $2)", "($1 >> $2)")
of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
@@ -658,11 +607,9 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
of mInt64ToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
of mFloatToStr:
useMagic(p, "nimFloatToString")
applyFormat "cstrToNimstr(nimFloatToString($1))"
of mFloatToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1")
of mStrToStr, mUnown: applyFormat("$1", "$1")
else:
assert false, $op
@@ -866,7 +813,6 @@ proc genRaiseStmt(p: PProc, n: PNode) =
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var
cond, stmt: TCompRes
totalRange = 0
genLineDir(p, n)
gen(p, n[0], cond)
let stringSwitch = skipTypes(n[0].typ, abstractVar).kind == tyString
@@ -886,10 +832,6 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
let e = it[j]
if e.kind == nkRange:
var v = copyNode(e[0])
inc(totalRange, int(e[1].intVal - v.intVal))
if totalRange > 65535:
localError(p.config, n.info,
"Your case statement contains too many branches, consider using if/else instead!")
while v.intVal <= e[1].intVal:
gen(p, v, cond)
lineF(p, "case $1:$n", [cond.rdLoc])
@@ -1050,17 +992,13 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes
var xtyp = mapType(p, x.typ)
# disable `[]=` for cstring
if x.kind == nkBracketExpr and x.len >= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCString:
localError(p.config, x.info, "cstring doesn't support `[]=` operator")
gen(p, x, a)
genLineDir(p, y)
gen(p, y, b)
# we don't care if it's an etyBaseIndex (global) of a string, it's
# still a string that needs to be copied properly:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}:
xtyp = etySeq
case xtyp
of etySeq:
@@ -1071,7 +1009,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
of etyObject:
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
if x.typ.kind == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
@@ -1084,15 +1022,8 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
elif b.typ == etyBaseIndex:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
elif b.typ == etyNone:
internalAssert p.config, b.address == nil
lineF(p, "$# = [$#, 0];$n", [a.address, b.res])
elif x.typ.kind == tyVar and y.typ.kind == tyPtr:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
lineF(p, "$1 = $2;$n", [a.address, b.res])
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
internalError(p.config, x.info, "genAsgn")
else:
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
@@ -1109,7 +1040,7 @@ proc genFastAsgn(p: PProc, n: PNode) =
# See bug #5933. So we try to be more compatible with the C backend semantics
# here for 'shallowCopy'. This is an educated guess and might require further
# changes later:
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
@@ -1210,7 +1141,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
useMagic(p, "raiseFieldError")
useMagic(p, "makeNimstrLit")
let msg = genFieldDefect(field, disc)
let msg = genFieldError(field, disc)
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n",
setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===",
makeJSString(msg))
@@ -1240,13 +1171,9 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
first = firstOrd(p.config, typ[0])
if optBoundsCheck in p.options:
useMagic(p, "chckIndx")
if first == 0: # save a couple chars
r.res = "chckIndx($1, 0, ($2).length-1)" % [b.res, tmp]
else:
r.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [
b.res, rope(first), tmp]
r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp]
elif first != 0:
r.res = "($1)-($2)" % [b.res, rope(first)]
r.res = "($1)-$2" % [b.res, rope(first)]
else:
r.res = b.res
r.kind = resExpr
@@ -1292,10 +1219,6 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
let s = n[0].sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
case s.kind
of skParam:
r.res = s.loc.r
r.address = nil
r.typ = etyNone
of skVar, skLet, skResult:
r.kind = resExpr
let jsType = mapType(p, n.typ)
@@ -1317,7 +1240,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
# 'var openArray' for instance produces an 'addr' but this is harmless:
gen(p, n[0], r)
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
else: internalError(p.config, n.info, "genAddr: 2")
of nkCheckedFieldExpr:
genCheckedFieldOp(p, n[0], n.typ, r)
of nkDotExpr:
@@ -1340,21 +1263,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
gen(p, n[0], r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkStmtListExpr:
if n.len == 1: gen(p, n[0], r)
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
of nkCallKinds:
if n[0].typ.kind == tyOpenArray:
# 'var openArray' for instance produces an 'addr' but this is harmless:
# namely toOpenArray(a, 1, 3)
gen(p, n[0], r)
else:
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
else:
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
gen(p, n[0][0], r)
else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
proc attachProc(p: PProc; content: Rope; s: PSym) =
p.g.code.add(content)
@@ -1427,7 +1337,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
s.name.s)
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
if lfNoDecl in s.loc.flags or s.magic != mNone or
{sfImportc, sfInfixCall} * s.flags != {}:
discard
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
@@ -1734,9 +1644,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("[null, 0]", indirect)
else:
result = putToSeq("null", indirect)
of tySequence, tyString:
result = putToSeq("[]", indirect)
of tyCString, tyProc:
of tySequence, tyOpt, tyString, tyCString, tyProc:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
@@ -1757,7 +1665,6 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
varCode: string
varName = mangleName(p.module, v)
useReloadingGuard = sfGlobal in v.flags and p.config.hcrOn
useGlobalPragmas = sfGlobal in v.flags and ({sfPure, sfThread} * v.flags != {})
if v.constraint.isNil:
if useReloadingGuard:
@@ -1765,10 +1672,6 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
lineF(p, "if ($1 === undefined) {$n", varName)
varCode = $varName
inc p.extraIndent
elif useGlobalPragmas:
lineF(p, "if (globalThis.$1 === undefined) {$n", varName)
varCode = $varName
inc p.extraIndent
else:
varCode = "var $2"
else:
@@ -1821,7 +1724,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
else:
line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s]))
if useReloadingGuard or useGlobalPragmas:
if useReloadingGuard:
dec p.extraIndent
lineF(p, "}$n")
@@ -1873,7 +1776,7 @@ proc genNewSeq(p: PProc, n: PNode) =
x.rdLoc, y.rdLoc, createVar(p, t, false)])
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
case skipTypes(n[1].typ, abstractVar + abstractRange).kind
case skipTypes(n[1].typ, abstractVar).kind
of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r)
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)")
else: internalError(p.config, n.info, "genOrd")
@@ -1948,7 +1851,6 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
genReprAux(p, n, r, "reprJSONStringify")
else:
genReprAux(p, n, r, "reprAny", genTypeInfo(p, t))
r.kind = resExpr
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
var x: TCompRes
@@ -1973,7 +1875,7 @@ proc genReset(p: PProc, n: PNode) =
if x.typ == etyBaseIndex:
lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
else:
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
let (a, tmp) = maybeMakeTemp(p, n[1], x)
lineF(p, "$1 = genericReset($3, $2);$n", [a,
genTypeInfo(p, n[1].typ), tmp])
@@ -1999,35 +1901,37 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mSwap: genSwap(p, n)
of mAppendStrCh:
binaryExpr(p, n, r, "addChar",
"addChar($1, $2);")
"if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }")
of mAppendStrStr:
var lhs, rhs: TCompRes
gen(p, n[1], lhs)
gen(p, n[2], rhs)
let rhsIsLit = n[2].kind in nkStrKinds
let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
if skipTypes(n[1].typ, abstractVarRange).kind == tyCString:
let (b, tmp) = maybeMakeTemp(p, n[2], rhs)
r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" %
[b, lhs.rdLoc, tmp]
r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [
a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
else:
let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [
lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
r.kind = resExpr
of mAppendSeqElem:
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let (a, tmp) = maybeMakeTemp(p, n[1], x)
if mapType(n[2].typ) == etyBaseIndex:
let c = "[$1, $2]" % [y.address, y.res]
r.res = "$1.push($2);" % [x.rdLoc, c]
r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
elif needsNoCopy(p, n[2]):
r.res = "$1.push($2);" % [x.rdLoc, y.rdLoc]
r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, y.rdLoc, tmp]
else:
useMagic(p, "nimCopy")
let c = getTemp(p, defineInLocals=false)
lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
[c, y.rdLoc, genTypeInfo(p, n[2].typ)])
r.res = "$1.push($2);" % [x.rdLoc, c]
r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
r.kind = resExpr
of mConStrStr:
genConStrStr(p, n, r)
@@ -2059,37 +1963,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mDestroy: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
var x: TCompRes
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCString:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp]
else:
r.res = "($1).length" % [x.rdLoc]
r.kind = resExpr
unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)")
of mHigh:
var x: TCompRes
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCString:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp]
else:
r.res = "($1).length - 1" % [x.rdLoc]
r.kind = resExpr
unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)")
of mInc:
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
binaryUintExpr(p, n, r, "+", true)
else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true)
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)")
of ast.mDec:
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
binaryUintExpr(p, n, r, "-", true)
else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)")
of mSetLengthStr:
binaryExpr(p, n, r, "mnewString", "($1.length = $2)")
binaryExpr(p, n, r, "mnewString", "($1 == null ? $3 = mnewString($2) : $3.length = $2)")
of mSetLengthSeq:
var x, y: TCompRes
gen(p, n[1], x)
@@ -2097,7 +1987,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
let t = skipTypes(n[1].typ, abstractVar)[0]
let (a, tmp) = maybeMakeTemp(p, n[1], x)
let (b, tmp2) = maybeMakeTemp(p, n[2], y)
r.res = """if ($1.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); }
r.res = """if ($1 === null) $4 = [];
if ($4.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); }
else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2]
r.kind = resExpr
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
@@ -2315,7 +2206,7 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
if hasFrameInfo(p):
result = frameCreate(p,
makeJSString(prc.owner.name.s & '.' & prc.name.s),
makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace)))
makeJSString(toFilename(p.config, prc.info)))
else:
result = nil
if p.beforeRetNeeded:
@@ -2444,7 +2335,8 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1 $2)" % [r.res, trimmer]
elif toInt:
if fromInt:
return
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif fromUint:
if src.size == 4 and dest.size == 4:
# XXX prevent multi evaluations
@@ -2470,7 +2362,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
if r.kind != resCallee: r.kind = resNone
#r.address = nil
r.res = nil
case n.kind
of nkSym:
genSym(p, n, r)
@@ -2525,7 +2417,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
n.len >= 1:
genInfixCall(p, n, r)
else:
genCall(p, n, r)
genCall(p, n, r)
of nkClosure: gen(p, n[0], r)
of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r)
@@ -2551,7 +2443,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
let s = n[namePos].sym
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
p.locals.add(genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)
@@ -2582,17 +2474,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
if n[0].kind != nkEmpty:
genLineDir(p, n)
gen(p, n[0], r)
r.res = "var _ = " & r.res
of nkAsmStmt: genAsmOrEmitStmt(p, n)
of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r)
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
nkMixinStmt, nkBindStmt: discard
of nkIteratorDef:
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
of nkPragma: genPragma(p, n)
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
var s = n[namePos].sym
@@ -2600,7 +2488,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
genSym(p, n[namePos], r)
r.res = nil
of nkGotoState, nkState:
globalError(p.config, n.info, "First class iterators not implemented")
internalError(p.config, n.info, "first class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r)
of nkComesFrom:
discard "XXX to implement for better stack traces"
@@ -2614,14 +2502,20 @@ proc newModule(g: ModuleGraph; module: PSym): BModule =
g.backend = newGlobals()
result.graph = g
result.config = g.config
if sfSystemModule in module.flags:
PGlobals(g.backend).inSystem = true
proc genHeader(): Rope =
result = rope("""/* Generated by the Nim Compiler v$1 */
var framePtr = null;
var excHandler = 0;
var lastJSError = null;
if (typeof Int8Array === 'undefined') Int8Array = Array;
if (typeof Int16Array === 'undefined') Int16Array = Array;
if (typeof Int32Array === 'undefined') Int32Array = Array;
if (typeof Uint8Array === 'undefined') Uint8Array = Array;
if (typeof Uint16Array === 'undefined') Uint16Array = Array;
if (typeof Uint32Array === 'undefined') Uint32Array = Array;
if (typeof Float32Array === 'undefined') Float32Array = Array;
if (typeof Float64Array === 'undefined') Float64Array = Array;
""".unindent.format(VersionAsString))
proc addHcrInitGuards(p: PProc, n: PNode,
@@ -2651,7 +2545,7 @@ proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options:
p.body.add(frameCreate(p,
makeJSString("module " & p.module.module.name.s),
makeJSString(toFilenameOption(p.config, p.module.module.info.fileIndex, foStacktrace))))
makeJSString(toFilename(p.config, p.module.module.info))))
var transformedN = transformStmt(p.module.graph, p.module.module, n)
if sfInjectDestructors in p.module.module.flags:
transformedN = injectDestructorCalls(p.module.graph, p.module.module, transformedN)
@@ -2681,7 +2575,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(m.config, n): return n
if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newInitProc(globals, m)
var p = newProc(globals, m, nil, m.module.options)
p.unique = globals.unique
genModule(p, n)
p.g.code.add(p.locals)
@@ -2691,14 +2585,14 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
let globals = PGlobals(graph.backend)
for prc in globals.forwarded:
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newInitProc(globals, m)
var p = newProc(globals, m, nil, m.module.options)
attachProc(p, prc)
var disp = generateMethodDispatchers(graph)
for i in 0..<disp.len:
let prc = disp[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newInitProc(globals, m)
var p = newProc(globals, m, nil, m.module.options)
attachProc(p, prc)
result = globals.typeInfo & globals.constants & globals.code
@@ -2718,8 +2612,6 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if sfMainModule in m.module.flags:
for destructorCall in graph.globalDestructors:
n.add destructorCall
if sfSystemModule in m.module.flags:
PGlobals(graph.backend).inSystem = false
if passes.skipCodegen(m.config, n): return n
if sfMainModule in m.module.flags:
var code = genHeader() & wholeCode(graph, m)
@@ -2727,10 +2619,10 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if optSourcemap in m.config.globalOptions:
var map: SourceMap
(code, map) = genSourceMap($(code), outFile.string)
(code, map) = genSourceMap($(code), mangled, outFile.string)
writeFile(outFile.string & ".map", $(%map))
discard writeRopeIfNotEqual(code, outFile)
proc myOpen(graph: ModuleGraph; s: PSym): PPassContext =
result = newModule(graph, s)

View File

@@ -235,14 +235,13 @@ template isIterator*(owner: PSym): bool =
proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
## lambda lifting can be harmful for JS-like code generators.
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
result = conf.backend == backendJs and not isCompileTime
result = conf.cmd == cmdCompileToJS and not isCompileTime
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) =
if owner.kind != skMacro:
createTypeBoundOps(g, nil, refType.lastSon, info)
createTypeBoundOps(g, nil, refType, info)
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
owner.flags.incl sfInjectDestructors
createTypeBoundOps(g, nil, refType.lastSon, info)
createTypeBoundOps(g, nil, refType, info)
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
owner.flags.incl sfInjectDestructors
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
@@ -292,11 +291,10 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
if illegalCapture(s):
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") %
[s.name.s, typeToString(s.typ), g.config$s.info])
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
" safety, declared here: $3") % [s.name.s, typeToString(s.typ), g.config$s.info])
elif owner.typ.callConv notin {ccClosure, ccDefault}:
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
incl(owner.typ.flags, tfCapturesEnv)
owner.typ.callConv = ccClosure
@@ -613,8 +611,7 @@ proc rawClosureCreation(owner: PSym;
let fieldAccess = indirectAccess(env, local, env.info)
# add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
if owner.kind != skMacro:
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info)
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info)
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions:
owner.flags.incl sfInjectDestructors
@@ -825,8 +822,7 @@ proc semCaptureSym*(s, owner: PSym) =
var o = owner.skipGenericOwner
while o != nil and o.kind != skModule:
if s.owner == o:
if owner.typ.callConv == ccClosure or owner.kind == skIterator or
owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags:
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
owner.typ.callConv = ccClosure
propagateClosure(owner.skipGenericOwner, s.owner)
else:
@@ -851,14 +847,14 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo
fn.typ.callConv = oldCC
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
# However we can do lifting for the stuff which is *only* compiletime.
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
if body.kind == nkEmpty or (
g.config.backend == backendJs and not isCompileTime) or
g.config.cmd == cmdCompileToJS and not isCompileTime) or
fn.skipGenericOwner.kind != skModule:
# ignore forward declaration:

View File

@@ -35,7 +35,7 @@ type
Emitter* = object
config: ConfigRef
fid: FileIndex
lastTok: TokType
lastTok: TTokType
inquote, lastTokWasTerse: bool
semicolons: SemicolonKind
col, lastLineNumber, lineSpan, indentLevel, indWidth*, inSection: int
@@ -327,7 +327,7 @@ const
splitters = openPars + {tkComma, tkSemiColon} # do not add 'tkColon' here!
oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, tkOr, tkXor}
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
template goodCol(col): bool = col >= em.maxLineLen div 2
@@ -402,7 +402,7 @@ proc endsInAlpha(em: Emitter): bool =
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i)
result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false
proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) =
proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) =
var col = em.col
let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB)
em.lineSpan = countNewlines(lit)
@@ -417,7 +417,7 @@ proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) =
inc col
emitMultilineComment(em, lit, col, dontIndent)
proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
template wasExportMarker(em): bool =
em.kinds.len > 0 and em.kinds[^1] == ltExportMarker
@@ -452,9 +452,6 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
if tok.tokType in openPars and tok.indent > em.indentStack[^1]:
while em.indentStack[^1] < tok.indent:
em.indentStack.add(em.indentStack[^1] + em.indWidth)
while em.indentStack[^1] > tok.indent:
discard em.indentStack.pop()
# aka: we are in an expression context:
let alignment = max(tok.indent - em.indentStack[^1], 0)
em.indentLevel = alignment + em.indentStack.high * em.indWidth
@@ -494,7 +491,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
wrSpace em
if not em.inquote:
wr(em, $tok.tokType, ltKeyword)
wr(em, TokTypeToStr[tok.tokType], ltKeyword)
if tok.tokType in {tkAnd, tkOr, tkIn, tkNotin}:
rememberSplit(splitIn)
wrSpace em
@@ -503,28 +500,28 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
wr(em, tok.ident.s, ltIdent)
of tkColon:
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
wrSpace em
of tkSemiColon, tkComma:
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
rememberSplit(splitComma)
wrSpace em
of openPars:
if tok.strongSpaceA > 0 and not em.endsInWhite and
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
wrSpace em
wr(em, $tok.tokType, ltSomeParLe)
wr(em, TokTypeToStr[tok.tokType], ltSomeParLe)
rememberSplit(splitParLe)
of closedPars:
wr(em, $tok.tokType, ltSomeParRi)
wr(em, TokTypeToStr[tok.tokType], ltSomeParRi)
of tkColonColon:
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
of tkDot:
lastTokWasTerse = true
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
of tkEquals:
if not em.inquote and not em.endsInWhite: wrSpace(em)
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
if not em.inquote: wrSpace(em)
of tkOpr, tkDotDot:
if em.inquote or ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) and
@@ -544,7 +541,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
wrSpace(em)
of tkAccent:
if not em.inquote and endsInAlpha(em): wrSpace(em)
wr(em, $tok.tokType, ltOther)
wr(em, TokTypeToStr[tok.tokType], ltOther)
em.inquote = not em.inquote
of tkComment:
if not preventComment:

View File

@@ -30,49 +30,42 @@ const
# don't forget to update the 'highlite' module if these charsets should change
type
TokType* = enum
tkInvalid = "tkInvalid", tkEof = "[EOF]", # order is important here!
tkSymbol = "tkSymbol", # keywords:
tkAddr = "addr", tkAnd = "and", tkAs = "as", tkAsm = "asm",
tkBind = "bind", tkBlock = "block", tkBreak = "break", tkCase = "case", tkCast = "cast",
tkConcept = "concept", tkConst = "const", tkContinue = "continue", tkConverter = "converter",
tkDefer = "defer", tkDiscard = "discard", tkDistinct = "distinct", tkDiv = "div", tkDo = "do",
tkElif = "elif", tkElse = "else", tkEnd = "end", tkEnum = "enum", tkExcept = "except", tkExport = "export",
tkFinally = "finally", tkFor = "for", tkFrom = "from", tkFunc = "func",
tkIf = "if", tkImport = "import", tkIn = "in", tkInclude = "include", tkInterface = "interface",
tkIs = "is", tkIsnot = "isnot", tkIterator = "iterator",
tkLet = "let",
tkMacro = "macro", tkMethod = "method", tkMixin = "mixin", tkMod = "mod", tkNil = "nil", tkNot = "not", tkNotin = "notin",
tkObject = "object", tkOf = "of", tkOr = "or", tkOut = "out",
tkProc = "proc", tkPtr = "ptr", tkRaise = "raise", tkRef = "ref", tkReturn = "return",
tkShl = "shl", tkShr = "shr", tkStatic = "static",
tkTemplate = "template",
tkTry = "try", tkTuple = "tuple", tkType = "type", tkUsing = "using",
tkVar = "var", tkWhen = "when", tkWhile = "while", tkXor = "xor",
tkYield = "yield", # end of keywords
tkIntLit = "tkIntLit", tkInt8Lit = "tkInt8Lit", tkInt16Lit = "tkInt16Lit",
tkInt32Lit = "tkInt32Lit", tkInt64Lit = "tkInt64Lit",
tkUIntLit = "tkUIntLit", tkUInt8Lit = "tkUInt8Lit", tkUInt16Lit = "tkUInt16Lit",
tkUInt32Lit = "tkUInt32Lit", tkUInt64Lit = "tkUInt64Lit",
tkFloatLit = "tkFloatLit", tkFloat32Lit = "tkFloat32Lit",
tkFloat64Lit = "tkFloat64Lit", tkFloat128Lit = "tkFloat128Lit",
tkStrLit = "tkStrLit", tkRStrLit = "tkRStrLit", tkTripleStrLit = "tkTripleStrLit",
tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit",
tkParLe = "(", tkParRi = ")", tkBracketLe = "[",
tkBracketRi = "]", tkCurlyLe = "{", tkCurlyRi = "}",
tkBracketDotLe = "[.", tkBracketDotRi = ".]",
tkCurlyDotLe = "{.", tkCurlyDotRi = ".}",
tkParDotLe = "(.", tkParDotRi = ".)",
tkComma = ",", tkSemiColon = ";",
tkColon = ":", tkColonColon = "::", tkEquals = "=",
tkDot = ".", tkDotDot = "..", tkBracketLeColon = "[:",
tkOpr, tkComment, tkAccent = "`",
TTokType* = enum
tkInvalid, tkEof, # order is important here!
tkSymbol, # keywords:
tkAddr, tkAnd, tkAs, tkAsm,
tkBind, tkBlock, tkBreak, tkCase, tkCast,
tkConcept, tkConst, tkContinue, tkConverter,
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
tkFinally, tkFor, tkFrom, tkFunc,
tkIf, tkImport, tkIn, tkInclude, tkInterface,
tkIs, tkIsnot, tkIterator,
tkLet,
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
tkObject, tkOf, tkOr, tkOut,
tkProc, tkPtr, tkRaise, tkRef, tkReturn,
tkShl, tkShr, tkStatic,
tkTemplate,
tkTry, tkTuple, tkType, tkUsing,
tkVar, tkWhen, tkWhile, tkXor,
tkYield, # end of keywords
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit,
tkStrLit, tkRStrLit, tkTripleStrLit,
tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe,
tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, # [. and .]
tkCurlyDotLe, tkCurlyDotRi, # {. and .}
tkParDotLe, tkParDotRi, # (. and .)
tkComma, tkSemiColon,
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon,
tkOpr, tkComment, tkAccent,
# these are fake tokens used by renderer.nim
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TokTypes* = set[TokType]
TTokTypes* = set[TTokType]
const
weakTokens = {tkComma, tkSemiColon, tkColon,
@@ -81,21 +74,53 @@ const
# tokens that should not be considered for previousToken
tokKeywordLow* = succ(tkSymbol)
tokKeywordHigh* = pred(tkIntLit)
TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]",
"tkSymbol",
"addr", "and", "as", "asm",
"bind", "block", "break", "case", "cast",
"concept", "const", "continue", "converter",
"defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "if",
"import", "in", "include", "interface", "is", "isnot", "iterator",
"let",
"macro", "method", "mixin", "mod",
"nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return",
"shl", "shr", "static",
"template",
"try", "tuple", "type", "using",
"var", "when", "while", "xor",
"yield",
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
"tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
"tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit",
"tkStrLit", "tkRStrLit",
"tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(",
")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)",
",", ";",
":", "::", "=", ".", "..", "[:",
"tkOpr", "tkComment", "`",
"tkSpaces", "tkInfixOpr",
"tkPrefixOpr", "tkPostfixOpr"]
type
NumericalBase* = enum
TNumericalBase* = enum
base10, # base10 is listed as the first element,
# so that it is the correct default value
base2, base8, base16
Token* = object # a Nim token
tokType*: TokType # the type of the token
CursorPosition* {.pure.} = enum ## XXX remove this again
None, InToken, BeforeToken, AfterToken
TToken* = object # a Nim token
tokType*: TTokType # the type of the token
indent*: int # the indentation; != -1 if the token has been
# preceded with indentation
ident*: PIdent # the parsed identifier
iNumber*: BiggestInt # the parsed integer literal
fNumber*: BiggestFloat # the parsed floating point literal
base*: NumericalBase # the numerical base; only valid for int
base*: TNumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: int8 # leading spaces of an operator
strongSpaceB*: int8 # trailing spaces of an operator
@@ -103,25 +128,26 @@ type
# documentation comments are here too
line*, col*: int
when defined(nimpretty):
offsetA*, offsetB*: int # used for pretty printing so that literals
# like 0b01 or r"\L" are unaffected
offsetA*, offsetB*: int # used for pretty printing so that literals
# like 0b01 or r"\L" are unaffected
commentOffsetA*, commentOffsetB*: int
ErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
Lexer* = object of TBaseLexer
TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
TLexer* = object of TBaseLexer
fileIdx*: FileIndex
indentAhead*: int # if > 0 an indentation has already been read
# this is needed because scanning comments
# needs so much look-ahead
currLineIndent*: int
strongSpaces*, allowTabs*: bool
errorHandler*: ErrorHandler
cursor*: CursorPosition
errorHandler*: TErrorHandler
cache*: IdentCache
when defined(nimsuggest):
previousToken: TLineInfo
config*: ConfigRef
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
result = newLineInfo(L.fileIdx, tok.line, tok.col)
when defined(nimpretty):
result.offsetA = tok.offsetA
@@ -129,8 +155,8 @@ proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
result.commentOffsetA = tok.commentOffsetA
result.commentOffsetB = tok.commentOffsetB
proc isKeyword*(kind: TokType): bool =
(kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
@@ -144,26 +170,28 @@ proc isNimIdentifier*(s: string): bool =
inc(i)
result = true
proc `$`*(tok: Token): string =
proc `$`*(tok: TToken): string =
case tok.tokType
of tkIntLit..tkInt64Lit: $tok.iNumber
of tkFloatLit..tkFloat64Lit: $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: tok.literal
of tkParLe..tkColon, tkEof, tkAccent: $tok.tokType
of tkIntLit..tkInt64Lit: result = $tok.iNumber
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
of tkParLe..tkColon, tkEof, tkAccent:
result = TokTypeToStr[tok.tokType]
else:
if tok.ident != nil:
tok.ident.s
result = tok.ident.s
else:
""
result = ""
proc prettyTok*(tok: Token): string =
if isKeyword(tok.tokType): "keyword " & tok.ident.s
else: $tok
proc prettyTok*(tok: TToken): string =
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
else: result = $tok
proc printTok*(conf: ConfigRef; tok: Token) =
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok)
proc printTok*(conf: ConfigRef; tok: TToken) =
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" &
TokTypeToStr[tok.tokType] & " " & $tok)
proc initToken*(L: var Token) =
proc initToken*(L: var TToken) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
@@ -176,7 +204,7 @@ proc initToken*(L: var Token) =
L.commentOffsetA = 0
L.commentOffsetB = 0
proc fillToken(L: var Token) =
proc fillToken(L: var TToken) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
@@ -189,7 +217,7 @@ proc fillToken(L: var Token) =
L.commentOffsetA = 0
L.commentOffsetB = 0
proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream;
proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openBaseLexer(lex, inputstream)
lex.fileIdx = fileIdx
@@ -201,36 +229,36 @@ proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream;
lex.previousToken.fileIndex = fileIdx
lex.config = config
proc openLexer*(lex: var Lexer, filename: AbsoluteFile, inputstream: PLLStream;
proc openLexer*(lex: var TLexer, filename: AbsoluteFile, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
proc closeLexer*(lex: var Lexer) =
proc closeLexer*(lex: var TLexer) =
if lex.config != nil:
inc(lex.config.linesCompiled, lex.lineNumber)
closeBaseLexer(lex)
proc getLineInfo(L: Lexer): TLineInfo =
proc getLineInfo(L: TLexer): TLineInfo =
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
proc dispMessage(L: Lexer; info: TLineInfo; msg: TMsgKind; arg: string) =
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
if L.errorHandler.isNil:
msgs.message(L.config, info, msg, arg)
else:
L.errorHandler(L.config, info, msg, arg)
proc lexMessage*(L: Lexer, msg: TMsgKind, arg = "") =
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg)
proc lexMessageTok*(L: Lexer, msg: TMsgKind, tok: Token, arg = "") =
proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
var info = newLineInfo(L.fileIdx, tok.line, tok.col)
L.dispMessage(info, msg, arg)
proc lexMessagePos(L: var Lexer, msg: TMsgKind, pos: int, arg = "") =
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
L.dispMessage(info, msg, arg)
proc matchTwoChars(L: Lexer, first: char, second: set[char]): bool =
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
template tokenBegin(tok, pos) {.dirty.} =
@@ -244,6 +272,7 @@ template tokenEnd(tok, pos) {.dirty.} =
let colB = getColNumber(L, pos)+1
if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.InToken
L.config.m.trackPos.col = colA.int16
colA = 0
when defined(nimpretty):
@@ -268,22 +297,23 @@ template tokenEndPrevious(tok, pos) =
let colB = getColNumber(L, pos)
if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.BeforeToken
L.config.m.trackPos = L.previousToken
L.config.m.trackPosAttached = true
colA = 0
when defined(nimpretty):
tok.offsetB = L.offsetBase + pos
template eatChar(L: var Lexer, t: var Token, replacementChar: char) =
template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
t.literal.add(replacementChar)
inc(L.bufpos)
template eatChar(L: var Lexer, t: var Token) =
template eatChar(L: var TLexer, t: var TToken) =
t.literal.add(L.buf[L.bufpos])
inc(L.bufpos)
proc getNumber(L: var Lexer, result: var Token) =
proc matchUnderscoreChars(L: var Lexer, tok: var Token, chars: set[char]): Natural =
proc getNumber(L: var TLexer, result: var TToken) =
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]): Natural =
var pos = L.bufpos # use registers for pos, buf
result = 0
while true:
@@ -303,19 +333,19 @@ proc getNumber(L: var Lexer, result: var Token) =
inc(pos)
L.bufpos = pos
proc matchChars(L: var Lexer, tok: var Token, chars: set[char]) =
proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
var pos = L.bufpos # use registers for pos, buf
while L.buf[pos] in chars:
tok.literal.add(L.buf[pos])
inc(pos)
L.bufpos = pos
proc lexMessageLitNum(L: var Lexer, msg: string, startpos: int, msgKind = errGenerated) =
proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int, msgKind = errGenerated) =
# Used to get slightly human friendlier err messages.
const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'}
var msgPos = L.bufpos
var t: Token
var t: TToken
t.literal = ""
L.bufpos = startpos # Use L.bufpos as pos because of matchChars
matchChars(L, t, literalishChars)
@@ -542,7 +572,7 @@ proc getNumber(L: var Lexer, result: var Token) =
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
raise newException(OverflowDefect, "number out of range: " & $result.literal)
raise newException(OverflowError, "number out of range: " & $result.literal)
if len != result.literal.len:
raise newException(ValueError, "invalid integer: " & $result.literal)
result.iNumber = cast[int64](iNumber)
@@ -552,7 +582,7 @@ proc getNumber(L: var Lexer, result: var Token) =
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
raise newException(OverflowDefect, "number out of range: " & $result.literal)
raise newException(OverflowError, "number out of range: " & $result.literal)
if len != result.literal.len:
raise newException(ValueError, "invalid integer: " & $result.literal)
result.iNumber = iNumber
@@ -578,12 +608,12 @@ proc getNumber(L: var Lexer, result: var Token) =
except ValueError:
lexMessageLitNum(L, "invalid number: '$1'", startpos)
except OverflowDefect, RangeDefect:
except OverflowError, RangeError:
lexMessageLitNum(L, "number out of range: '$1'", startpos)
tokenEnd(result, postPos-1)
L.bufpos = postPos
proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) =
proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) =
template invalid() =
lexMessage(L, errGenerated,
"expected a hex digit, but found: " & L.buf[L.bufpos] &
@@ -608,7 +638,7 @@ proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) =
# Need to progress for `nim check`
inc(L.bufpos)
proc handleDecChars(L: var Lexer, xi: var int) =
proc handleDecChars(L: var TLexer, xi: var int) =
while L.buf[L.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
@@ -651,11 +681,16 @@ proc addUnicodeCodePoint(s: var string, i: int) =
s[pos+4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
s[pos+5] = chr(i and ones(6) or 0b10_0000_00)
proc getEscapedChar(L: var Lexer, tok: var Token) =
proc getEscapedChar(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '\'
case L.buf[L.bufpos]
of 'n', 'N':
tok.literal.add('\L')
if L.config.oldNewlines:
if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\n not allowed in character literal")
tok.literal.add(L.config.target.tnl)
else:
tok.literal.add('\L')
inc(L.bufpos)
of 'p', 'P':
if tok.tokType == tkCharLit:
@@ -731,13 +766,18 @@ proc getEscapedChar(L: var Lexer, tok: var Token) =
else: lexMessage(L, errGenerated, "invalid character constant")
else: lexMessage(L, errGenerated, "invalid character constant")
proc handleCRLF(L: var Lexer, pos: int): int =
proc newString(s: cstring, len: int): string =
## XXX, how come there is no support for this?
result = newString(len)
for i in 0..<len:
result[i] = s[i]
proc handleCRLF(L: var TLexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
when not defined(nimpretty):
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
case L.buf[pos]
of CR:
@@ -754,7 +794,7 @@ type
raw,
generalized
proc getString(L: var Lexer, tok: var Token, mode: StringMode) =
proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
var pos = L.bufpos
var line = L.lineNumber # save linenumber for better error message
tokenBegin(tok, pos - ord(mode == raw))
@@ -820,7 +860,7 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) =
inc(pos)
L.bufpos = pos
proc getCharacter(L: var Lexer, tok: var Token) =
proc getCharacter(L: var TLexer, tok: var TToken) =
tokenBegin(tok, L.bufpos)
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
@@ -837,7 +877,7 @@ proc getCharacter(L: var Lexer, tok: var Token) =
tokenEndIgnore(tok, L.bufpos)
inc(L.bufpos) # skip '
proc getSymbol(L: var Lexer, tok: var Token) =
proc getSymbol(L: var TLexer, tok: var TToken) =
var h: Hash = 0
var pos = L.bufpos
tokenBegin(tok, pos)
@@ -867,21 +907,21 @@ proc getSymbol(L: var Lexer, tok: var Token) =
(tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
tok.tokType = tkSymbol
else:
tok.tokType = TokType(tok.ident.id + ord(tkSymbol))
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}:
lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s)
L.bufpos = pos
proc endOperator(L: var Lexer, tok: var Token, pos: int,
proc endOperator(L: var TLexer, tok: var TToken, pos: int,
hash: Hash) {.inline.} =
var h = !$hash
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon))
else: tok.tokType = TTokType(tok.ident.id - oprLow + ord(tkColon))
L.bufpos = pos
proc getOperator(L: var Lexer, tok: var Token) =
proc getOperator(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
tokenBegin(tok, pos)
var h: Hash = 0
@@ -901,15 +941,18 @@ proc getOperator(L: var Lexer, tok: var Token) =
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc getPrecedence*(tok: Token): int =
proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token.
template considerStrongSpaces(x): untyped =
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType
of tkOpr:
let relevantChar = tok.ident.s[0]
# arrow like?
if tok.ident.s.len > 1 and tok.ident.s[^1] == '>' and
tok.ident.s[^2] in {'-', '~', '='}: return 1
tok.ident.s[^2] in {'-', '~', '='}: return considerStrongSpaces(1)
template considerAsgn(value: untyped) =
result = if tok.ident.s[^1] == '=': 1 else: value
@@ -925,13 +968,15 @@ proc getPrecedence*(tok: Token): int =
of '?': result = 2
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5
of tkDotDot: result = 6
of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs, tkFrom: result = 5
of tkAnd: result = 4
of tkOr, tkXor, tkPtr, tkRef: result = 3
else: return -10
result = considerStrongSpaces(result)
proc newlineFollows*(L: Lexer): bool =
proc newlineFollows*(L: TLexer): bool =
var pos = L.bufpos
while true:
case L.buf[pos]
@@ -947,7 +992,7 @@ proc newlineFollows*(L: Lexer): bool =
else:
break
proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
isDoc: bool) =
var pos = start
var toStrip = 0
@@ -1012,14 +1057,14 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc scanComment(L: var Lexer, tok: var Token) =
proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
assert L.buf[pos+1] == '#'
when defined(nimpretty):
tok.commentOffsetA = L.offsetBase + pos
tok.commentOffsetA = L.offsetBase + pos - 1
if L.buf[pos+2] == '[':
skipMultiLineComment(L, tok, pos+3, true)
@@ -1062,7 +1107,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc skip(L: var Lexer, tok: var Token) =
proc skip(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
tokenBegin(tok, pos)
tok.strongSpaceA = 0
@@ -1134,7 +1179,7 @@ proc skip(L: var Lexer, tok: var Token) =
tok.tokType = tkComment
tok.indent = commentIndent
proc rawGetTok*(L: var Lexer, tok: var Token) =
proc rawGetTok*(L: var TLexer, tok: var TToken) =
template atTokenEnd() {.dirty.} =
when defined(nimsuggest):
# we attach the cursor to the last *strong* token
@@ -1142,6 +1187,8 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
L.previousToken.line = tok.line.uint16
L.previousToken.col = tok.col.int16
when defined(nimsuggest):
L.cursor = CursorPosition.None
fillToken(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
@@ -1212,6 +1259,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col+1 == L.config.m.trackPos.col and
tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideSug:
tok.tokType = tkDot
L.cursor = CursorPosition.InToken
L.config.m.trackPos.col = tok.col.int16
inc(L.bufpos)
atTokenEnd()
@@ -1284,8 +1332,8 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
var lex: Lexer
var tok: Token
var lex: TLexer
var tok: TToken
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof
@@ -1299,11 +1347,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
proc getPrecedence*(ident: PIdent): int =
## assumes ident is binary operator already
var tok: Token
var tok: TToken
initToken(tok)
tok.ident = ident
tok.tokType =
if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TokType(tok.ident.id + ord(tkSymbol))
TTokType(tok.ident.id + ord(tkSymbol))
else: tkOpr
getPrecedence(tok)
getPrecedence(tok, false)

View File

@@ -10,6 +10,9 @@
## This module implements lifting for type-bound operations
## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``).
# Todo:
# - use openArray instead of array to avoid over-specializations
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables
@@ -23,9 +26,8 @@ type
fn: PSym
asgnForType: PType
recurse: bool
addMemReset: bool # add wasMoved() call after destructor call
canRaise: bool
filterDiscriminator: PSym # we generating destructor for case branch
addMemReset: bool # add wasMoved() call after destructor call
c: PContext # c can be nil, then we are called from lambdalifting!
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
@@ -40,9 +42,6 @@ proc at(a, i: PNode, elemType: PType): PNode =
result[1] = i
result.typ = elemType
proc destructorOverriden(t: PType): bool =
t.attachedOps[attachedDestructor] != nil and sfOverriden in t.attachedOps[attachedDestructor].flags
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0..<t.len:
let lit = lowerings.newIntLit(c.g, x.info, i)
@@ -63,18 +62,9 @@ proc newAsgnStmt(le, ri: PNode): PNode =
result[0] = le
result[1] = ri
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
result = newNodeI(nkCall, i.info)
result.add createMagic(g, name, magic).newSymNode
result.add i
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c.g, mDefault, "default", x)
call.typ = t
body.add newAsgnStmt(x, call)
proc genAddr(g: ModuleGraph; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -84,6 +74,12 @@ proc genAddr(g: ModuleGraph; x: PNode): PNode =
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
result.add x
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
result = newNodeI(nkCall, i.info)
result.add createMagic(g, name, magic).newSymNode
result.add i
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c.g, mLtI, "<", i)
@@ -95,7 +91,7 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode =
proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode =
# generate: cast[ptr ObjType](cast[int](addr(x)) - offsetOf(objType.field))
let intType = getSysType(c.g, unknownLineInfo, tyInt)
@@ -108,7 +104,7 @@ proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode =
let dotExpr = newNodeIT(nkDotExpr, c.info, x.typ)
dotExpr.add newNodeIT(nkType, c.info, objType)
dotExpr.add newSymNode(field)
let offsetOf = genBuiltin(c.g, mOffsetOf, "offsetof", dotExpr)
offsetOf.typ = intType
@@ -121,12 +117,10 @@ proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode =
result.add newNodeIT(nkType, c.info, objPtr)
result.add minusExpr
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
proc destructorCall(c: TLiftCtx; op: PSym; x: PNode): PNode =
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
destroy.add(newSymNode(op))
destroy.add genAddr(c.g, x)
if sfNeverRaises notin op.flags:
c.canRaise = true
if c.addMemReset:
result = newTree(nkStmtList, destroy, genBuiltin(c.g, mWasMoved, "wasMoved", x))
else:
@@ -146,6 +140,9 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
let oldfilterDiscriminator = c.filterDiscriminator
if c.filterDiscriminator == n[0].sym:
c.filterDiscriminator = nil # we have found the case part, proceed as normal
# XXX This is only correct for 'attachedSink'!
var localEnforceDefaultOp = enforceDefaultOp
if c.kind == attachedSink:
@@ -157,14 +154,8 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
c.kind = prevKind
localEnforceDefaultOp = true
if c.kind != attachedDestructor:
# copy the selector before case stmt, but destroy after case stmt
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
let oldfilterDiscriminator = c.filterDiscriminator
if c.filterDiscriminator == n[0].sym:
c.filterDiscriminator = nil # we have found the case part, proceed as normal
# copy the selector:
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, c.info)
# XXX generate 'if' that checks same branches
@@ -183,11 +174,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
caseStmt.add(branch)
if emptyBranches != n.len-1:
body.add(caseStmt)
if c.kind == attachedDestructor:
# destructor for selector is done after case stmt
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
c.filterDiscriminator = oldfilterDiscriminator
c.filterDiscriminator = oldfilterDiscriminator
of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
else:
@@ -246,37 +233,29 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
else:
fillBodyObjTImpl(c, t, body, x, y)
proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
#if sfError in op.flags:
# localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
result = newNodeI(nkCall, x.info)
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ.sons[1].kind == tyVar:
result.add genAddr(c.g, x)
result.add genAddr(g, x)
else:
result.add x
if y != nil:
result.add y
proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
proc newOpCall(op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ[0])
result.add(newSymNode(op))
result.add x
if sfNeverRaises notin op.flags:
c.canRaise = true
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc usesBuiltinArc(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
result = types.searchTypeFor(t, wrap)
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(op, y))
proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
result = optSeqDestructors in c.g.config.globalOptions and
({tfHasGCedMem, tfHasOwned} * t.flags != {} or usesBuiltinArc(t))
({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
proc requiresDestructor(c: TLiftCtx; t: PType): bool {.inline.} =
result = optSeqDestructors in c.g.config.globalOptions and
@@ -293,20 +272,14 @@ proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
field: var PSym): bool =
if optSeqDestructors in c.g.config.globalOptions:
var op = field
let destructorOverriden = destructorOverriden(t)
if op != nil and op != c.fn and
(sfOverriden in op.flags or destructorOverriden):
let op = field
if field != nil and sfOverriden in field.flags:
if sfError in op.flags:
incl c.fn.flags, sfError
#else:
# markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newHookCall(c, op, x, y)
result = true
elif op == nil and destructorOverriden:
op = produceSym(c.g, c.c, t, c.kind, c.info)
body.add newHookCall(c, op, x, y)
body.add newHookCall(c.g, op, x, y)
result = true
elif tfHasAsgn in t.flags:
var op: PSym
@@ -335,7 +308,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
#debug(t)
#return false
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newHookCall(c, op, x, y)
body.add newHookCall(c.g, op, x, y)
result = true
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
@@ -386,7 +359,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op != nil:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newDeepCopyCall(c, op, x, y)
body.add newDeepCopyCall(op, x, y)
result = true
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
@@ -399,16 +372,6 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
v.addVar(result, lowerings.newIntLit(c.g, body.info, first))
body.add v
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = value.typ
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp)
v.addVar(result, value)
body.add v
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c.g, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.g, c.info, 1)
@@ -435,17 +398,13 @@ proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let counterIdx = body.len
let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon
let b = if c.kind == attachedTrace: y else: y.at(i, elemType)
fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b)
if whileLoop[1].len > 0:
addIncStmt(c, whileLoop[1], i)
body.add whileLoop
else:
body.sons.setLen counterIdx
addIncStmt(c, whileLoop[1], i)
body.add whileLoop
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -468,11 +427,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
forallElements(c, t, body, x, y)
body.add genBuiltin(c.g, mDestroy, "destroy", x)
of attachedTrace:
if canFormAcycle(t.elemType):
# follow all elements:
forallElements(c, t, body, x, y)
of attachedDispose:
# follow all elements:
forallElements(c, t, body, x, y)
of attachedDispose:
body.add genBuiltin(c.g, mDestroy, "destroy", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -487,10 +444,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy:
# XXX: replace these with assertions.
if t.assignment == nil:
return # protect from recursion
body.add newHookCall(c, t.assignment, x, y)
doAssert t.assignment != nil
body.add newHookCall(c.g, t.assignment, x, y)
of attachedSink:
# we always inline the move for better performance:
let moveCall = genBuiltin(c.g, mMove, "move", x)
@@ -501,18 +456,14 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# alternatively we could do this:
when false:
doAssert t.asink != nil
body.add newHookCall(c, t.asink, x, y)
body.add newHookCall(c.g, t.asink, x, y)
of attachedDestructor:
doAssert t.destructor != nil
body.add destructorCall(c, t.destructor, x)
of attachedTrace:
if t.attachedOps[c.kind] == nil:
return # protect from recursion
body.add newHookCall(c, t.attachedOps[c.kind], x, y)
body.add newHookCall(c.g, t.attachedOps[c.kind], x, y)
of attachedDispose:
if t.attachedOps[c.kind] == nil:
return # protect from recursion
body.add newHookCall(c, t.attachedOps[c.kind], x, nil)
body.add newHookCall(c.g, t.attachedOps[c.kind], x, nil)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -530,93 +481,54 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
discard "strings are atomic and have no inner elements that are to trace"
proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
#[ bug #15753 is really subtle. Usually the classical write barrier for reference
counting looks like this::
incRef source # increment first; this takes care of self-assignments1
decRef dest
dest[] = source
However, 'decRef dest' might trigger a cycle collection and then the collector
traverses the graph. It is crucial that when it follows the pointers the assignment
'dest[] = source' already happened so that we don't do trial deletion on a wrong
graph -- this causes premature freeing of objects! The correct barrier looks like
this::
let tmp = dest
incRef source
dest[] = source
decRef tmp
]#
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.lastSon
createTypeBoundOps(c.g, c.c, elemType, c.info)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, x)
else:
x
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(t)
var cond: PNode
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, x)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
cond.typ = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
else:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedAsgn:
body.add genIf(c, y, callCodegenProc(c.g,
if isCyclic: "nimIncRefCyclic" else: "nimIncRef", c.info, y))
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
else:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t))
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
else:
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y)
#echo "can follow ", elemType, " static ", isFinal(elemType)
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
else:
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y)
of attachedDispose:
# this is crucial! dispose is like =destroy but we don't follow refs
# as that is dealt within the cycle collector.
if not isCyclic:
body.add genIf(c, cond, actions)
when false:
let cond = copyTree(x)
cond.typ = getSysType(c.g, x.info, tyBool)
@@ -629,30 +541,19 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
xenv.typ = getSysType(c.g, c.info, tyPointer)
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, xenv)
else:
xenv
var actions = newNodeI(nkStmtList, c.info)
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xenv)
let decRefProc =
if isCyclic: "nimDecRefIsLastCyclicDyn"
if c.g.config.selectedGC == gcOrc: "nimDecRefIsLastCyclicDyn"
else: "nimDecRefIsLast"
let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
let cond = callCodegenProc(c.g, decRefProc, c.info, xenv)
cond.typ = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
else:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedAsgn:
let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
@@ -660,14 +561,11 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.g.config.selectedGC == gcOrc: "nimIncRefCyclic"
else: "nimIncRef"
body.add genIf(c, yenv, callCodegenProc(c.g, incRefProc, c.info, yenv))
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
else:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, cond, actions)
body.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ))
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv), y)
@@ -696,6 +594,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# prevent wrong "dangling refs exist" problems:
var actions = newNodeI(nkStmtList, c.info)
actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, x)
actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t))
let des = genIf(c, x, actions)
if body.len == 0:
body.add des
@@ -713,9 +612,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
@@ -726,6 +623,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, x, actions)
body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t))
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace, attachedDispose: discard
@@ -755,7 +653,10 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDestructor:
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
var actions = newNodeI(nkStmtList, c.info)
actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)
actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ))
let des = genIf(c, xx, actions)
if body.len == 0:
body.add des
else:
@@ -775,6 +676,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, xx, actions)
body.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ))
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace, attachedDispose: discard
@@ -782,7 +684,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
tyPtr, tyUncheckedArray, tyVar, tyLent:
tyPtr, tyOpt, tyUncheckedArray, tyVar, tyLent:
defaultOp(c, t, body, x, y)
of tyRef:
if c.g.config.selectedGC in {gcArc, gcOrc}:
@@ -858,13 +760,12 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:
tyTypeDesc, tyGenericInvocation, tyForward:
#internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
discard
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
tyGenericInst, tyStatic, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y)
of tyOptDeprecated: doAssert false
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo): PSym =
@@ -875,11 +776,11 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
typ.attachedOps[kind] = baseType.attachedOps[kind]
result = typ.attachedOps[kind]
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
proc symPrototype(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym =
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, owner, info)
result = newSym(skProc, procname, typ.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), result, info)
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), result, info)
dest.typ = makeVarType(typ.owner, typ)
@@ -888,7 +789,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
else:
src.typ = typ
result.typ = newProcType(info, owner)
result.typ = newProcType(info, typ.owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedDispose}:
result.typ.addParam src
@@ -908,10 +809,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
if typ.kind == tyDistinct:
return produceSymDistinctType(g, c, typ, kind, info)
result = typ.attachedOps[kind]
if result == nil:
result = symPrototype(g, typ, typ.owner, kind, info)
result = symPrototype(g, typ, kind, info)
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType:typ)
a.fn = result
@@ -923,10 +821,11 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
# register this operation already:
typ.attachedOps[kind] = result
if kind == attachedSink and destructorOverriden(typ):
if kind == attachedSink and typ.attachedOps[attachedDestructor] != nil and
sfOverriden in typ.attachedOps[attachedDestructor].flags:
## compiler can use a combination of `=destroy` and memCopy for sink op
dest.flags.incl sfCursor
result.ast[bodyPos].add newOpCall(a, typ.attachedOps[attachedDestructor], d[0])
result.ast[bodyPos].add newOpCall(typ.attachedOps[attachedDestructor], d[0])
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
@@ -941,12 +840,11 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if not a.canRaise: incl result.flags, sfNeverRaises
proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, info: TLineInfo): PSym =
assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info)
assert(typ.kind == tyObject)
result = symPrototype(g, field.typ, attachedDestructor, info)
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ)
a.fn = result
a.asgnForType = typ
@@ -963,7 +861,6 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
result.ast[bodyPos].add v
let placeHolder = newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
fillBody(a, typ, result.ast[bodyPos], d, placeHolder)
if not a.canRaise: incl result.flags, sfNeverRaises
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
@@ -1002,6 +899,11 @@ template inst(field, t) =
proc isTrival(s: PSym): bool {.inline.} =
s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
proc isEmptyContainer(g: ModuleGraph, t: PType): bool =
(t.kind == tyArray and lengthOrd(g.config, t[0]) == 0) or
(t.kind == tySequence and t[0].kind == tyError)
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo) =
## In the semantic pass this is called in strategic places
## to ensure we lift assignment, destructors and moves properly.
@@ -1010,7 +912,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
incl orig.flags, tfCheckedForDestructor
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
if isEmptyContainer(skipped): return
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)
@@ -1030,18 +932,9 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
let lastAttached = if g.config.selectedGC == gcOrc: attachedDispose
else: attachedSink
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we shoule rewrite
# this module.
var generics: array[attachedDestructor..attachedDispose, bool]
for k in attachedDestructor..lastAttached:
generics[k] = canon.attachedOps[k] != nil
if not generics[k]:
canon.attachedOps[k] = symPrototype(g, canon, canon.owner, k, info)
# we generate the destructor first so that other operators can depend on it:
for k in attachedDestructor..lastAttached:
if not generics[k]:
if canon.attachedOps[k] == nil:
discard produceSym(g, c, canon, k, info)
else:
inst(canon.attachedOps[k], canon)

View File

@@ -10,20 +10,10 @@
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
import ropes, tables, pathutils, hashes
import ropes, tables, pathutils
const
explanationsBaseUrl* = "https://nim-lang.github.io/Nim"
# was: "https://nim-lang.org/docs" but we're now usually showing devel docs
# instead of latest release docs.
proc createDocLink*(urlSuffix: string): string =
# os.`/` is not appropriate for urls.
result = explanationsBaseUrl
if urlSuffix.len > 0 and urlSuffix[0] == '/':
result.add urlSuffix
else:
result.add "/" & urlSuffix
explanationsBaseUrl* = "https://nim-lang.org/docs"
type
TMsgKind* = enum
@@ -33,43 +23,40 @@ type
errGeneralParseError,
errNewSectionExpected,
errInvalidDirectiveX,
errProveInit, # deadcode
errProveInit,
errGenerated,
errUser,
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit",
warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated",
warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic",
warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX",
warnLanguageXNotSupported = "LanguageXNotSupported", warnFieldXNotSupported = "FieldXNotSupported",
warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam",
warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap",
warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport",
warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple",
warnUnsafeSetLen = "UnsafeSetLen", warnUnsafeDefault = "UnsafeDefault",
warnProveInit = "ProveInit", warnProveField = "ProveField", warnProveIndex = "ProveIndex",
warnUnreachableElse = "UnreachableElse", warnUnreachableCode = "UnreachableCode",
warnStaticIndexCheck = "IndexCheck", warnGcUnsafe = "GcUnsafe", warnGcUnsafe2 = "GcUnsafe2",
warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor",
warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed",
warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition",
warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores",
warnResultUsed = "ResultUsed",
warnUser = "User",
hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC",
hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed",
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin",
hintCodeEnd = "CodeEnd", hintConf = "Conf", hintPath = "Path",
hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name",
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnTypelessParam,
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
warnUnusedImportX,
warnInheritFromException,
warnEachIdentIsTuple,
warnUnsafeSetLen,
warnUnsafeDefault,
warnProveInit, warnProveField, warnProveIndex,
warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated,
warnObservableStores,
warnResultUsed,
warnUser,
hintSuccess, hintSuccessX, hintCC,
hintLineTooLong, hintXDeclaredButNotUsed,
hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
hintExecuting, hintLinking, hintDependency,
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintGlobalVar, hintExpandMacro,
hintUser, hintUserRaw,
hintExtendedContext
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -82,7 +69,7 @@ const
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errInvalidDirectiveX: "invalid directive: '$1'",
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
errProveInit: "Cannot prove that '$1' is initialized.",
errGenerated: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
@@ -112,12 +99,10 @@ const
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
warnProveField: "cannot prove that field '$1' is accessible",
warnProveIndex: "cannot prove index '$1' is valid",
warnUnreachableElse: "unreachable else, all cases are already covered",
warnUnreachableCode: "unreachable code after 'return' statement or '{.noReturn.}' proc",
warnStaticIndexCheck: "$1",
warnGcUnsafe: "not GC-safe: '$1'",
warnGcUnsafe2: "$1",
warnUninit: "use explicit initialization of '$1' for clarity",
warnUninit: "'$1' might not have been initialized",
warnGcMem: "'$1' uses GC'ed memory",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
warnLockLevel: "$1",
@@ -130,11 +115,10 @@ const
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "${loc} lines; ${sec}s; $mem; $build build; proj: $project; out: $output",
hintSuccessX: "$loc LOC; $sec sec; $mem; $build build; proj: $project; out: $output",
hintCC: "CC: $1",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintXCannotRaiseY: "$1",
hintConvToBaseNotNeeded: "conversion to base object is not needed",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
hintExprAlwaysX: "expression evaluates always to '$1'",
@@ -160,7 +144,34 @@ const
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
]
const
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored",
"TypelessParam", "UseBase", "WriteToForeignHeap",
"UnsafeCode", "UnusedImport", "InheritFromException",
"EachIdentIsTuple",
"UnsafeSetLen", "UnsafeDefault",
"ProveInit", "ProveField", "ProveIndex",
"IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "CaseTransition", "CycleCreated",
"ObservableStores", "ResultUsed", "User"]
HintsToStr* = [
"Success", "SuccessX", "CC", "LineTooLong",
"XDeclaredButNotUsed",
"ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro",
"User", "UserRaw", "ExtendedContext",
]
const
@@ -173,16 +184,20 @@ const
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnResultUsed}
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin}
hintSource, hintGlobalVar, hintGCStats}
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC}
@@ -237,9 +252,6 @@ type
proc `==`*(a, b: FileIndex): bool {.borrow.}
proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)
proc raiseRecoverableError*(msg: string) {.noinline.} =
raise newException(ERecoverableError, msg)

View File

@@ -71,9 +71,12 @@ proc beautifyName(s: string, k: TSymKind): string =
proc differ*(line: string, a, b: int, x: string): string =
proc substrEq(s: string, pos, last: int, substr: string): bool =
result = true
for i in 0..<substr.len:
if pos+i > last or s[pos+i] != substr[i]: return false
var i = 0
while i < substr.len and pos+i <= last and s[pos+i] == substr[i]:
inc i
return i == substr.len
let last = min(b, line.len)
result = ""
if not substrEq(line, a, b, x):
@@ -81,6 +84,11 @@ proc differ*(line: string, a, b: int, x: string): string =
if cmpIgnoreStyle(y, x) == 0:
result = y
proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
let beau = beautifyName(s, k)
if s != beau:
lintReport(conf, info, beau, s)
proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
# operators stay as they are:
if k in {skResult, skTemp} or s.name.s[0] notin Letters: return
@@ -128,6 +136,6 @@ proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) =
lintReport(conf, info, newName, oldName)
proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
let wanted = $w
let wanted = canonPragmaSpelling(w)
if pragmaName != wanted:
lintReport(conf, info, wanted, pragmaName)

View File

@@ -91,15 +91,8 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s & " is deprecated")
proc isShadowScope*(s: PScope): bool {.inline.} = s.parent != nil and s.parent.depthLevel == s.depthLevel
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
var scope = c.currentScope
result = strTableGet(scope.symbols, s)
while result == nil and scope.isShadowScope:
# We are in a shadow scope, check in the parent too
scope = scope.parent
result = strTableGet(scope.symbols, s)
result = strTableGet(c.currentScope.symbols, s)
proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):
@@ -238,23 +231,6 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
addOverloadableSymAt(c, scope, sym)
addInterfaceDeclAux(c, sym)
proc openShadowScope*(c: PContext) =
c.currentScope = PScope(parent: c.currentScope,
symbols: newStrTable(),
depthLevel: c.scopeDepth)
proc closeShadowScope*(c: PContext) =
c.closeScope
proc mergeShadowScope*(c: PContext) =
let shadowScope = c.currentScope
c.rawCloseScope
for sym in shadowScope.symbols:
if sym.kind in OverloadableSyms:
c.addInterfaceOverloadableSymAt(c.currentScope, sym)
else:
c.addInterfaceDecl(sym)
when defined(nimfix):
# when we cannot find the identifier, retry with a changed identifier:
proc altSpelling(x: PIdent): PIdent =
@@ -340,7 +316,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
fixSpelling(n, ident, searchInScopes)
errorUndeclaredIdentifier(c, n.info, ident.s)
result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and result.id in c.ambiguousSymbols:
elif checkAmbiguity in flags and result != nil and
contains(c.ambiguousSymbols, result.id):
errorUseQualifier(c, n.info, result)
of nkSym:
result = n.sym

View File

@@ -59,13 +59,6 @@ proc newFastAsgnStmt*(le, ri: PNode): PNode =
result[0] = le
result[1] = ri
proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode =
result = newNodeI(nkFastAsgn, le.info, 2)
result[0] = le
result[1] = newNodeIT(nkCall, ri.info, ri.typ)
result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove))
result[1].add ri
proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple
let value = n.lastSon
@@ -136,7 +129,6 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
var temp = newSym(skVar, getIdent(g.cache, genPrefix), owner, n.info, owner.options)
temp.typ = n[1].typ
incl(temp.flags, sfFromGeneric)
incl(temp.flags, sfGenSym)
var v = newNodeI(nkVarSection, n.info)
let tempAsNode = newSymNode(temp)
@@ -159,7 +151,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType
else:
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info)),
owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
@@ -370,3 +362,14 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode =
result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
result[1] = n
proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
result = newSym(skLet, name, owner, varSection.info, owner.options)
result.flags.incl sfHoisted
result.typ = expr.typ
var varDef = newNodeI(nkIdentDefs, varSection.info, 3)
varDef[0] = newSymNode(result)
varDef[1] = newNodeI(nkEmpty, varSection.info)
varDef[2] = expr
varSection.add varDef

View File

@@ -19,7 +19,7 @@ import
cgen, json, nversion,
platform, nimconf, passaux, depends, vm, idgen,
modules,
modulegraphs, tables, rod, lineinfos, pathutils, vmprofiler
modulegraphs, tables, rod, lineinfos, pathutils
when not defined(leanCompiler):
import jsgen, docgen, docgen2
@@ -51,7 +51,7 @@ proc commandGenDepend(graph: ModuleGraph) =
' ' & changeFileExt(project, "dot").string)
proc commandCheck(graph: ModuleGraph) =
graph.config.setErrorMaxHighMaybe
graph.config.errorMax = high(int) # do not stop after first error
defineSymbol(graph.config.symbols, "nimcheck")
semanticPasses(graph) # use an empty backend for semantic checking only
compileProject(graph)
@@ -59,7 +59,7 @@ proc commandCheck(graph: ModuleGraph) =
when not defined(leanCompiler):
proc commandDoc2(graph: ModuleGraph; json: bool) =
handleDocOutputOptions graph.config
graph.config.setErrorMaxHighMaybe
graph.config.errorMax = high(int) # do not stop after first error
semanticPasses(graph)
if json: registerPass(graph, docgen2JsonPass)
else: registerPass(graph, docgen2Pass)
@@ -68,7 +68,16 @@ when not defined(leanCompiler):
proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config
setOutFile(conf)
if conf.outDir.isEmpty:
conf.outDir = conf.projectPath
if conf.outFile.isEmpty:
let targetName = if optGenDynLib in conf.globalOptions:
platform.OS[conf.target.targetOS].dllFrmt % conf.projectName
else:
conf.projectName & platform.OS[conf.target.targetOS].exeExt
conf.outFile = RelativeFile targetName
extccomp.initVars(conf)
semanticPasses(graph)
registerPass(graph, cgenPass)
@@ -99,13 +108,13 @@ proc commandJsonScript(graph: ModuleGraph) =
let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj)
proc commandCompileToJS(graph: ModuleGraph) =
when defined(leanCompiler):
globalError(graph.config, unknownLineInfo, "compiler wasn't built with JS code generator")
else:
when not defined(leanCompiler):
proc commandCompileToJS(graph: ModuleGraph) =
let conf = graph.config
conf.exc = excCpp
if conf.outDir.isEmpty:
conf.outDir = conf.projectPath
if conf.outFile.isEmpty:
conf.outFile = RelativeFile(conf.projectName & ".js")
@@ -113,6 +122,7 @@ proc commandCompileToJS(graph: ModuleGraph) =
setTarget(graph.config.target, osJS, cpuJS)
#initDefines()
defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
defineSymbol(graph.config.symbols, "js")
semanticPasses(graph)
registerPass(graph, JSgenPass)
compileProject(graph)
@@ -129,7 +139,7 @@ proc interactivePasses(graph: ModuleGraph) =
registerPass(graph, evalPass)
proc commandInteractive(graph: ModuleGraph) =
graph.config.setErrorMaxHighMaybe
graph.config.errorMax = high(int) # do not stop after first error
interactivePasses(graph)
compileSystemModule(graph)
if graph.config.commandArgs.len > 0:
@@ -149,8 +159,8 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: Lexer
tok: Token
L: TLexer
tok: TToken
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:
@@ -174,103 +184,63 @@ proc mainCommand*(graph: ModuleGraph) =
conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath)
setId(100)
proc customizeForBackend(backend: TBackend) =
## Sets backend specific options but don't compile to backend yet in
## case command doesn't require it. This must be called by all commands.
if conf.backend == backendInvalid:
# only set if wasn't already set, to allow override via `nim c -b:cpp`
conf.backend = backend
defineSymbol(graph.config.symbols, $conf.backend)
case conf.backend
of backendC:
if conf.exc == excNone: conf.exc = excSetjmp
of backendCpp:
if conf.exc == excNone: conf.exc = excCpp
of backendObjc: discard
of backendJs:
case conf.command.normalize
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
conf.cmd = cmdCompileToC
if conf.exc == excNone: conf.exc = excSetjmp
defineSymbol(graph.config.symbols, "c")
commandCompileToC(graph)
of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp
if conf.exc == excNone: conf.exc = excCpp
defineSymbol(graph.config.symbols, "cpp")
commandCompileToC(graph)
of "objc", "compiletooc":
conf.cmd = cmdCompileToOC
defineSymbol(graph.config.symbols, "objc")
commandCompileToC(graph)
of "run":
conf.cmd = cmdRun
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
commandCompileToC(graph)
else:
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
of "js", "compiletojs":
when defined(leanCompiler):
quit "compiler wasn't built with JS code generator"
else:
conf.cmd = cmdCompileToJS
if conf.hcrOn:
# XXX: At the moment, system.nim cannot be compiled in JS mode
# with "-d:useNimRtl". The HCR option has been processed earlier
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendInvalid: doAssert false
if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp:
conf.exc = excGoto
var commandAlreadyProcessed = false
proc compileToBackend(backend: TBackend, cmd = cmdCompileToBackend) =
commandAlreadyProcessed = true
conf.cmd = cmd
customizeForBackend(backend)
case conf.backend
of backendC: commandCompileToC(graph)
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendInvalid: doAssert false
template docLikeCmd(body) =
commandCompileToJS(graph)
of "doc0":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc")
body
block: ## command prepass
var docLikeCmd2 = false # includes what calls `docLikeCmd` + some more
case conf.command.normalize
of "r": conf.globalOptions.incl {optRun, optUseNimcache}
of "doc0", "doc2", "doc", "rst2html", "rst2tex", "jsondoc0", "jsondoc2",
"jsondoc", "ctags", "buildindex": docLikeCmd2 = true
else: discard
if conf.outDir.isEmpty:
# doc like commands can generate a lot of files (especially with --project)
# so by default should not end up in $PWD nor in $projectPath.
conf.outDir = block:
var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf)
else: conf.projectPath
doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee
if docLikeCmd2: ret = ret / htmldocsDir
ret
## process all backend commands
case conf.command.normalize
of "c", "cc", "compile", "compiletoc": compileToBackend(backendC) # compile means compileToC currently
of "cpp", "compiletocpp": compileToBackend(backendCpp)
of "objc", "compiletooc": compileToBackend(backendObjc)
of "js", "compiletojs": compileToBackend(backendJs)
of "r": compileToBackend(backendC) # different from `"run"`!
of "run":
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
if conf.backend notin {backendC, backendInvalid}:
rawMessage(conf, errGenerated, "'run' requires c backend, got: '$1'" % $conf.backend)
compileToBackend(backendC, cmd = cmdRun)
else:
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
else: customizeForBackend(backendC) # fallback for other commands
## process all other commands
case conf.command.normalize # synchronize with `cmdUsingHtmlDocs`
of "doc0": docLikeCmd commandDoc(cache, conf)
commandDoc(cache, conf)
of "doc2", "doc":
docLikeCmd():
conf.setNoteDefaults(warnLockLevel, false) # issue #13218
conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218
# because currently generates lots of false positives due to conflation
# of labels links in doc comments, e.g. for random.rand:
# ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
# ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
conf.setNoteDefaults(warnLockLevel, false) # issue #13218
conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218
# because currently generates lots of false positives due to conflation
# of labels links in doc comments, eg for random.rand:
# ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
# ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, false)
if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions:
commandBuildIndex(conf, $conf.outDir)
of "rst2html":
conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218
when defined(leanCompiler):
@@ -286,10 +256,41 @@ proc mainCommand*(graph: ModuleGraph) =
conf.cmd = cmdRst2tex
loadConfigs(DocTexConfig, cache, conf)
commandRst2TeX(cache, conf)
of "jsondoc0": docLikeCmd commandJson(cache, conf)
of "jsondoc2", "jsondoc": docLikeCmd commandDoc2(graph, true)
of "ctags": docLikeCmd commandTags(cache, conf)
of "buildindex": docLikeCmd commandBuildIndex(conf, $conf.projectFull, conf.outFile)
of "jsondoc0":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc")
commandJson(cache, conf)
of "jsondoc2", "jsondoc":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, true)
of "ctags":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc")
commandTags(cache, conf)
of "buildindex":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
commandBuildIndex(cache, conf)
of "gendepend":
conf.cmd = cmdGenDepend
commandGenDepend(graph)
@@ -308,10 +309,12 @@ proc mainCommand*(graph: ModuleGraph) =
var hints = newJObject() # consider factoring with `listHints`
for a in hintMin..hintMax:
hints[$a] = %(a in conf.notes)
let key = lineinfos.HintsToStr[ord(a) - ord(hintMin)]
hints[key] = %(a in conf.notes)
var warnings = newJObject()
for a in warnMin..warnMax:
warnings[$a] = %(a in conf.notes)
let key = lineinfos.WarningsToStr[ord(a) - ord(warnMin)]
warnings[key] = %(a in conf.notes)
var dumpdata = %[
(key: "version", val: %VersionAsString),
@@ -363,9 +366,7 @@ proc mainCommand*(graph: ModuleGraph) =
conf.cmd = cmdDump
of "jsonscript":
conf.cmd = cmdJsonScript
setOutFile(graph.config)
commandJsonScript(graph)
elif commandAlreadyProcessed: discard # already handled
else:
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
@@ -380,18 +381,8 @@ proc mainCommand*(graph: ModuleGraph) =
else: "Debug"
let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3)
let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName
var output: string
if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonScript:
output = $conf.jsonBuildFile
elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonScript, cmdCompileToBackend, cmdDoc}:
# for some cmd we expect a valid absOutFile
output = "unknownOutput"
else:
output = $conf.absOutFile
var output = $conf.absOutFile
if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename
if optProfileVM in conf.globalOptions:
echo conf.dump(conf.vmProfileData)
rawMessage(conf, hintSuccessX, [
"loc", loc,
"sec", sec,
@@ -408,3 +399,5 @@ proc mainCommand*(graph: ModuleGraph) =
echo " int tries: ", gCacheIntTries
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
ffDecimal, 3)
resetAttributes(conf)

View File

@@ -31,7 +31,7 @@ import ast, intsets, tables, options, lineinfos, hashes, idents,
type
SigHash* = distinct MD5Digest
ModuleGraph* {.acyclic.} = ref object
ModuleGraph* = ref object
modules*: seq[PSym] ## indexed by int32 fileIdx
packageSyms*: TStrTable
deps*: IntSet # the dependency graph or potentially its transitive closure.
@@ -72,7 +72,9 @@ type
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
globalDestructors*: seq[PNode]
strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {.nimcall.}
proofEngine*: proc (graph: ModuleGraph; assumptions: seq[PNode]; toProve: PNode): (bool, string) {.nimcall.}
requirementsCheck*: proc (graph: ModuleGraph; assumptions: seq[PNode];
call, requirement: PNode): (bool, string) {.nimcall.}
compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.}
TPassContext* = object of RootObj # the pass's context

View File

@@ -91,7 +91,8 @@ when false:
if result.len > 0: return result
proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
if result.isNil: result = ""
proc lookupPackage(pkg, subdir: PNode): string =
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
@@ -111,7 +112,8 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
try:
result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
result =
pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
except ValueError:
localError(conf, n.info, "invalid path: " & n.strVal)
result = n.strVal

View File

@@ -17,29 +17,22 @@ import
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
getIdent(graph.cache, splitFile(filename).name)
proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym =
## returns package symbol (skPackage) for yet to be defined module for fileIdx
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
let name = getModuleIdent(graph, filename)
let info = newLineInfo(fileIdx, 1, 1)
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
let
pck = getPackageName(graph.config, filename.string)
pck2 = if pck.len > 0: pck else: "unknown"
pack = getIdent(graph.cache, pck2)
var packSym = graph.packageSyms.strTableGet(pack)
if packSym == nil:
packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, info)
packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info)
initStrTable(packSym.tab)
graph.packageSyms.strTableAdd(packSym)
else:
let existing = strTableGet(packSym.tab, name)
if existing != nil and existing.info.fileIndex != info.fileIndex:
let existing = strTableGet(packSym.tab, result.name)
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
when false:
# we used to produce an error:
localError(graph.config, info,
localError(graph.config, result.info,
"module names need to be unique per Nimble package; module clashes with " &
toFullPath(graph.config, existing.info.fileIndex))
else:
@@ -47,13 +40,10 @@ proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym =
# to resolve the conflicts:
let pck3 = fakePackageName(graph.config, filename)
# this makes the new `packSym`'s owner be the original `packSym`
packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, info)
packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, result.info)
initStrTable(packSym.tab)
graph.packageSyms.strTableAdd(packSym)
result = packSym
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
let packSym = getPackage(graph, fileIdx)
result.owner = packSym
result.position = int fileIdx
@@ -70,15 +60,13 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
result = PSym(kind: skModule, id: -1, # for better error checking
name: getModuleIdent(graph, filename),
name: getIdent(graph.cache, splitFile(filename).name),
info: newLineInfo(fileIdx, 1, 1))
if not isNimIdentifier(result.name.s):
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
partialInitModule(result, graph, fileIdx, filename)
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
var flags = flags
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
result = graph.getModule(fileIdx)
if result == nil:
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
@@ -86,7 +74,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
result = r
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
result.flags = result.flags + flags
result.id = id
registerModule(graph, result)
else:
@@ -116,7 +104,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
graph.config.notes =
if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
if s.owner.id == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
@@ -137,7 +125,7 @@ proc compileSystemModule*(graph: ModuleGraph) =
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:
fatal(conf, newLineInfo(conf, AbsoluteFile(commandLineDesc), 1, 1), errGenerated,
fatal(conf, newLineInfo(conf, AbsoluteFile"command line", 1, 1), errGenerated,
"command expects a filename")
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
@@ -147,12 +135,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
wantMainModule(conf)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
conf.projectMainIdx2 = projectFile
let packSym = getPackage(graph, projectFile)
graph.config.mainPackageId = packSym.getnimblePkgId
graph.importStack.add projectFile
if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else:

View File

@@ -10,17 +10,6 @@
import
options, strutils, os, tables, ropes, terminal, macros,
lineinfos, pathutils
import std/private/miscdollars
import strutils2
type InstantiationInfo* = typeof(instantiationInfo())
template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true)
template flushDot(conf, stdorr) =
## safe to call multiple times
if conf.lastMsgWasDot:
conf.lastMsgWasDot = false
write(stdorr, "\n")
proc toCChar*(c: char; result: var string) =
case c
@@ -45,6 +34,7 @@ proc makeCString*(s: string): Rope =
res.add('\"')
result.add(rope(res))
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result.fullPath = fullPath
#shallow(result.fullPath)
@@ -67,12 +57,6 @@ when defined(nimpretty):
proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string =
substr(conf.m.fileInfos[fid.int].fullContent, a, b)
proc canonicalCase(path: var string) =
## the idea is to only use this for checking whether a path is already in
## the table but otherwise keep the original case
when FileSystemCaseSensitive: discard
else: toLowerAscii(path)
proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool =
var
canon: AbsoluteFile
@@ -80,7 +64,6 @@ proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool =
canon = canonicalizePath(conf, filename)
except OSError:
canon = filename
canon.string.canonicalCase
result = conf.m.filenameToIndexTbl.hasKey(canon.string)
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool): FileIndex =
@@ -97,19 +80,15 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
# This flag indicates that we are working with such a path here
pseudoPath = true
var canon2: string
forceCopy(canon2, canon.string) # because `canon` may be shallow
canon2.canonicalCase
if conf.m.filenameToIndexTbl.hasKey(canon2):
if conf.m.filenameToIndexTbl.hasKey(canon.string):
isKnownFile = true
result = conf.m.filenameToIndexTbl[canon2]
result = conf.m.filenameToIndexTbl[canon.string]
else:
isKnownFile = false
result = conf.m.fileInfos.len.FileIndex
conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename
else: relativeTo(canon, conf.projectPath)))
conf.m.filenameToIndexTbl[canon2] = result
conf.m.filenameToIndexTbl[canon.string] = result
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool
@@ -129,7 +108,6 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} =
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
const gCmdLineInfo* = newLineInfo(commandLineIdx, 1, 1)
proc concat(strings: openArray[string]): string =
var totalLen = 0
@@ -154,6 +132,7 @@ proc suggestQuit*() =
# this format is understood by many text editors: it is the same that
# Borland and Freepascal use
const
PosFormat = "$1($2, $3) "
KindFormat = " [$1]"
KindColor = fgCyan
ErrorTitle = "Error: "
@@ -166,7 +145,6 @@ const
# but column numbers start with 0, however most editors expect
# first column to be 1, so we need to +1 here
ColOffset* = 1
commandLineDesc* = "command line"
proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len
proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L)
@@ -182,6 +160,9 @@ proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
if i >=% conf.m.msgContext.len: result = unknownLineInfo
else: result = conf.m.msgContext[i].info
const
commandLineDesc = "command line"
template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
if fileIdx.int32 < 0 or conf == nil:
(if fileIdx == commandLineIdx: commandLineDesc else: "???")
@@ -232,36 +213,16 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string =
string toFullPathConsiderDirty(conf, info.fileIndex)
type FilenameOption* = enum
foAbs # absolute path, e.g.: /pathto/bar/foo.nim
foRelProject # relative to project path, e.g.: ../foo.nim
foMagicSauce # magic sauce, shortest of (foAbs, foRelProject)
foName # lastPathPart, e.g.: foo.nim
foStacktrace # if optExcessiveStackTrace: foAbs else: foName
proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string =
case opt
of foAbs: result = toFullPath(conf, fileIdx)
of foRelProject: result = toProjPath(conf, fileIdx)
of foMagicSauce:
let
absPath = toFullPath(conf, fileIdx)
relPath = toProjPath(conf, fileIdx)
result = if (optListFullPaths in conf.globalOptions) or
(relPath.len > absPath.len) or
(relPath.count("..") > 2):
absPath
else:
relPath
of foName: result = toProjPath(conf, fileIdx).lastPathPart
of foStacktrace:
if optExcessiveStackTrace in conf.globalOptions:
result = toFilenameOption(conf, fileIdx, foAbs)
else:
result = toFilenameOption(conf, fileIdx, foName)
proc toMsgFilename*(conf: ConfigRef; info: FileIndex): string =
toFilenameOption(conf, info, foMagicSauce)
let
absPath = toFullPath(conf, info)
relPath = toProjPath(conf, info)
result = if (optListFullPaths in conf.globalOptions) or
(relPath.len > absPath.len) or
(relPath.count("..") > 2):
absPath
else:
relPath
template toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
toMsgFilename(conf, info.fileIndex)
@@ -272,11 +233,10 @@ proc toLinenumber*(info: TLineInfo): int {.inline.} =
proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
result.toLocation(info.filename, info.line, info.column + ColOffset)
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
# consider calling `helpers.lineInfoToString` instead
result = toMsgFilename(conf, info) & "(" & $info.line & ", " &
$(info.col + ColOffset) & ")"
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -301,16 +261,15 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
## This is used for 'nim dump' etc. where we don't have nimsuggest
## support.
#if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if not isNil(conf.writelnHook) and msgSkipHook notin flags:
conf.writelnHook(s)
elif optStdout in conf.globalOptions or msgStdout in flags:
if eStdOut in conf.m.errorOutputs:
flushDot(conf, stdout)
writeLine(stdout, s)
flushFile(stdout)
else:
if eStdErr in conf.m.errorOutputs:
flushDot(conf, stderr)
writeLine(stderr, s)
# On Windows stderr is fully-buffered when piped, regardless of C std.
when defined(windows):
@@ -339,48 +298,40 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
result.add(bindSym"stderr")
for arg in children(args[0][1]):
result.add(arg)
when false:
# not needed because styledWriteLine already ends with resetAttributes
result = newStmtList(result, newCall(bindSym"resetAttributes", bindSym"stderr"))
template callWritelnHook(args: varargs[string, `$`]) =
conf.writelnHook concat(args)
proc msgWrite(conf: ConfigRef; s: string) =
if conf.m.errorOutputs != {}:
let stdOrr =
if optStdout in conf.globalOptions:
stdout
else:
stderr
write(stdOrr, s)
flushFile(stdOrr)
conf.lastMsgWasDot = true # subsequent writes need `flushDot`
template styledMsgWriteln*(args: varargs[typed]) =
if not isNil(conf.writelnHook):
callIgnoringStyle(callWritelnHook, nil, args)
elif optStdout in conf.globalOptions:
if eStdOut in conf.m.errorOutputs:
flushDot(conf, stdout)
callIgnoringStyle(writeLine, stdout, args)
flushFile(stdout)
elif eStdErr in conf.m.errorOutputs:
flushDot(conf, stderr)
if optUseColors in conf.globalOptions:
callStyledWriteLineStderr(args)
else:
callIgnoringStyle(writeLine, stderr, args)
# On Windows stderr is fully-buffered when piped, regardless of C std.
when defined(windows):
flushFile(stderr)
else:
if eStdErr in conf.m.errorOutputs:
if optUseColors in conf.globalOptions:
callStyledWriteLineStderr(args)
else:
callIgnoringStyle(writeLine, stderr, args)
# On Windows stderr is fully-buffered when piped, regardless of C std.
when defined(windows):
flushFile(stderr)
proc msgKindToString*(kind: TMsgKind): string = MsgKindToStr[kind]
proc coordToStr(coord: int): string =
if coord == -1: result = "???"
else: result = $coord
proc msgKindToString*(kind: TMsgKind): string =
# later versions may provide translated error messages
result = MsgKindToStr[kind]
proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) % [arg]
proc getMessageStr(msg: TMsgKind, arg: string): string =
result = msgKindToString(msg) % [arg]
type TErrorHandling* = enum doNothing, doAbort, doRaise
type
TErrorHandling = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File
@@ -394,18 +345,16 @@ proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} =
if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, """
No stack traceback available
To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 for details""" %
[conf.command, "intern.html#debugging-the-compiler".createDocLink])
styledMsgWriteln(fgRed, "No stack traceback available\n" &
"To create a stacktrace, rerun compilation with ./koch temp " &
conf.command & " <file>")
quit 1
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
if msg >= fatalMin and msg <= fatalMax:
if conf.cmd == cmdIdeTools: log(s)
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..warnMax and msg in conf.warningAsErrors):
if msg >= errMin and msg <= errMax:
inc(conf.errorCounter)
conf.exitcode = 1'i8
if conf.errorCounter >= conf.errorMax:
@@ -436,34 +385,80 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
instantiationFrom
else:
instantiationOfFrom.format(context.detail)
styledMsgWriteln(styleBright, conf.toFileLineCol(context.info), " ", resetStyle, message)
styledMsgWriteln(styleBright,
PosFormat % [toMsgFilename(conf, context.info),
coordToStr(context.info.line.int),
coordToStr(context.info.col+ColOffset)],
resetStyle,
message)
info = context.info
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
var
title: string
color: ForegroundColor
kind: string
sev: Severity
case msg
of errMin..errMax:
sev = Severity.Error
writeContext(conf, unknownLineInfo)
title = ErrorTitle
color = ErrorColor
of warnMin..warnMax:
sev = Severity.Warning
if not conf.hasWarn(msg): return
writeContext(conf, unknownLineInfo)
title = WarningTitle
color = WarningColor
kind = WarningsToStr[ord(msg) - ord(warnMin)]
inc(conf.warnCounter)
of hintMin..hintMax:
sev = Severity.Hint
if not conf.hasHint(msg): return
title = HintTitle
color = HintColor
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
inc(conf.hintCounter)
let s = msgKindToString(msg) % args
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, unknownLineInfo,
s & (if kind.len > 0: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind.len > 0:
styledMsgWriteln(color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind))
else:
styledMsgWriteln(color, title, resetStyle, s)
handleError(conf, msg, doAbort, s)
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
rawMessage(conf, msg, [arg])
proc resetAttributes*(conf: ConfigRef) =
if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
terminal.resetAttributes(stderr)
proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) =
conf.m.fileInfos[fileIdx.int32].lines.add line
proc numLines*(conf: ConfigRef, fileIdx: FileIndex): int =
## xxx there's an off by 1 error that should be fixed; if a file ends with "foo" or "foo\n"
## it will return same number of lines (ie, a trailing empty line is discounted)
result = conf.m.fileInfos[fileIdx.int32].lines.len
if result == 0:
proc sourceLine*(conf: ConfigRef; i: TLineInfo): string =
if i.fileIndex.int32 < 0: return ""
if conf.m.fileInfos[i.fileIndex.int32].lines.len == 0:
try:
for line in lines(toFullPathConsiderDirty(conf, fileIdx).string):
addSourceLine conf, fileIdx, line.string
for line in lines(toFullPathConsiderDirty(conf, i)):
addSourceLine conf, i.fileIndex, line.string
except IOError:
discard
result = conf.m.fileInfos[fileIdx.int32].lines.len
proc sourceLine*(conf: ConfigRef; i: TLineInfo): string =
## 1-based index (matches editor line numbers); 1st line is for i.line = 1
## last valid line is `numLines` inclusive
if i.fileIndex.int32 < 0: return ""
let num = numLines(conf, i.fileIndex)
assert i.fileIndex.int32 < conf.m.fileInfos.len
# can happen if the error points to EOF:
if i.line.int > num: return ""
if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return ""
result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1]
@@ -478,127 +473,101 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
of warnMin..warnMax: WarningTitle
of hintMin..hintMax: HintTitle
else: ErrorTitle
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
coordToStr(info.col+ColOffset)] &
title &
getMessageStr(msg, arg)
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.noinline.} =
proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
var
title: string
color: ForegroundColor
kind: string
ignoreMsg = false
sev: Severity
let kind = if msg in warnMin..hintMax and msg != hintUserRaw: $msg else: "" # xxx not sure why hintUserRaw is special
case msg
of errMin..errMax:
sev = Severity.Error
writeContext(conf, info)
title = ErrorTitle
color = ErrorColor
when false:
# we try to filter error messages so that not two error message
# in the same file and line are produced:
# xxx `lastError` is only used in this disabled code; but could be useful to revive
ignoreMsg = conf.m.lastError == info and info != unknownLineInfo and eh != doAbort
if info != unknownLineInfo: conf.m.lastError = info
# we try to filter error messages so that not two error message
# in the same file and line are produced:
#ignoreMsg = lastError == info and eh != doAbort
conf.m.lastError = info
of warnMin..warnMax:
sev = Severity.Warning
ignoreMsg = not conf.hasWarn(msg)
if msg in conf.warningAsErrors:
ignoreMsg = false
title = ErrorTitle
else:
title = WarningTitle
if not ignoreMsg: writeContext(conf, info)
title = WarningTitle
color = WarningColor
kind = WarningsToStr[ord(msg) - ord(warnMin)]
inc(conf.warnCounter)
of hintMin..hintMax:
sev = Severity.Hint
ignoreMsg = not conf.hasHint(msg)
title = HintTitle
color = HintColor
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
inc(conf.hintCounter)
let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
coordToStr(info.col+ColOffset)]
let s = getMessageStr(msg, arg)
let s = if isRaw: arg else: getMessageStr(msg, arg)
if not ignoreMsg:
let loc = if info != unknownLineInfo: conf.toFileLineCol(info) & " " else: ""
var kindmsg = if kind.len > 0: KindFormat % kind else: ""
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, info, s & kindmsg, sev)
conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if msg == hintProcessing:
msgWrite(conf, ".")
if kind.len > 0:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind))
else:
styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg)
if conf.hasHint(hintSource) and info != unknownLineInfo:
conf.writeSurroundingSrc(info)
if hintMsgOrigin in conf.mainPackageNotes:
styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle,
" compiler msg initiated here", KindColor,
KindFormat % $hintMsgOrigin,
resetStyle)
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
if conf.hasHint(hintSource):
conf.writeSurroundingSrc(info)
handleError(conf, msg, eh, s)
template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
let arg = msgKindToString(msg) % args
liMessage(conf, unknownLineInfo, msg, arg, eh = doAbort, instLoc(), isRaw = true)
template rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
liMessage(conf, unknownLineInfo, msg, arg, eh = doAbort, instLoc())
template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal' was executed.
proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal'
# was executed.
conf.m.errorOutputs = {eStdOut, eStdErr}
liMessage(conf, info, msg, arg, doAbort, instLoc())
liMessage(conf, info, msg, arg, doAbort)
template globalAssert*(conf: ConfigRef; cond: untyped, info: TLineInfo = unknownLineInfo, arg = "") =
## avoids boilerplate
if not cond:
var arg2 = "'$1' failed" % [astToStr(cond)]
if arg.len > 0: arg2.add "; " & astToStr(arg) & ": " & arg
liMessage(conf, info, errGenerated, arg2, doRaise, instLoc())
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doRaise)
template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
## `local` means compilation keeps going until errorMax is reached (via `doNothing`),
## `global` means it stops.
liMessage(conf, info, msg, arg, doRaise, instLoc())
proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doRaise)
template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doRaise, instLoc())
proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing, instLoc())
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing)
template localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing, instLoc())
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) =
localError(conf, info, format % params)
template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) =
liMessage(conf, info, errGenerated, format % params, doNothing, instLoc())
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing, instLoc())
proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) =
proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort, info2)
liMessage(conf, info, errInternal, errMsg, doAbort)
template internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
internalErrorImpl(conf, info, errMsg, instLoc())
proc internalError*(conf: ConfigRef; errMsg: string) =
if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, unknownLineInfo)
rawMessage(conf, errInternal, errMsg)
template internalError*(conf: ConfigRef; errMsg: string) =
internalErrorImpl(conf, unknownLineInfo, errMsg, instLoc())
template assertNotNil*(conf: ConfigRef; e): untyped =
if e == nil: internalError(conf, $instantiationInfo())
e
template internalAssert*(conf: ConfigRef, e: bool) =
# xxx merge with `globalAssert`
if not e:
const info2 = instLoc()
let arg = info2.toFileLineCol
internalErrorImpl(conf, unknownLineInfo, arg, info2)
template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) =
let m = "'$2' should be: '$1'" % [beau, got]
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
if not e: internalError(conf, $instantiationInfo())
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
@@ -608,9 +577,25 @@ proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
else:
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
template listMsg(title, r) =
msgWriteln(conf, title)
for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", $a])
proc listWarnings*(conf: ConfigRef) =
msgWriteln(conf, "Warnings:")
for warn in warnMin..warnMax:
msgWriteln(conf, " [$1] $2" % [
if warn in conf.notes: "x" else: " ",
lineinfos.WarningsToStr[ord(warn) - ord(warnMin)]
])
proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax)
proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax)
proc listHints*(conf: ConfigRef) =
msgWriteln(conf, "Hints:")
for hint in hintMin..hintMax:
msgWriteln(conf, " [$1] $2" % [
if hint in conf.notes: "x" else: " ",
lineinfos.HintsToStr[ord(hint) - ord(hintMin)]
])
proc lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) =
let m = "'$2' should be: '$1'" % [beau, got]
if optStyleError in conf.globalOptions:
localError(conf, info, m)
else:
message(conf, info, hintName, m)

View File

@@ -22,7 +22,3 @@ define:useStdoutAsStdmsg
#define:useNodeIds
#gc:markAndSweep
@if nimHasWarningObservableStores:
warning[ObservableStores]: off
@end

View File

@@ -22,10 +22,9 @@ import
commands, options, msgs,
extccomp, strutils, os, main, parseopt,
idents, lineinfos, cmdlinehelper,
pathutils, modulegraphs
pathutils
from browsers import openDefaultBrowser
from nodejs import findNodeJs
include nodejs
when hasTinyCBackend:
import tccgen
@@ -34,6 +33,20 @@ when defined(profiler) or defined(memProfiler):
{.hint: "Profiling support is turned on!".}
import nimprof
proc prependCurDir(f: AbsoluteFile): AbsoluteFile =
when defined(unix):
if os.isAbsolute(f.string): result = f
else: result = AbsoluteFile("./" & f.string)
else:
result = f
proc addCmdPrefix*(result: var string, kind: CmdLineKind) =
# consider moving this to std/parseopt
case kind
of cmdLongOption: result.add "--"
of cmdShortOption: result.add "-"
of cmdArgument, cmdEnd: discard
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
@@ -53,7 +66,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
config.commandLine.add ':'
config.commandLine.add p.val.quoteShell
if p.key == "": # `-` was passed to indicate main project is stdin
if p.key == " ":
p.key = "-"
if processArgument(pass, p, argsCount, config): break
else:
@@ -64,13 +77,14 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
if processArgument(pass, p, argsCount, config): break
if pass == passCmd2:
if {optRun, optWasNimscript} * config.globalOptions == {} and
config.arguments.len > 0 and config.command.normalize notin ["run", "e", "r"]:
config.arguments.len > 0 and config.command.normalize notin ["run", "e"]:
rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
supportsStdinFile: true,
processCmdLine: processCmdLine
processCmdLine: processCmdLine,
mainCommand: mainCommand
)
self.initDefinesProg(conf, "nim_compiler")
if paramCount() == 0:
@@ -78,9 +92,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
return
self.processCmdLineAndProjectPath(conf)
var graph = newModuleGraph(cache, conf)
if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return
mainCommand(graph)
if not self.loadConfigsAndRunMainCommand(cache, conf): return
if conf.hasHint(hintGCStats): echo(GC_getStatistics())
#echo(GC_getStatistics())
if conf.errorCounter != 0: return
@@ -88,23 +100,11 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
if conf.cmd == cmdRun:
tccgen.run(conf, conf.arguments)
if optRun in conf.globalOptions:
let output = conf.absOutFile
case conf.cmd
of cmdCompileToBackend:
var cmdPrefix = ""
case conf.backend
of backendC, backendCpp, backendObjc: discard
of backendJs: cmdPrefix = findNodeJs() & " "
else: doAssert false, $conf.backend
execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments)
of cmdDoc, cmdRst2html:
if conf.arguments.len > 0:
# reserved for future use
rawMessage(conf, errGenerated, "'$1 cannot handle arguments" % [$conf.cmd])
openDefaultBrowser($output)
var ex = quoteShell conf.absOutFile
if conf.cmd == cmdCompileToJS:
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
else:
# support as needed
rawMessage(conf, errGenerated, "'$1 cannot handle --run" % [$conf.cmd])
execExternalProgram(conf, ex & ' ' & conf.arguments)
when declared(GC_setMaxPause):
GC_setMaxPause 2_000

View File

@@ -134,3 +134,30 @@ proc nimblePath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
if i != -1:
conf.nimblePaths.delete(i)
conf.nimblePaths.insert(path, 0)
when isMainModule:
proc v(s: string): Version = s.newVersion
# #head is special in the sense that it's assumed to always be newest.
doAssert v"1.0" < v"#head"
doAssert v"1.0" < v"1.1"
doAssert v"1.0.1" < v"1.1"
doAssert v"1" < v"1.1"
doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer.
doAssert v"#a111" < v"#head"
let conf = newConfigRef()
var rr = newStringTable()
addPackage conf, rr, "irc-#a111", unknownLineInfo
addPackage conf, rr, "irc-#head", unknownLineInfo
addPackage conf, rr, "irc-0.1.0", unknownLineInfo
#addPackage conf, rr, "irc", unknownLineInfo
#addPackage conf, rr, "another", unknownLineInfo
addPackage conf, rr, "another-0.1", unknownLineInfo
addPackage conf, rr, "ab-0.1.3", unknownLineInfo
addPackage conf, rr, "ab-0.1", unknownLineInfo
addPackage conf, rr, "justone-1.0", unknownLineInfo
doAssert toSeq(rr.chosen) ==
@["irc-#head", "another-0.1", "ab-0.1.3", "justone-1.0"]

View File

@@ -16,13 +16,13 @@ import
# ---------------- configuration file parser -----------------------------
# we use Nim's scanner here to save space and work
proc ppGetTok(L: var Lexer, tok: var Token) =
proc ppGetTok(L: var TLexer, tok: var TToken) =
# simple filter
rawGetTok(L, tok)
while tok.tokType in {tkComment}: rawGetTok(L, tok)
proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool
proc parseAtom(L: var Lexer, tok: var Token; config: ConfigRef): bool =
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
if tok.tokType == tkParLe:
ppGetTok(L, tok)
result = parseExpr(L, tok, config)
@@ -35,21 +35,21 @@ proc parseAtom(L: var Lexer, tok: var Token; config: ConfigRef): bool =
result = isDefined(config, tok.ident.s)
ppGetTok(L, tok)
proc parseAndExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool =
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAtom(L, tok, config)
while tok.tokType == tkAnd:
ppGetTok(L, tok) # skip "and"
var b = parseAtom(L, tok, config)
result = result and b
proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool =
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAndExpr(L, tok, config)
while tok.tokType == tkOr:
ppGetTok(L, tok) # skip "or"
var b = parseAndExpr(L, tok, config)
result = result or b
proc evalppIf(L: var Lexer, tok: var Token; config: ConfigRef): bool =
proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok, config)
if tok.tokType == tkColon: ppGetTok(L, tok)
@@ -57,7 +57,7 @@ proc evalppIf(L: var Lexer, tok: var Token; config: ConfigRef): bool =
#var condStack: seq[bool] = @[]
proc doEnd(L: var Lexer, tok: var Token; condStack: var seq[bool]) =
proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
ppGetTok(L, tok) # skip 'end'
setLen(condStack, high(condStack))
@@ -66,21 +66,21 @@ type
TJumpDest = enum
jdEndif, jdElseEndif
proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool])
proc doElse(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
ppGetTok(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack)
proc doElif(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
var res = evalppIf(L, tok, config)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
else: condStack[high(condStack)] = true
proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool]) =
var nestedIfs = 0
while true:
@@ -110,7 +110,7 @@ proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: Conf
else:
ppGetTok(L, tok)
proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
@@ -149,16 +149,16 @@ proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack:
else:
lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok)
proc confTok(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
ppGetTok(L, tok)
while tok.ident != nil and tok.ident.s == "@":
parseDirective(L, tok, config, condStack) # else: give the token to the parser
proc checkSymbol(L: Lexer, tok: Token) =
proc checkSymbol(L: TLexer, tok: TToken) =
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
proc parseAssignment(L: var Lexer, tok: var Token;
proc parseAssignment(L: var TLexer, tok: var TToken;
config: ConfigRef; condStack: var seq[bool]) =
if tok.ident != nil:
if tok.ident.s == "-" or tok.ident.s == "--":
@@ -211,8 +211,8 @@ proc parseAssignment(L: var Lexer, tok: var Token;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: Lexer
tok: Token
L: TLexer
tok: TToken
stream: PLLStream
stream = llStreamOpen(filename, fmRead)
if stream != nil:

View File

@@ -10,9 +10,9 @@
## exposes the Nim VM to clients.
import
ast, astalgo, modules, passes, condsyms,
options, sem, semdata, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
passaux, scriptconfig
options, sem, semdata, llstream, vm, vmdef,
modulegraphs, idents, os, pathutils, passaux,
scriptconfig
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
@@ -81,9 +81,6 @@ proc findNimStdLib*(): string =
## Returns "" on failure.
try:
let nimexe = os.findExe("nim")
# this can't work with choosenim shims, refs https://github.com/dom96/choosenim/issues/189
# it'd need `nim dump --dump.format:json . | jq -r .libpath`
# which we should simplify as `nim dump --key:libpath`
if nimexe.len == 0: return ""
result = nimexe.splitPath()[0] /../ "lib"
if not fileExists(result / "system.nim"):
@@ -96,22 +93,20 @@ proc findNimStdLib*(): string =
proc findNimStdLibCompileTime*(): string =
## Same as ``findNimStdLib`` but uses source files used at compile time,
## and asserts on error.
const exe = getCurrentCompilerExe()
result = exe.splitFile.dir.parentDir / "lib"
const sourcePath = currentSourcePath()
result = sourcePath.parentDir.parentDir / "lib"
doAssert fileExists(result / "system.nim"), "result:" & result
proc createInterpreter*(scriptName: string;
searchPaths: openArray[string];
flags: TSandboxFlags = {},
defines = @[("nimscript", "true")],
registerOps = true): Interpreter =
flags: TSandboxFlags = {}): Interpreter =
var conf = newConfigRef()
var cache = newIdentCache()
var graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
initDefines(conf.symbols)
for define in defines:
defineSymbol(conf.symbols, define[0], define[1])
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(graph, semPass)
registerPass(graph, evalPass)
@@ -124,8 +119,6 @@ proc createInterpreter*(scriptName: string;
var vm = newCtx(m, cache, graph)
vm.mode = emRepl
vm.features = flags
if registerOps:
vm.registerAdditionalOps() # Required to register parts of stdlib modules
graph.vm = vm
graph.compileSystemModule()
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName)
@@ -134,15 +127,9 @@ proc destroyInterpreter*(i: Interpreter) =
## destructor.
discard "currently nothing to do."
proc registerErrorHook*(i: Interpreter, hook:
proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.gcsafe.}) =
i.graph.config.structuredErrorHook = hook
proc runRepl*(r: TLLRepl;
searchPaths: openArray[string];
supportNimscript: bool) =
## deadcode but please don't remove... might be revived
var conf = newConfigRef()
var cache = newIdentCache()
var graph = newModuleGraph(cache, conf)
@@ -152,7 +139,7 @@ proc runRepl*(r: TLLRepl;
if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
conf.cmd = cmdInteractive
conf.setErrorMaxHighMaybe
conf.errorMax = high(int)
initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")

View File

@@ -39,9 +39,7 @@ const
type
TBaseLexer* = object of RootObj
bufpos*: int
buf*: cstring
bufStorage: string
bufLen: int
buf*: string
stream*: PLLStream # we read from this stream
lineNumber*: int # the current line number
# private data:
@@ -77,8 +75,8 @@ proc fillBuffer(L: var TBaseLexer) =
oldBufLen: int
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.bufLen - L.sentinel - 1
assert(L.sentinel < L.buf.len)
toCopy = L.buf.len - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
moveMem(addr L.buf[0], addr L.buf[L.sentinel + 1], toCopy)
@@ -92,7 +90,7 @@ proc fillBuffer(L: var TBaseLexer) =
# compute sentinel:
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
assert(s < L.buf.len)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
@@ -101,18 +99,16 @@ proc fillBuffer(L: var TBaseLexer) =
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.bufStorage.setLen(L.bufLen)
L.buf = L.bufStorage
assert(L.bufLen - oldBufLen == oldBufLen)
oldBufLen = L.buf.len
L.buf.setLen(L.buf.len * 2)
assert(L.buf.len - oldBufLen == oldBufLen)
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
oldBufLen)
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
L.sentinel = oldBufLen + charsRead
break
s = L.bufLen - 1
s = L.buf.len - 1
proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
assert(pos <= L.sentinel)
@@ -146,9 +142,7 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
assert(bufLen > 0)
L.bufpos = 0
L.offsetBase = 0
L.bufStorage = newString(bufLen)
L.buf = L.bufStorage
L.bufLen = bufLen
L.buf = newString(bufLen)
L.sentinel = bufLen - 1
L.lineStart = 0
L.lineNumber = 1 # lines start at 1
@@ -162,9 +156,9 @@ proc getColNumber(L: TBaseLexer, pos: int): int =
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
result = ""
var i = L.lineStart
while L.buf[i] notin {CR, LF, EndOfFile}:
result.add L.buf[i]
inc i
result.add "\n"
while not (L.buf[i] in {CR, LF, EndOfFile}):
result.add(L.buf[i])
inc(i)
result.add("\n")
if marker:
result.add spaces(getColNumber(L, L.bufpos)) & '^' & "\n"
result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")

View File

@@ -1,47 +0,0 @@
##[
Represents absolute paths, but using a symbolic variables (eg $nimr) which can be
resolved at runtime; this avoids hardcoding at compile time absolute paths so
that the project root can be relocated.
xxx consider some refactoring with $nim/testament/lib/stdtest/specialpaths.nim;
specialpaths is simpler because it doesn't need variables to be relocatable at
runtime (eg for use in testament)
interpolation variables:
$nimr: such that `$nimr/lib/system.nim` exists (avoids confusion with $nim binary)
in compiler, it's obtainable via getPrefixDir(); for other tools (eg koch),
this could be getCurrentDir() or getAppFilename().parentDir.parentDir,
depending on use case
Unstable API
]##
import os, strutils
const
docCss* = "$nimr/doc/nimdoc.css"
docHackNim* = "$nimr/tools/dochack/dochack.nim"
docHackJs* = docHackNim.changeFileExt("js")
docHackJsFname* = docHackJs.lastPathPart
theindexFname* = "theindex.html"
nimdocOutCss* = "nimdoc.out.css"
# `out` to make it easier to use with gitignore in user's repos
htmldocsDirname* = "htmldocs"
dotdotMangle* = "_._" ## refs #13223
# if this changes, make sure it's consistent with `esc` and `escapeLink`
# lots of other obvious options won't work, see #14454; `_` could work too
proc interp*(path: string, nimr: string): string =
result = path % ["nimr", nimr]
doAssert '$' notin result, $(path, nimr, result) # avoids un-interpolated variables in output
proc getDocHacksJs*(nimr: string, nim = getCurrentCompilerExe(), forceRebuild = false): string =
## return absolute path to dochack.js, rebuilding if it doesn't exist or if
## `forceRebuild`.
let docHackJs2 = docHackJs.interp(nimr = nimr)
if forceRebuild or not docHackJs2.fileExists:
let cmd = "$nim js -d:release $file" % ["nim", nim.quoteShell, "file", docHackNim.interp(nimr = nimr).quoteShell]
echo "getDocHacksJs: cmd: " & cmd
doAssert execShellCmd(cmd) == 0, $(cmd)
doAssert docHackJs2.fileExists
result = docHackJs2

View File

@@ -58,18 +58,18 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
return true
result = false
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
var first, j: Int128
first = firstOrd(conf, s.typ[0])
bitSetInit(result, int(getSize(conf, s.typ)))
bitSetInit(b, int(getSize(conf, s.typ)))
for i in 0..<s.len:
if s[i].kind == nkRange:
j = getOrdValue(s[i][0], first)
while j <= getOrdValue(s[i][1], first):
bitSetIncl(result, toInt64(j - first))
bitSetIncl(b, toInt64(j - first))
inc(j)
else:
bitSetIncl(result, toInt64(getOrdValue(s[i]) - first))
bitSetIncl(b, toInt64(getOrdValue(s[i]) - first))
proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
@@ -106,8 +106,9 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
inc(e)
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
var x = toBitSet(conf, a)
let y = toBitSet(conf, b)
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
op(x, y)
result = toTreeSet(conf, x, a.typ, a.info)
@@ -117,26 +118,31 @@ proc intersectSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSe
proc symdiffSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc containsSets*(conf: ConfigRef; a, b: PNode): bool =
let x = toBitSet(conf, a)
let y = toBitSet(conf, b)
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
result = bitSetContains(x, y)
proc equalSets*(conf: ConfigRef; a, b: PNode): bool =
let x = toBitSet(conf, a)
let y = toBitSet(conf, b)
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
result = bitSetEquals(x, y)
proc complement*(conf: ConfigRef; a: PNode): PNode =
var x = toBitSet(conf, a)
var x: TBitSet
toBitSet(conf, a, x)
for i in 0..high(x): x[i] = not x[i]
result = toTreeSet(conf, x, a.typ, a.info)
proc deduplicate*(conf: ConfigRef; a: PNode): PNode =
let x = toBitSet(conf, a)
var x: TBitSet
toBitSet(conf, a, x)
result = toTreeSet(conf, x, a.typ, a.info)
proc cardSet*(conf: ConfigRef; a: PNode): BiggestInt =
let x = toBitSet(conf, a)
var x: TBitSet
toBitSet(conf, a, x)
result = bitSetCard(x)
proc setHasRange*(s: PNode): bool =

View File

@@ -1,287 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Optimizer:
## - elide 'wasMoved(x); destroy(x)' pairs
## - recognize "all paths lead to 'wasMoved(x)'"
import
ast, renderer, idents, intsets
from trees import exprStructuralEquivalent
const
nfMarkForDeletion = nfNone # faster than a lookup table
type
BasicBlock = object
wasMovedLocs: seq[PNode]
kind: TNodeKind
hasReturn, hasBreak: bool
label: PSym # can be nil
parent: ptr BasicBlock
Con = object
somethingTodo: bool
inFinally: int
proc nestedBlock(parent: var BasicBlock; kind: TNodeKind): BasicBlock =
BasicBlock(wasMovedLocs: @[], kind: kind, hasReturn: false, hasBreak: false,
label: nil, parent: addr(parent))
proc breakStmt(b: var BasicBlock; n: PNode) =
var it = addr(b)
while it != nil:
it.wasMovedLocs.setLen 0
it.hasBreak = true
if n.kind == nkSym:
if it.label == n.sym: break
else:
# unnamed break leaves the block is nkWhileStmt or the like:
if it.kind in {nkWhileStmt, nkBlockStmt, nkBlockExpr}: break
it = it.parent
proc returnStmt(b: var BasicBlock) =
b.hasReturn = true
var it = addr(b)
while it != nil:
it.wasMovedLocs.setLen 0
it = it.parent
proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} =
if this.hasReturn:
parent.wasMovedLocs.setLen 0
parent.hasReturn = true
proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool =
result = false
for i in 0..<branch.len:
if exprStructuralEquivalent(branch[i][1].skipAddr, moveTarget,
strictSymEquality = true):
result = true
matches.incl i
proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
# keep all 'wasMoved(x)' calls in summary that are also in 'branch':
var i = 0
var matches = initIntSet()
while i < summary.len:
if wasMovedTarget(matches, branch, summary[i][1].skipAddr):
inc i
else:
summary.del i
for m in matches:
summary.add branch[m]
proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
var i = 0
while i < c.wasMovedLocs.len:
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipAddr, x,
strictSymEquality = true):
c.wasMovedLocs.del i
else:
inc i
proc wasMovedDestroyPair(c: var Con; b: var BasicBlock; d: PNode) =
var i = 0
while i < b.wasMovedLocs.len:
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipAddr, d[1].skipAddr,
strictSymEquality = true):
b.wasMovedLocs[i].flags.incl nfMarkForDeletion
c.somethingTodo = true
d.flags.incl nfMarkForDeletion
b.wasMovedLocs.del i
else:
inc i
proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
case n.kind
of nkCallKinds:
var special = false
var reverse = false
if n[0].kind == nkSym:
let s = n[0].sym
if s.magic == mWasMoved:
b.wasMovedLocs.add n
special = true
elif s.name.s == "=destroy":
if c.inFinally > 0 and (b.hasReturn or b.hasBreak):
discard "cannot optimize away the destructor"
else:
c.wasMovedDestroyPair b, n
special = true
elif s.name.s == "=sink":
reverse = true
if not special:
if not reverse:
for i in 0 ..< n.len:
analyse(c, b, n[i])
else:
#[ Test tmatrix.test3:
Prevent this from being elided. We should probably
find a better solution...
`=sink`(b, - (
let blitTmp = b;
wasMoved(b);
blitTmp + a)
`=destroy`(b)
]#
for i in countdown(n.len-1, 0):
analyse(c, b, n[i])
if canRaise(n[0]): returnStmt(b)
of nkSym:
# any usage of the location before destruction implies we
# cannot elide the 'wasMoved(x)':
b.invalidateWasMoved n
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
discard "do not follow the construct"
of nkAsgn, nkFastAsgn:
# reverse order, see remark for `=sink`:
analyse(c, b, n[1])
analyse(c, b, n[0])
of nkIfStmt, nkIfExpr:
let isExhaustive = n[^1].kind in {nkElse, nkElseExpr}
var wasMovedSet: seq[PNode] = @[]
for i in 0 ..< n.len:
var branch = nestedBlock(b, n[i].kind)
analyse(c, branch, n[i])
mergeBasicBlockInfo(b, branch)
if isExhaustive:
if i == 0:
wasMovedSet = move(branch.wasMovedLocs)
else:
wasMovedSet.intersect(branch.wasMovedLocs)
for i in 0..<wasMovedSet.len:
b.wasMovedLocs.add wasMovedSet[i]
of nkCaseStmt:
let isExhaustive = skipTypes(n[0].typ,
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString} or
n[^1].kind == nkElse
analyse(c, b, n[0])
var wasMovedSet: seq[PNode] = @[]
for i in 1 ..< n.len:
var branch = nestedBlock(b, n[i].kind)
analyse(c, branch, n[i])
mergeBasicBlockInfo(b, branch)
if isExhaustive:
if i == 1:
wasMovedSet = move(branch.wasMovedLocs)
else:
wasMovedSet.intersect(branch.wasMovedLocs)
for i in 0..<wasMovedSet.len:
b.wasMovedLocs.add wasMovedSet[i]
of nkTryStmt:
for i in 0 ..< n.len:
var tryBody = nestedBlock(b, nkTryStmt)
analyse(c, tryBody, n[i])
mergeBasicBlockInfo(b, tryBody)
of nkWhileStmt:
analyse(c, b, n[0])
var loopBody = nestedBlock(b, nkWhileStmt)
analyse(c, loopBody, n[1])
mergeBasicBlockInfo(b, loopBody)
of nkBlockStmt, nkBlockExpr:
var blockBody = nestedBlock(b, n.kind)
if n[0].kind == nkSym:
blockBody.label = n[0].sym
analyse(c, blockBody, n[1])
mergeBasicBlockInfo(b, blockBody)
of nkBreakStmt:
breakStmt(b, n[0])
of nkReturnStmt, nkRaiseStmt:
for child in n: analyse(c, b, child)
returnStmt(b)
of nkFinally:
inc c.inFinally
for child in n: analyse(c, b, child)
dec c.inFinally
else:
for child in n: analyse(c, b, child)
proc opt(c: Con; n, parent: PNode; parentPos: int) =
template recurse() =
let x = shallowCopy(n)
for i in 0 ..< n.len:
opt(c, n[i], x, i)
parent[parentPos] = x
case n.kind
of nkCallKinds:
if nfMarkForDeletion in n.flags:
parent[parentPos] = newNodeI(nkEmpty, n.info)
else:
recurse()
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr,
nkMixinStmt, nkBindStmt:
parent[parentPos] = n
else:
recurse()
proc optimize*(n: PNode): PNode =
# optimize away simple 'wasMoved(x); destroy(x)' pairs.
#[ Unfortunately this optimization is only really safe when no exceptions
are possible, see for example:
proc main(inp: string; cond: bool) =
if cond:
try:
var s = ["hi", inp & "more"]
for i in 0..4:
use s
consume(s)
wasMoved(s)
finally:
destroy(s)
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
var c: Con
var b: BasicBlock
analyse(c, b, n)
if c.somethingTodo:
result = shallowCopy(n)
for i in 0 ..< n.safeLen:
opt(c, n[i], result, i)
else:
result = n

View File

@@ -9,7 +9,7 @@
import
os, strutils, strtabs, sets, lineinfos, platform,
prefixmatches, pathutils, nimpaths, tables
prefixmatches, pathutils
from terminal import isatty
from times import utc, fromUnix, local, getTime, format, DateTime
@@ -19,13 +19,13 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2021"
copyrightYear* = "2020"
type # please make sure we have under 32 options
# (improves code efficiency a lot!)
TOption* = enum # **keep binary compatible**
optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
optOverflowCheck, optRefCheck,
optOverflowCheck, optNilCheck, optRefCheck,
optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck,
optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize,
@@ -39,9 +39,10 @@ type # please make sure we have under 32 options
# evaluation
optTrMacros, # en/disable pattern matching
optMemTracker,
optLaxStrings,
optNilSeqs,
optOldAst,
optSinkInference # 'sink T' inference
optCursorInference
TOptions* = set[TOption]
@@ -56,7 +57,6 @@ type # please make sure we have under 32 options
optGenScript, # generate a script file to compile the *.c files
optGenMapping, # generate a mapping file
optRun, # run the compiled project
optUseNimcache, # save artifacts (including binary) in $nimcache
optStyleHint, # check that the names adhere to NEP-1
optStyleError, # enforce that the names adhere to NEP-1
optStyleUsages, # only enforce consistent **usages** of the symbol
@@ -78,7 +78,7 @@ type # please make sure we have under 32 options
optIdeTerse # idetools: use terse descriptions
optExcessiveStackTrace # fully qualified module filenames
optShowAllMismatches # show all overloading resolution candidates
optWholeProject # for 'doc': output any dependency
optWholeProject # for 'doc2': output any dependency
optDocInternal # generate documentation for non-exported symbols
optMixedMode # true if some module triggered C++ codegen
optListFullPaths # use full paths in toMsgFilename
@@ -91,14 +91,12 @@ type # please make sure we have under 32 options
# implementation
optOwnedRefs # active if the Nim compiler knows about 'owned'.
optMultiMethods
optNimV019
optBenchmarkVM # Enables cpuTime() in the VM
optProduceAsm # produce assembler code
optPanics # turn panics (sysFatal) into a process termination
optNimV1Emulation # emulate Nim v1.0
optNimV12Emulation # emulate Nim v1.2
optSourcemap
optProfileVM # enable VM profiler
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
TGlobalOptions* = set[TGlobalOption]
@@ -106,26 +104,12 @@ const
harmlessOptions* = {optForceFullMake, optNoLinking, optRun,
optUseColors, optStdout}
type
TBackend* = enum
backendInvalid = "" # for parseEnum
backendC = "c"
backendCpp = "cpp" # was cmdCompileToCpp
backendJs = "js" # was cmdCompileToJS
backendObjc = "objc" # was cmdCompileToOC
# backendNimscript = "nimscript" # this could actually work
# backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
type
TCommands* = enum # Nim's commands
# **keep binary compatible**
cmdNone,
cmdCompileToC, # deadcode
cmdCompileToCpp, # deadcode
cmdCompileToOC, # deadcode
cmdCompileToJS, # deadcode
cmdCompileToLLVM, # deadcode
cmdInterpret, cmdPretty, cmdDoc,
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdDump,
cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging)
@@ -137,11 +121,11 @@ type
cmdInteractive, # start interactive session
cmdRun, # run the project via TCC backend
cmdJsonScript # compile a .json build file
cmdCompileToBackend, # compile to backend in TBackend
TStringSeq* = seq[string]
TGCMode* = enum # the selected GC
gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc,
gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo
gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc,
gcHooks,
gcRefc, gcV2, gcGo
# gcRefc and the GCs that follow it use a write barrier,
# as far as usesWriteBarrier() is concerned
@@ -157,16 +141,13 @@ type
destructor,
notnil,
dynamicBindSym,
forLoopMacros, # not experimental anymore; remains here for backwards compatibility
forLoopMacros,
caseStmtMacros,
codeReordering,
compiletimeFFI,
## This requires building nim with `-d:nimHasLibFFI`
## which itself requires `nimble install libffi`, see #10150
## Note: this feature can't be localized with {.push.}
vmopsDanger,
strictFuncs,
views
LegacyFeature* = enum
allowSemcheckedAstModification,
@@ -182,8 +163,8 @@ type
disabledSf, writeOnlySf, readOnlySf, v2Sf
TSystemCC* = enum
ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc,
ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl
ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl
ExceptionSystem* = enum
excNone, # no exception system selected yet
@@ -223,24 +204,15 @@ type
version*: int
Suggestions* = seq[Suggest]
ProfileInfo* = object
time*: float
count*: int
ProfileData* = ref object
data*: TableRef[TLineInfo, ProfileInfo]
ConfigRef* {.acyclic.} = ref object ## every global configuration
ConfigRef* = ref object ## every global configuration
## fields marked with '*' are subject to
## the incremental compilation mechanisms
## (+) means "part of the dependency"
backend*: TBackend # set via `nim x` or `nim --backend:x`
target*: Target # (+)
linesCompiled*: int # all lines that have been compiled
options*: TOptions # (+)
globalOptions*: TGlobalOptions # (+)
macrosToExpand*: StringTableRef
arcToExpand*: StringTableRef
m*: MsgConfig
evalTemplateCounter*: int
evalMacroCounter*: int
@@ -267,7 +239,6 @@ type
cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline
foreignPackageNotes*: TNoteKinds
notes*: TNoteKinds # notes after resolving all logic(defaults, verbosity)/cmdline/configs
warningAsErrors*: TNoteKinds
mainPackageNotes*: TNoteKinds
mainPackageId*: int
errorCounter*: int
@@ -285,16 +256,13 @@ type
lazyPaths*: seq[AbsoluteDir]
outFile*: RelativeFile
outDir*: AbsoluteDir
jsonBuildFile*: AbsoluteFile
prefixDir*, libpath*, nimcacheDir*: AbsoluteDir
dllOverrides, moduleOverrides*, cfileSpecificOptions*: StringTableRef
projectName*: string # holds a name like 'nim'
projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/
projectFull*: AbsoluteFile # projectPath/projectName
projectIsStdin*: bool # whether we're compiling from stdin
lastMsgWasDot*: bool # the last compiler message was a single '.'
projectMainIdx*: FileIndex # the canonical path id of the main module
projectMainIdx2*: FileIndex # consider merging with projectMainIdx
command*: string # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] # any arguments after the main command
commandLine*: string
@@ -305,7 +273,6 @@ type
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
docRoot*: string ## see nim --fullhelp for --docRoot
docCmd*: string ## see nim --fullhelp for --docCmd
# the used compiler
cIncludes*: seq[AbsoluteDir] # directories to search for included files
@@ -328,15 +295,6 @@ type
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.closure, gcsafe.}
cppCustomNamespace*: string
vmProfileData*: ProfileData
proc assignIfDefault*[T](result: var T, val: T, def = default(T)) =
## if `result` was already assigned to a value (that wasn't `def`), this is a noop.
if result == def: result = val
template setErrorMaxHighMaybe*(conf: ConfigRef) =
## do not stop after first error (but honor --errorMax if provided)
assignIfDefault(conf.errorMax, high(int))
proc setNoteDefaults*(conf: ConfigRef, note: TNoteKind, enabled = true) =
template fun(op) =
@@ -351,10 +309,7 @@ proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) =
if enabled: incl(conf.notes, note) else: excl(conf.notes, note)
proc hasHint*(conf: ConfigRef, note: TNoteKind): bool =
if optHints notin conf.options: false
elif note in {hintConf}: # could add here other special notes like hintSource
note in conf.mainPackageNotes
else: note in conf.notes
optHints in conf.options and note in conf.notes
proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool {.inline.} =
optWarns in conf.options and note in conf.notes
@@ -370,14 +325,14 @@ template depConfigFields*(fn) {.dirty.} =
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
const
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
optStyleCheck}
DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
optTrMacros, optStyleCheck, optCursorInference}
optTrMacros, optNilCheck, optStyleCheck, optSinkInference}
DefaultGlobalOptions* = {optThreadAnalysis,
optExcessiveStackTrace, optListFullPaths}
@@ -405,9 +360,6 @@ template newPackageCache*(): untyped =
else:
modeCaseSensitive)
proc newProfileData(): ProfileData =
ProfileData(data: newTable[TLineInfo, ProfileInfo]())
proc newConfigRef*(): ConfigRef =
result = ConfigRef(
selectedGC: gcRefc,
@@ -416,7 +368,6 @@ proc newConfigRef*(): ConfigRef =
options: DefaultOptions,
globalOptions: DefaultGlobalOptions,
macrosToExpand: newStringTable(modeStyleInsensitive),
arcToExpand: newStringTable(modeStyleInsensitive),
m: initMsgConfig(),
evalExpr: "",
cppDefines: initHashSet[string](),
@@ -450,7 +401,7 @@ proc newConfigRef*(): ConfigRef =
cIncludes: @[], # directories to search for included files
cLibs: @[], # directories to search for lib files
cLinkedLibs: @[], # libraries to link
backend: backendInvalid,
externalToLink: @[],
linkOptionsCmd: "",
compileOptionsCmd: @[],
@@ -461,7 +412,6 @@ proc newConfigRef*(): ConfigRef =
arguments: "",
suggestMaxResults: 10_000,
maxLoopIterationsVM: 10_000_000,
vmProfileData: newProfileData(),
)
setTargetFromSystem(result.target)
# enable colors by default on terminals
@@ -499,7 +449,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
osAndroid, osNintendoSwitch, osFreeRTOS}
osAndroid, osNintendoSwitch}
of "linux":
result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd":
@@ -515,10 +465,6 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
of "sunos": result = conf.target.targetOS == osSolaris
of "nintendoswitch":
result = conf.target.targetOS == osNintendoSwitch
of "freertos":
result = conf.target.targetOS == osFreeRTOS
of "lwip":
result = conf.target.targetOS in {osFreeRTOS}
of "littleendian": result = CPU[conf.target.targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[conf.target.targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
@@ -553,9 +499,8 @@ const
DefaultConfigNims* = RelativeFile"config.nims"
DocConfig* = RelativeFile"nimdoc.cfg"
DocTexConfig* = RelativeFile"nimdoc.tex.cfg"
htmldocsDir* = htmldocsDirname.RelativeDir
docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications
oKeepVariableNames* = true
const oKeepVariableNames* = true
proc mainCommandArg*(conf: ConfigRef): string =
## This is intended for commands like check or parse
@@ -576,23 +521,21 @@ proc setConfigVar*(conf: ConfigRef; key, val: string) =
conf.configVars[key] = val
proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): AbsoluteFile =
# explains regression https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125
# Yet another reason why "" should not mean "."; `""/something` should raise
# instead of implying "" == "." as it's bug prone.
doAssert conf.outDir.string.len > 0
result = conf.outDir / changeFileExt(filename, ext)
conf.outDir / changeFileExt(filename, ext)
proc absOutFile*(conf: ConfigRef): AbsoluteFile =
doAssert not conf.outDir.isEmpty
doAssert not conf.outFile.isEmpty
result = conf.outDir / conf.outFile
when defined(posix):
if dirExists(result.string): result.string.add ".out"
if dirExists(result.string):
result.string.add ".out"
proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile =
## Create the output directory and returns a full path to the output file
result = conf.absOutFile
createDir result.string.parentDir
createDir conf.outDir
result = conf.outDir / conf.outFile
when defined(posix):
if dirExists(result.string):
result.string.add ".out"
proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
## Gets the prefix dir, usually the parent directory where the binary resides.
@@ -632,6 +575,17 @@ proc setDefaultLibpath*(conf: ConfigRef) =
proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
result = AbsoluteFile path.string.expandFilename
proc shortenDir*(conf: ConfigRef; dir: string): string {.
deprecated: "use 'relativeTo' instead".} =
## returns the interesting part of a dir
var prefix = conf.projectPath.string & DirSep
if startsWith(dir, prefix):
return substr(dir, prefix.len)
prefix = getPrefixDir(conf).string & DirSep
if startsWith(dir, prefix):
return substr(dir, prefix.len)
result = dir
proc removeTrailingDirSep*(path: string): string =
if (path.len > 0) and (path[^1] == DirSep):
result = substr(path, 0, path.len - 2)
@@ -659,7 +613,7 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
# XXX projectName should always be without a file extension!
result = if not conf.nimcacheDir.isEmpty:
conf.nimcacheDir
elif conf.backend == backendJs:
elif conf.cmd == cmdCompileToJS:
conf.projectPath / genSubDir
else:
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
@@ -689,10 +643,12 @@ iterator nimbleSubs*(conf: ConfigRef; p: string): string =
proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile,
ext: string): AbsoluteFile =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
result = getNimcacheDir(conf) / RelativeFile path.string.splitPath.tail.changeFileExt(ext)
let (head, tail) = splitPath(path.string)
result = getNimcacheDir(conf) / RelativeFile changeFileExt(tail, ext)
proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
createSubDir: bool = true): AbsoluteFile =
let (head, tail) = splitPath(f.string)
let subdir = getNimcacheDir(conf)
if createSubDir:
try:
@@ -700,7 +656,7 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
except OSError:
writeLine(stdout, "cannot create directory: " & subdir.string)
quit(1)
result = subdir / RelativeFile f.string.splitPath.tail
result = subdir / RelativeFile tail
#echo "completeGeneratedFilePath(", f, ") = ", result
proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile =
@@ -750,7 +706,7 @@ proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile): RelativeF
proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile =
if f.isAbsolute:
result = if f.fileExists: AbsoluteFile(f) else: AbsoluteFile""
result = if f.existsFile: AbsoluteFile(f) else: AbsoluteFile""
else:
result = rawFindFile(conf, RelativeFile f, suppressStdlib)
if result.isEmpty:
@@ -764,8 +720,7 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile
const stdlibDirs = [
"pure", "core", "arch",
"pure/collections",
"pure/concurrency",
"pure/unidecode", "impure",
"pure/concurrency", "impure",
"wrappers", "wrappers/linenoise",
"windows", "posix", "js"]
@@ -886,18 +841,3 @@ proc floatInt64Align*(conf: ConfigRef): int16 =
# to 4bytes (except with -malign-double)
return 4
return 8
proc setOutFile*(conf: ConfigRef) =
proc libNameTmpl(conf: ConfigRef): string {.inline.} =
result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a"
if conf.outFile.isEmpty:
let base = conf.projectName
let targetName =
if optGenDynLib in conf.globalOptions:
platform.OS[conf.target.targetOS].dllFrmt % base
elif optGenStaticLib in conf.globalOptions:
libNameTmpl(conf) % base
else:
base & platform.OS[conf.target.targetOS].exeExt
conf.outFile = RelativeFile targetName

View File

@@ -16,7 +16,7 @@ iterator myParentDirs(p: string): string =
yield current
proc getNimbleFile*(conf: ConfigRef; path: string): string =
## returns absolute path to nimble file, e.g.: /pathto/cligen.nimble
## returns absolute path to nimble file, eg: /pathto/cligen.nimble
var parents = 0
block packageSearch:
for d in myParentDirs(path):
@@ -28,6 +28,8 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string =
result = file
break packageSearch
# we also store if we didn't find anything:
when not defined(nimNoNilSeqs):
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
conf.packageCache[d] = result
@@ -35,7 +37,7 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string =
if parents <= 0: break
proc getPackageName*(conf: ConfigRef; path: string): string =
## returns nimble package name, e.g.: `cligen`
## returns nimble package name, eg: `cligen`
let path = getNimbleFile(conf, path)
result = path.splitFile.name

View File

@@ -99,14 +99,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) =
else:
# check all symkinds:
internalAssert conf, int(high(TSymKind)) < 255
for i in TSymKind:
for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind)
result.add(chr(i.ord))
return
# check all nodekinds:
internalAssert conf, int(high(TNodeKind)) < 255
for i in TNodeKind:
for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
result.add(chr(i.ord))
@@ -200,7 +200,7 @@ proc exprRoot*(n: PNode): PSym =
if it.len > 0 and it.typ != nil: it = it.lastSon
else: break
of nkCallKinds:
if it.typ != nil and it.typ.kind in {tyVar, tyLent} and it.len > 1:
if it.typ != nil and it.typ.kind == tyVar and it.len > 1:
# See RFC #7373, calls returning 'var T' are assumed to
# return a view into the first argument (if there is one):
it = it[1]
@@ -214,7 +214,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
result = arNone
case n.kind
of nkEmpty:
if n.typ != nil and n.typ.kind in {tyVar}:
if n.typ != nil and n.typ.kind == tyVar:
result = arLValue
of nkSym:
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
@@ -223,8 +223,6 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
result = arLValue
elif isUnsafeAddr and n.sym.kind == skParam:
result = arLValue
elif isUnsafeAddr and n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
result = arLValue
elif n.sym.kind in kinds:
if owner != nil and owner == n.sym.owner and
sfGlobal notin n.sym.flags:
@@ -233,7 +231,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
result = arLValue
elif n.sym.kind == skType:
let t = n.sym.typ.skipTypes({tyTypeDesc})
if t.kind in {tyVar}: result = arStrange
if t.kind == tyVar: result = arStrange
of nkDotExpr:
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
@@ -279,7 +277,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
# builtin slice keeps lvalue-ness:
if getMagic(n) in {mArrGet, mSlice}:
result = isAssignable(owner, n[1], isUnsafeAddr)
elif n.typ != nil and n.typ.kind in {tyVar}:
elif n.typ != nil and n.typ.kind == tyVar:
result = arLValue
elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent:
result = arLValue

File diff suppressed because it is too large Load Diff

View File

@@ -113,8 +113,10 @@ const
nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt}
proc prepareConfigNotes(graph: ModuleGraph; module: PSym) =
if sfMainModule in module.flags:
graph.config.mainPackageId = module.owner.id
# don't be verbose unless the module belongs to the main package:
if module.getnimblePkgId == graph.config.mainPackageId:
if module.owner.id == graph.config.mainPackageId:
graph.config.notes = graph.config.mainPackageNotes
else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
@@ -126,7 +128,7 @@ proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} =
if graph.stopCompile(): return true
var
p: Parser
p: TParsers
a: TPassContextArray
s: PLLStream
fileIdx = module.fileIdx
@@ -164,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
else:
s = stream
while true:
openParser(p, fileIdx, s, graph.cache, graph.config)
openParsers(p, fileIdx, s, graph.cache, graph.config)
if module.owner == nil or module.owner.name.s != "stdlib" or module.name.s == "distros":
# XXX what about caching? no processing then? what if I change the
@@ -212,7 +214,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
else:
#echo "----- single\n", n
if not processTopLevelStmt(graph, n, a): break
closeParser(p)
closeParsers(p)
if s.kind != llsStdIn: break
closePasses(graph, a)
# id synchronization point for more consistent code generation:

View File

@@ -99,3 +99,19 @@ when true:
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
when isMainModule:
doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim"
doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim"
doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim"
doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim"
doAssert $RelativeDir"foo/bar" == "foo/bar"
doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar"
doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt"
doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt"
doAssert not RelativeDir"foo/bar".isEmpty
doAssert RelativeDir"".isEmpty
when isMainModule and defined(windows):
let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim")
doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim"

View File

@@ -53,7 +53,7 @@ const
wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert}
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume}
lambdaPragmas* = {FirstCallConv..LastCallConv,
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
wThread, wAsmNoStackFrame,
@@ -61,20 +61,18 @@ const
wGcSafe, wCodegenDecl, wNoInit}
typePragmas* = declPragmas + {wMagic, wAcyclic,
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
wRequiresInit, wAlign} - {wExportNims, wNodecl} # why exclude these?
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl,
wGuard, wGoto, wCursor, wNoalias, wAlign}
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wAlign}
constPragmas* = declPragmas + {wHeader, wMagic,
wGensym, wInject,
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
paramPragmas* = {wNoalias, wInject, wGensym}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
wThread, wRaises, wLocks, wTags, wGcSafe,
@@ -180,7 +178,7 @@ proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
incl(s.flags, sfImportc)
incl(s.flags, sfInfixCall)
excl(s.flags, sfForward)
if c.config.backend == backendC:
if c.config.cmd == cmdCompileToC:
let m = s.getModule()
incl(m.flags, sfCompileToCpp)
incl c.config.globalOptions, optMixedMode
@@ -239,7 +237,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
var v: string
if n[1].kind == nkIdent: v = n[1].ident.s
else: v = expectStrLit(c, n)
for m in TMagic:
for m in low(TMagic)..high(TMagic):
if substr($m, 1) == v:
s.magic = m
break
@@ -248,7 +246,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
# this assumes that the order of special words and calling conventions is
# the same
TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall))
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind in nkPragmaCallKinds and n.len == 2:
@@ -258,8 +256,8 @@ proc isTurnedOn(c: PContext, n: PNode): bool =
localError(c.config, n.info, "'on' or 'off' expected")
proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
if isTurnedOn(c, n): resOptions.incl op
else: resOptions.excl op
if isTurnedOn(c, n): resOptions = resOptions + op
else: resOptions = resOptions - op
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
if isTurnedOn(c, n):
@@ -327,32 +325,35 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
# a calling convention that doesn't introduce custom name mangling
# cdecl is the default - the user can override this explicitly
if sym.kind in routineKinds and sym.typ != nil and
tfExplicitCallConv notin sym.typ.flags:
sym.typ.callConv == ccDefault:
sym.typ.callConv = ccCDecl
proc processNote(c: PContext, n: PNode) =
template handleNote(enumVals, notes) =
let x = findStr(enumVals, n[0][1].ident.s, errUnknown)
if x != errUnknown:
nk = TNoteKind(x)
let x = c.semConstBoolExpr(c, n[1])
n[1] = x
if x.kind == nkIntLit and x.intVal != 0: incl(notes, nk)
else: excl(notes, nk)
else:
invalidPragma(c, n)
if n.kind in nkPragmaCallKinds and n.len == 2 and
n[0].kind == nkBracketExpr and
n[0].len == 2 and
n[0][1].kind == nkIdent and n[0][0].kind == nkIdent:
var nk: TNoteKind
case whichKeyword(n[0][0].ident)
of wHint: handleNote(hintMin .. hintMax, c.config.notes)
of wWarning: handleNote(warnMin .. warnMax, c.config.notes)
of wWarningAsError: handleNote(warnMin .. warnMax, c.config.warningAsErrors)
else: invalidPragma(c, n)
else: invalidPragma(c, n)
of wHint:
var x = findStr(HintsToStr, n[0][1].ident.s)
if x >= 0: nk = TNoteKind(x + ord(hintMin))
else: invalidPragma(c, n); return
of wWarning:
var x = findStr(WarningsToStr, n[0][1].ident.s)
if x >= 0: nk = TNoteKind(x + ord(warnMin))
else: invalidPragma(c, n); return
else:
invalidPragma(c, n)
return
let x = c.semConstBoolExpr(c, n[1])
n[1] = x
if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk)
else: excl(c.config.notes, nk)
# checkme: honor cmdlineNotes with: c.setNote(nk, x.kind == nkIntLit and x.intVal != 0)
else:
invalidPragma(c, n)
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
case w
@@ -362,6 +363,7 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
of wRangeChecks: {optRangeCheck}
of wBoundChecks: {optBoundsCheck}
of wOverflowChecks: {optOverflowCheck}
of wNilChecks: {optNilCheck}
of wFloatChecks: {optNaNCheck, optInfCheck}
of wNanChecks: {optNaNCheck}
of wInfChecks: {optInfCheck}
@@ -470,12 +472,14 @@ proc processPop(c: PContext, n: PNode) =
proc processDefine(c: PContext, n: PNode) =
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
defineSymbol(c.config.symbols, n[1].ident.s)
message(c.config, n.info, warnDeprecated, "define is deprecated")
else:
invalidPragma(c, n)
proc processUndef(c: PContext, n: PNode) =
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
undefSymbol(c.config.symbols, n[1].ident.s)
message(c.config, n.info, warnDeprecated, "undef is deprecated")
else:
invalidPragma(c, n)
@@ -544,7 +548,7 @@ proc processLink(c: PContext, n: PNode) =
proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
case n[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = newNodeI(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
var str = n[1].strVal
if str == "":
localError(con.config, n.info, "empty 'asm' statement")
@@ -575,7 +579,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
a = c + 1
else:
illFormedAstLocal(n, con.config)
result = newNodeI(nkAsmStmt, n.info)
result = newNode(nkAsmStmt, n.info)
proc pragmaEmit(c: PContext, n: PNode) =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -638,7 +642,7 @@ proc processPragma(c: PContext, n: PNode, i: int) =
invalidPragma(c, n)
var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options)
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1])
strTableAdd(c.userPragmas, userPragma)
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
@@ -782,15 +786,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if key.kind == nkBracketExpr:
processNote(c, it)
return
elif key.kind == nkCast:
if comesFromPush:
localError(c.config, n.info, "a 'cast' pragma cannot be pushed")
elif not isStatement:
localError(c.config, n.info, "'cast' pragma only allowed in a statement context")
case whichPragma(key[1])
of wRaises, wTags: pragmaRaisesOrTags(c, key[1])
else: discard
return
elif key.kind notin nkIdentKinds:
n[i] = semCustomPragma(c, it)
return
@@ -818,8 +813,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wExportc, wExportCpp:
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
if k == wExportCpp:
if c.config.backend != backendCpp:
localError(c.config, it.info, "exportcpp requires `cpp` backend, got " & $c.config.backend)
if c.config.cmd != cmdCompileToCpp:
localError(c.config, it.info, "exportcpp requires `nim cpp`, got " & $c.config.cmd)
else:
incl(sym.flags, sfMangleCpp)
incl(sym.flags, sfUsed) # avoid wrong hints
@@ -840,7 +835,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wImportCpp:
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
of wImportJs:
if c.config.backend != backendJs:
if c.config.cmd != cmdCompileToJS:
localError(c.config, it.info, "`importjs` pragma requires the JavaScript target")
let name = getOptionalStr(c, it, "$1")
incl(sym.flags, sfImportc)
@@ -885,9 +880,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wRegister:
noVal(c, it)
incl(sym.flags, sfRegister)
of wNoalias:
noVal(c, it)
incl(sym.flags, sfNoalias)
of wThreadVar:
noVal(c, it)
incl(sym.flags, {sfThread, sfGlobal})
@@ -897,11 +889,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wMagic: processMagic(c, it, sym)
of wCompileTime:
noVal(c, it)
if comesFromPush:
if sym.kind in {skProc, skFunc}:
incl(sym.flags, sfCompileTime)
else:
incl(sym.flags, sfCompileTime)
incl(sym.flags, sfCompileTime)
#incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(c, it)
@@ -1006,7 +994,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
incl(sym.flags, sfProcvar)
if sym.typ != nil:
incl(sym.typ.flags, tfThread)
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
of wGcSafe:
noVal(c, it)
if sym != nil:
@@ -1061,9 +1049,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wPush:
processPush(c, n, i + 1)
result = true
of wPop:
processPop(c, it)
result = true
of wPop: processPop(c, it)
of wPragma:
if not sym.isNil and sym.kind == skTemplate:
sym.flags.incl sfCustomPragma
@@ -1091,9 +1077,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(c, it)
else:
sym.typ.callConv = wordToCallConv(k)
sym.typ.flags.incl tfExplicitCallConv
else: sym.typ.callConv = wordToCallConv(k)
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(c, it)
@@ -1104,10 +1088,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wCompleteStruct:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfCompleteStruct)
of wUnchecked:
noVal(c, it)
if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
@@ -1115,12 +1095,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else:
sym.typ.kind = tyUncheckedArray
of wUnion:
if c.config.backend == backendJs:
localError(c.config, it.info, "`{.union.}` is not implemented for js backend.")
else:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfUnion)
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(c, it)
if sym.kind == skField:

View File

@@ -54,3 +54,36 @@ proc prefixMatch*(p, s: string): PrefixMatch =
else:
return PrefixMatch.None
return PrefixMatch.None
when isMainModule:
import macros
macro check(val, body: untyped): untyped =
result = newStmtList()
expectKind body, nnkStmtList
for b in body:
expectKind b, nnkPar
expectLen b, 2
let p = b[0]
let s = b[1]
result.add quote do:
echo prefixMatch(`p`, `s`) == `val`
check PrefixMatch.Prefix:
("abc", "abc")
("a", "abc")
("xyz", "X_yzzzZe")
check PrefixMatch.Substr:
("b", "abc")
("abc", "fooabcabc")
("abC", "foo_AB_c")
check PrefixMatch.Abbrev:
("abc", "AxxxBxxxCxxx")
("xyz", "X_yabcZe")
check PrefixMatch.None:
("foobar", "afkslfjd_as")
("xyz", "X_yuuZuuZe")
("ru", "remotes")

View File

@@ -11,7 +11,7 @@
# This is needed for proper handling of forward declarations.
import
ast, astalgo, msgs, semdata, types, trees, strutils, lookups
ast, astalgo, msgs, semdata, types, trees, strutils
proc equalGenericParams(procA, procB: PNode): bool =
if procA.len != procB.len: return false
@@ -28,7 +28,40 @@ proc equalGenericParams(procA, procB: PNode): bool =
if not exprStructuralEquivalent(a.ast, b.ast): return
result = true
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
# Searches for a forward declaration or a "twin" symbol of fn
# in the symbol table. If the parameter lists are exactly
# the same the sym in the symbol table is returned, else nil.
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name)
if isGenericRoutine(fn):
# we simply check the AST; this is imprecise but nearly the best what
# can be done; this doesn't work either though as type constraints are
# not kept in the AST ..
while result != nil:
if result.kind == fn.kind and isGenericRoutine(result):
let genR = result.ast[genericParamsPos]
let genF = fn.ast[genericParamsPos]
if exprStructuralEquivalent(genR, genF) and
exprStructuralEquivalent(result.ast[paramsPos],
fn.ast[paramsPos]) and
equalGenericParams(genR, genF):
return
result = nextIdentIter(it, scope.symbols)
else:
while result != nil:
if result.kind == fn.kind and not isGenericRoutine(result):
case equalParams(result.typ.n, fn.typ.n)
of paramsEqual:
return
of paramsIncompatible:
localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
return
of paramsNotEqual:
discard
result = nextIdentIter(it, scope.symbols)
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
@@ -50,13 +83,15 @@ proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
discard
result = nextIdentIter(it, scope.symbols)
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] =
var scope = scope
result.proto = searchForProcAux(c, scope, fn)
while result.proto == nil and scope.isShadowScope:
scope = scope.parent
result.proto = searchForProcAux(c, scope, fn)
result.comesFromShadowScope = true
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
result = searchForProcNew(c, scope, fn)
when false:
let old = searchForProcOld(c, scope, fn)
if old != result:
echo "Mismatch in searchForProc: ", fn.info
debug fn.typ
debug if result != nil: result.typ else: nil
debug if old != nil: old.typ else: nil
when false:
proc paramsFitBorrow(child, parent: PNode): bool =

View File

@@ -1,7 +0,0 @@
## Nim Compiler
- This directory contains the Nim compiler written in Nim.
- Note that this code has been translated from a bootstrapping version written in Pascal.
- So the code is **not** a poster child of good Nim code.
See [Internals of the Nim Compiler](https://nim-lang.org/docs/intern.html) for more information.

5
compiler/readme.txt Normal file
View File

@@ -0,0 +1,5 @@
This directory contains the Nim compiler written in Nim. Note that this
code has been translated from a bootstrapping version written in Pascal, so
the code is **not** a poster child of good Nim code.
See https://nim-lang.org/docs/intern.html for more information.

View File

@@ -20,11 +20,10 @@ import
type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples,
renderIr
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
kind*: TokType
kind*: TTokType
length*: int16
sym*: PSym
@@ -49,20 +48,11 @@ type
pendingNewlineCount: int
fid*: FileIndex
config*: ConfigRef
mangler: seq[PSym]
# We render the source code in a two phases: The first
# determines how long the subtree will likely be, the second
# phase appends to a buffer that will be the output.
proc disamb(g: var TSrcGen; s: PSym): int =
# we group by 's.name.s' to compute the stable name ID.
result = 0
for i in 0 ..< g.mangler.len:
if s == g.mangler[i]: return result
if s.name.s == g.mangler[i].name.s: inc result
g.mangler.add s
proc isKeyword*(i: PIdent): bool =
if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
@@ -119,7 +109,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
g.inGenericParams = false
g.config = config
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
g.buf.add(s)
if kind != tkSpaces:
@@ -160,6 +150,7 @@ proc putNL(g: var TSrcGen) =
proc optNL(g: var TSrcGen, indent: int) =
g.pendingNL = indent
g.lineLen = indent
g.col = g.indent
when defined(nimpretty): g.pendingNewlineCount = 0
proc optNL(g: var TSrcGen) =
@@ -168,6 +159,7 @@ proc optNL(g: var TSrcGen) =
proc optNL(g: var TSrcGen; a, b: PNode) =
g.pendingNL = g.indent
g.lineLen = g.indent
g.col = g.indent
when defined(nimpretty): g.pendingNewlineCount = lineDiff(a, b)
proc indentNL(g: var TSrcGen) =
@@ -182,7 +174,7 @@ proc dedent(g: var TSrcGen) =
dec(g.pendingNL, IndentWidth)
dec(g.lineLen, IndentWidth)
proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
if kind != tkSpaces:
addPendingNL(g)
if s.len > 0:
@@ -255,7 +247,7 @@ proc maxLineLength(s: string): int =
inc(lineLen)
inc(i)
proc putRawStr(g: var TSrcGen, kind: TokType, s: string) =
proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
var i = 0
let hi = s.len - 1
var str = ""
@@ -327,8 +319,8 @@ proc lsub(g: TSrcGen; n: PNode): int
proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
proc skip(t: PType): PType =
result = t
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar,
tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
tyOrdinal, tyAlias, tySink}:
result = lastSon(result)
let typ = n.typ.skip
@@ -344,7 +336,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
elif nfBase8 in n.flags:
var y = if size < sizeof(BiggestInt): x and ((1.BiggestInt shl (size*8)) - 1)
var y = if size < sizeof(BiggestInt): x and ((1 shl (size*8)) - 1)
else: x
result = "0o" & toOct(y, size * 3)
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
@@ -467,8 +459,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkDo: result = lsons(g, n) + len("do__:_")
of nkConstDef, nkIdentDefs:
result = lcomma(g, n, 0, - 3)
if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2
if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3
if n[^2].kind != nkEmpty: result = result + lsub(g, n[^2]) + 2
if n[^1].kind != nkEmpty: result = result + lsub(g, n[^1]) + 3
of nkVarTuple:
if n[^1].kind == nkEmpty:
result = lcomma(g, n, 0, - 2) + len("()")
@@ -479,8 +471,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n)
of nkObjDownConv, nkObjUpConv:
result = 2
if n.len >= 1: result += lsub(g, n[0])
result += lcomma(g, n, 1)
if n.len >= 1: result = result + lsub(g, n[0])
result = result + lcomma(g, n, 1)
of nkExprColonExpr: result = lsons(g, n) + 2
of nkInfix: result = lsons(g, n) + 2
of nkPrefix:
@@ -544,7 +536,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkGenericParams: result = lcomma(g, n) + 2
of nkFormalParams:
result = lcomma(g, n, 1) + 2
if n[0].kind != nkEmpty: result += lsub(g, n[0]) + 2
if n[0].kind != nkEmpty: result = result + lsub(g, n[0]) + 2
of nkExceptBranch:
result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_")
of nkObjectTy:
@@ -583,7 +575,7 @@ proc hasCom(n: PNode): bool =
for i in 0..<n.len:
if hasCom(n[i]): return true
proc putWithSpace(g: var TSrcGen, kind: TokType, s: string) =
proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
put(g, kind, s)
put(g, tkSpaces, Space)
@@ -597,7 +589,7 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
gsub(g, n[i])
if c:
if g.tokens.len > oldLen:
putWithSpace(g, separator, $separator)
putWithSpace(g, separator, TokTypeToStr[separator])
if hasCom(n[i]):
gcoms(g)
optNL(g, ind)
@@ -626,7 +618,7 @@ proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = - 1) =
for i in start..n.len + theEnd: gsub(g, n[i], c)
proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TokType,
proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
k: string) =
if n.len == 0: return # empty var sections are possible
putWithSpace(g, kind, k)
@@ -855,7 +847,7 @@ proc gident(g: var TSrcGen, n: PNode) =
if sfAnon in n.sym.flags or
(n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
var t: TokType
var t: TTokType
var s = atom(g, n)
if s.len > 0 and s[0] in lexer.SymChars:
if n.kind == nkIdent:
@@ -863,19 +855,12 @@ proc gident(g: var TSrcGen, n: PNode) =
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
t = tkSymbol
else:
t = TokType(n.ident.id + ord(tkSymbol))
t = TTokType(n.ident.id + ord(tkSymbol))
else:
t = tkSymbol
else:
t = tkOpr
if renderIr in g.flags and n.kind == nkSym:
let localId = disamb(g, n.sym)
if localId != 0 and n.sym.magic == mNone:
s.add '_'
s.addInt localId
if sfCursor in n.sym.flags:
s.add "_cursor"
elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
s.add '_'
s.addInt n.sym.id
when defined(debugMagics):
@@ -899,23 +884,12 @@ proc gsub(g: var TSrcGen; n: PNode; i: int) =
else:
put(g, tkOpr, "<<" & $i & "th child missing for " & $n.kind & " >>")
type
BracketKind = enum
bkNone, bkBracket, bkBracketAsgn, bkCurly, bkCurlyAsgn
proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
if renderIds notin g.flags:
case n.kind
of nkClosedSymChoice, nkOpenSymChoice:
if n.len > 0: result = bracketKind(g, n[0])
of nkSym:
result = case n.sym.name.s
of "[]": bkBracket
of "[]=": bkBracketAsgn
of "{}": bkCurly
of "{}=": bkCurlyAsgn
else: bkNone
else: result = bkNone
proc isBracket*(n: PNode): bool =
case n.kind
of nkClosedSymChoice, nkOpenSymChoice:
if n.len > 0: result = isBracket(n[0])
of nkSym: result = n.sym.name.s == "[]"
else: result = false
proc skipHiddenNodes(n: PNode): PNode =
result = n
@@ -928,11 +902,10 @@ proc skipHiddenNodes(n: PNode): PNode =
else: break
proc accentedName(g: var TSrcGen, n: PNode) =
const backticksNeeded = OpChars + {'[', '{'}
if n == nil: return
let isOperator =
if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in backticksNeeded: true
elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in backticksNeeded: true
if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in OpChars: true
elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in OpChars: true
else: false
if isOperator:
@@ -991,7 +964,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkCharLit: put(g, tkCharLit, atom(g, n))
of nkNilLit: put(g, tkNil, atom(g, n)) # complex expressions
of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
if n.len > 1 and n.lastSon.kind in {nkStmtList, nkStmtListExpr}:
if renderIds notin g.flags and n.len > 0 and isBracket(n[0]):
gsub(g, n, 1)
put(g, tkBracketLe, "[")
gcomma(g, n, 2)
put(g, tkBracketRi, "]")
elif n.len > 1 and n.lastSon.kind == nkStmtList:
accentedName(g, n[0])
if n.len > 2:
put(g, tkParLe, "(")
@@ -999,41 +977,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParRi, ")")
put(g, tkColon, ":")
gsub(g, n, n.len-1)
elif n.len >= 1:
case bracketKind(g, n[0])
of bkBracket:
gsub(g, n, 1)
put(g, tkBracketLe, "[")
gcomma(g, n, 2)
put(g, tkBracketRi, "]")
of bkBracketAsgn:
gsub(g, n, 1)
put(g, tkBracketLe, "[")
gcomma(g, n, 2, -2)
put(g, tkBracketRi, "]")
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n, n.len - 1)
of bkCurly:
gsub(g, n, 1)
put(g, tkCurlyLe, "{")
gcomma(g, n, 2)
put(g, tkCurlyRi, "}")
of bkCurlyAsgn:
gsub(g, n, 1)
put(g, tkCurlyLe, "{")
gcomma(g, n, 2, -2)
put(g, tkCurlyRi, "}")
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n, n.len - 1)
of bkNone:
accentedName(g, n[0])
put(g, tkParLe, "(")
gcomma(g, n, 1)
put(g, tkParRi, ")")
else:
if n.len >= 1: accentedName(g, n[0])
put(g, tkParLe, "(")
gcomma(g, n, 1)
put(g, tkParRi, ")")
of nkCallStrLit:
if n.len > 0: accentedName(g, n[0])
@@ -1041,34 +988,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
else:
gsub(g, n, 1)
of nkHiddenStdConv, nkHiddenSubConv:
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
if n.len >= 2:
when false:
# if {renderIds, renderIr} * g.flags != {}:
put(g, tkSymbol, "(conv)")
put(g, tkParLe, "(")
gsub(g, n[1])
put(g, tkParRi, ")")
else:
gsub(g, n[1])
else:
put(g, tkSymbol, "(wrong conv)")
of nkHiddenCallConv:
if {renderIds, renderIr} * g.flags != {}:
accentedName(g, n[0])
put(g, tkParLe, "(")
gcomma(g, n, 1)
put(g, tkParRi, ")")
elif n.len >= 2:
gsub(g, n[1])
else:
put(g, tkSymbol, "(wrong conv)")
of nkCast:
put(g, tkCast, "cast")
if n.len > 0 and n[0].kind != nkEmpty:
put(g, tkBracketLe, "[")
gsub(g, n, 0)
put(g, tkBracketRi, "]")
put(g, tkBracketLe, "[")
gsub(g, n, 0)
put(g, tkBracketRi, "]")
put(g, tkParLe, "(")
gsub(g, n, 1)
put(g, tkParRi, ")")
@@ -1226,7 +1155,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
infixArgument(g, n, 1)
put(g, tkSpaces, Space)
gsub(g, n, 0) # binary operator
# e.g.: `n1 == n2` decompses as following sum:
# eg: `n1 == n2` decompses as following sum:
if n.len == 3 and not fits(g, oldLineLen + lsub(g, n[1]) + lsub(g, n[2]) + lsub(g, n[0]) + len(" ")):
optNL(g, g.indent + longIndentWid)
else:
@@ -1660,7 +1589,7 @@ proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
initSrcGen(r, renderFlags, newPartialConfigRef())
gsub(r, n)
proc getNextTok*(r: var TSrcGen, kind: var TokType, literal: var string) =
proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
if r.idx < r.tokens.len:
kind = r.tokens[r.idx].kind
let length = r.tokens[r.idx].length.int
@@ -1680,9 +1609,9 @@ proc quoteExpr*(a: string): string {.inline.} =
## can be used for quoting expressions in error msgs.
"'" & a & "'"
proc genFieldDefect*(field: PSym, disc: PSym): string =
proc genFieldError*(field: PSym, disc: PSym): string =
## this needs to be in a module accessible by jsgen, ccgexprs, and vm to
## provide this error msg FieldDefect; msgs would be better but it does not
## provide this error msg FieldError; msgs would be better but it does not
## import ast
result = field.name.s.quoteExpr & " is not accessible using discriminant " &
disc.name.s.quoteExpr & " of type " &

View File

@@ -1,152 +0,0 @@
import strutils
from xmltree import addEscaped
import ast, options, msgs
import packages/docutils/highlite
const isDebug = false
when isDebug:
import renderer
import astalgo
proc lastNodeRec(n: PNode): PNode =
result = n
while result.safeLen > 0: result = result[^1]
proc isInIndentationBlock(src: string, indent: int): bool =
#[
we stop at the first de-indentation; there's an inherent ambiguity with non
doc comments since they can have arbitrary indentation, so we just take the
practical route and require a runnableExamples to keep its code (including non
doc comments) to its indentation level.
]#
for j in 0..<indent:
if src.len <= j: return true
if src[j] != ' ': return false
return true
type LineData = object
## keep track of which lines are starting inside a multiline doc comment.
## We purposefully avoid re-doing parsing which is already done (we get a PNode)
## so we don't worry about whether we're inside (nested) doc comments etc.
## But we sill need some logic to disambiguate different multiline styles.
conf: ConfigRef
lineFirst: int
lines: seq[bool]
## lines[index] is true if line `lineFirst+index` starts inside a multiline string
## Using a HashSet (extra dependency) would simplify but not by much.
proc tripleStrLitStartsAtNextLine(conf: ConfigRef, n: PNode): bool =
# enabling TLineInfo.offsetA,offsetB would probably make this easier
const tripleQuote = "\"\"\""
let src = sourceLine(conf, n.info)
let col = n.info.col
doAssert src.continuesWith(tripleQuote, col) # sanity check
var i = col + 3
var onlySpace = true
while true:
if src.len <= i:
doAssert src.len == i
return onlySpace
elif src.continuesWith(tripleQuote, i) and (src.len == i+3 or src[i+3] != '\"'):
return false # triple lit is in 1 line
elif src[i] != ' ': onlySpace = false
i.inc
proc visitMultilineStrings(ldata: var LineData, n: PNode) =
var cline = ldata.lineFirst
template setLine() =
let index = cline - ldata.lineFirst
if ldata.lines.len < index+1: ldata.lines.setLen index+1
ldata.lines[index] = true
case n.kind
of nkTripleStrLit:
# same logic should be applied for any multiline token
# we could also consider nkCommentStmt but right now we just assume doc comments,
# unlike triple string litterals, don't de-indent from runnableExamples.
cline = n.info.line.int
if tripleStrLitStartsAtNextLine(ldata.conf, n):
cline.inc
setLine()
for ai in n.strVal:
case ai
of '\n':
cline.inc
setLine()
else: discard
else:
for i in 0..<n.safeLen:
visitMultilineStrings(ldata, n[i])
proc startOfLineInsideTriple(ldata: LineData, line: int): bool =
let index = line - ldata.lineFirst
if index >= ldata.lines.len: false
else: ldata.lines[index]
proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string =
## TLineInfo.offsetA,offsetB would be cleaner but it's only enabled for nimpretty,
## we'd need to check performance impact to enable it for nimdoc.
var first = n.lastSon.info
if first.line == n[0].info.line:
#[
runnableExamples: assert true
]#
discard
else:
#[
runnableExamples:
# non-doc comment that we want to capture even though `first` points to `assert true`
assert true
]#
first.line = n[0].info.line + 1
let last = n.lastNodeRec.info
var info = first
var indent = info.col
let numLines = numLines(conf, info.fileIndex).uint16
var lastNonemptyPos = 0
var ldata = LineData(lineFirst: first.line.int, conf: conf)
visitMultilineStrings(ldata, n[^1])
when isDebug:
debug(n)
for i in 0..<ldata.lines.len:
echo (i+ldata.lineFirst, ldata.lines[i])
result = ""
for line in first.line..numLines: # bugfix, see `testNimDocTrailingExample`
info.line = line
let src = sourceLine(conf, info)
let special = startOfLineInsideTriple(ldata, line.int)
if line > last.line and not special and not isInIndentationBlock(src, indent):
break
if line > first.line: result.add "\n"
if special:
result.add src
lastNonemptyPos = result.len
elif src.len > indent:
result.add src[indent..^1]
lastNonemptyPos = result.len
result.setLen lastNonemptyPos
proc renderNimCode*(result: var string, code: string, isLatex = false) =
var toknizr: GeneralTokenizer
initGeneralTokenizer(toknizr, code)
var buf = ""
template append(kind, val) =
buf.setLen 0
buf.addEscaped(val)
let class = tokenClassToStr[kind]
if isLatex:
result.addf "\\span$1{$2}", [class, buf]
else:
result.addf "<span class=\"$1\">$2</span>", [class, buf]
while true:
getNextToken(toknizr, langNim)
case toknizr.kind
of gtEof: break # End Of File (or string)
else:
# TODO: avoid alloc; maybe toOpenArray
append(toknizr.kind, substr(code, toknizr.start, toknizr.length + toknizr.start - 1))

View File

@@ -1,6 +1,6 @@
import
intsets, ast, idents, algorithm, renderer, strutils,
intsets, ast, idents, algorithm, renderer, os, strutils,
msgs, modulegraphs, syntaxes, options, modulepaths,
lineinfos
@@ -100,15 +100,38 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
for i in 0..<n.len: computeDeps(cache, n[i], declares, uses, topLevel)
of nkPragma:
let a = n[0]
if a.kind == nkExprColonExpr and a[0].kind == nkIdent and a[0].ident.s == "pragma":
# user defined pragma
decl(a[1])
if a.kind == nkExprColonExpr and a[0].kind == nkIdent and
a[0].ident.s == "pragma":
# user defined pragma
decl(a[1])
else:
for i in 0..<n.safeLen: deps(n[i])
of nkMixinStmt, nkBindStmt: discard
else:
for i in 0..<n.safeLen: deps(n[i])
proc cleanPath(s: string): string =
# Here paths may have the form A / B or "A/B"
result = ""
for c in s:
if c != ' ' and c != '\"':
result.add c
proc joinPath(parts: seq[string]): string =
let nb = parts.len
assert nb > 0
if nb == 1:
return parts[0]
result = parts[0] / parts[1]
for i in 2..<parts.len:
result = result / parts[i]
proc getIncludePath(n: PNode, modulePath: string): string =
let istr = n.renderTree.cleanPath
let (pdir, _) = modulePath.splitPath
let p = istr.split('/').joinPath.addFileExt("nim")
result = pdir / p
proc hasIncludes(n:PNode): bool =
for a in n:
if a.kind == nkIncludeStmt:
@@ -187,42 +210,42 @@ proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
sn.add dn.pnode[0]
res.add sn
else:
# Problematic circular dependency, we arrange the nodes into
# their original relative order and make sure to re-merge
# consecutive type and const sections
var wmsg = "Circular dependency detected. `codeReordering` pragma may not be able to" &
" reorder some nodes properely"
when defined(debugReorder):
wmsg &= ":\n"
for i in 0..<cs.len-1:
for j in i..<cs.len:
for ci in 0..<cs[i].kids.len:
if cs[i].kids[ci].id == cs[j].id:
wmsg &= "line " & $cs[i].pnode.info.line &
" depends on line " & $cs[j].pnode.info.line &
": " & cs[i].expls[ci] & "\n"
for j in 0..<cs.len-1:
for ci in 0..<cs[^1].kids.len:
if cs[^1].kids[ci].id == cs[j].id:
wmsg &= "line " & $cs[^1].pnode.info.line &
" depends on line " & $cs[j].pnode.info.line &
": " & cs[^1].expls[ci] & "\n"
message(conf, cs[0].pnode.info, warnUser, wmsg)
# Problematic circular dependency, we arrange the nodes into
# their original relative order and make sure to re-merge
# consecutive type and const sections
var wmsg = "Circular dependency detected. `codeReordering` pragma may not be able to" &
" reorder some nodes properely"
when defined(debugReorder):
wmsg &= ":\n"
for i in 0..<cs.len-1:
for j in i..<cs.len:
for ci in 0..<cs[i].kids.len:
if cs[i].kids[ci].id == cs[j].id:
wmsg &= "line " & $cs[i].pnode.info.line &
" depends on line " & $cs[j].pnode.info.line &
": " & cs[i].expls[ci] & "\n"
for j in 0..<cs.len-1:
for ci in 0..<cs[^1].kids.len:
if cs[^1].kids[ci].id == cs[j].id:
wmsg &= "line " & $cs[^1].pnode.info.line &
" depends on line " & $cs[j].pnode.info.line &
": " & cs[^1].expls[ci] & "\n"
message(conf, cs[0].pnode.info, warnUser, wmsg)
var i = 0
while i < cs.len:
if cs[i].pnode.kind in {nkTypeSection, nkConstSection}:
let ckind = cs[i].pnode.kind
var sn = newNode(ckind)
sn.add cs[i].pnode[0]
inc i
while i < cs.len and cs[i].pnode.kind == ckind:
var i = 0
while i < cs.len:
if cs[i].pnode.kind in {nkTypeSection, nkConstSection}:
let ckind = cs[i].pnode.kind
var sn = newNode(ckind)
sn.add cs[i].pnode[0]
inc i
res.add sn
else:
res.add cs[i].pnode
inc i
while i < cs.len and cs[i].pnode.kind == ckind:
sn.add cs[i].pnode[0]
inc i
res.add sn
else:
res.add cs[i].pnode
inc i
proc hasImportStmt(n: PNode): bool =
# Checks if the node is an import statement or
@@ -269,17 +292,17 @@ proc hasAccQuoted(n: PNode): bool =
if hasAccQuoted(a):
return true
const extendedProcDefs = procDefs + {nkMacroDef, nkTemplateDef}
const extandedProcDefs = procDefs + {nkMacroDef, nkTemplateDef}
proc hasAccQuotedDef(n: PNode): bool =
# Checks if the node is a function, macro, template ...
# with a quoted name or if it contains one
case n.kind
of extendedProcDefs:
of extandedProcDefs:
result = n[0].hasAccQuoted
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for a in n:
if hasAccQuotedDef(a):
if a.hasAccQuotedDef:
return true
else:
result = false
@@ -295,7 +318,7 @@ proc hasBody(n: PNode): bool =
case n.kind
of nkCommand, nkCall:
result = true
of extendedProcDefs:
of extandedProcDefs:
result = n[^1].kind == nkStmtList
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for a in n:
@@ -388,7 +411,8 @@ proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN],
proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
## Tarjan's algorithm. Performs a topological sort
## and detects strongly connected components.
var s: seq[DepN]
result = newSeq[seq[DepN]]()
var s = newSeq[DepN]()
var idx = 0
for v in g.mitems:
if v.idx < 0:
@@ -400,7 +424,7 @@ proc hasForbiddenPragma(n: PNode): bool =
for a in n:
if a.kind == nkPragma and a[0].kind == nkIdent and
a[0].ident.s == "push":
return true
return true
proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
if n.hasForbiddenPragma:

View File

@@ -917,8 +917,6 @@ proc loadNode*(g: ModuleGraph; module: PSym): PNode =
replay(g, module, result)
proc setupModuleCache*(g: ModuleGraph) =
# historical note: there used to be a `rodfiles` dir with special tests
# for incremental compilation via symbol files. This was likely replaced by ic.
if g.config.symbolFiles == disabledSf: return
g.recordStmt = recordStmt
let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"

View File

@@ -80,14 +80,16 @@ proc decodeStr*(s: cstring, pos: var int): string =
else: break
pos = i
const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
{.push overflowChecks: off.}
# since negative numbers require a leading '-' they use up 1 byte. Thus we
# subtract/add `vintDelta` here to save space for small negative numbers
# which are common in ROD files:
const vintDelta = 5
const
vintDelta = 5
template encodeIntImpl(self) =
var d: char

View File

@@ -15,33 +15,33 @@ proc `|+|`*(a, b: BiggestInt): BiggestInt =
if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
return result
if a < 0 or b < 0:
result = low(typeof(result))
result = low(result)
else:
result = high(typeof(result))
result = high(result)
proc `|-|`*(a, b: BiggestInt): BiggestInt =
result = a -% b
if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
return result
if b > 0:
result = low(typeof(result))
result = low(result)
else:
result = high(typeof(result))
result = high(result)
proc `|abs|`*(a: BiggestInt): BiggestInt =
if a != low(typeof(a)):
if a != low(a):
if a >= 0: result = a
else: result = -a
else:
result = low(typeof(a))
result = low(a)
proc `|div|`*(a, b: BiggestInt): BiggestInt =
# (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4)..(5 div 1)
if b == 0'i64:
# make the same as ``div 1``:
result = a
elif a == low(typeof(a)) and b == -1'i64:
result = high(typeof(result))
elif a == low(a) and b == -1'i64:
result = high(result)
else:
result = a div b
@@ -74,6 +74,6 @@ proc `|*|`*(a, b: BiggestInt): BiggestInt =
return result
if floatProd >= 0.0:
result = high(typeof(result))
result = high(result)
else:
result = low(typeof(result))
result = low(result)

View File

@@ -228,14 +228,11 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
# watch out, "newruntime" can be set within NimScript itself and then we need
# to remember this:
if conf.selectedGC == gcUnselected:
conf.selectedGC = oldSelectedGC
if optOwnedRefs in oldGlobalOptions:
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
if conf.selectedGC in {gcArc, gcOrc}:
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
if conf.selectedGC == gcUnselected:
conf.selectedGC = oldSelectedGC
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph)

View File

@@ -16,8 +16,7 @@ import
procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
lowerings, plugins/active, rod, lineinfos, strtabs, int128,
isolation_check, typeallowed
lowerings, plugins/active, rod, lineinfos, strtabs, int128
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
@@ -198,13 +197,15 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
suggestDecl(c, n, result)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
# and sfGenSym in n.sym.flags:
result = n.sym
if result.kind notin {kind, skTemp}:
localError(c.config, n.info, "cannot use symbol of kind '$1' as a '$2'" %
[result.kind.toHumanStr, kind.toHumanStr])
localError(c.config, n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'")
when false:
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym:
@@ -228,22 +229,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, c, flags)
let t = typeAllowed(typ, kind, flags)
if t != nil:
var err: string
if t == typ:
err = "invalid type: '$1' for $2" % [typeToString(typ), toHumanStr(kind)]
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
err &= ". Did you mean to call the $1 with '()'?" % [toHumanStr(typ.owner.kind)]
localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
else:
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
typeToString(typ), toHumanStr(kind)]
localError(c.config, info, err)
localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c, typ.n.info, typ, skProc)
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -324,7 +323,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
let oldErrorOutputs = c.config.m.errorOutputs
c.config.m.errorOutputs = {}
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
c.config.errorMax = high(int)
try:
result = evalConstExpr(c.module, c.graph, e)
@@ -378,15 +377,14 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
include hlo, seminst, semcall
proc resetSemFlag(n: PNode) =
excl n.flags, nfSem
for i in 0..<n.safeLen:
resetSemFlag(n[i])
when false:
# hopefully not required:
proc resetSemFlag(n: PNode) =
excl n.flags, nfSem
for i in 0..<n.safeLen:
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
@@ -401,7 +399,8 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
c.friendModules.add(s.owner.getModule)
idSynchronizationPoint(5000)
result = macroResult
resetSemFlag result
excl(result.flags, nfSem)
#resetSemFlag n
if s.typ[0] == nil:
result = semStmt(c, result, flags)
else:
@@ -469,7 +468,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.graph, c.templInstCounter, n, nOrig, sym)
result = evalMacroCall(c.module, c.graph, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
if c.config.macrosToExpand.hasKey(sym.name.s):
@@ -482,10 +481,15 @@ proc forceBool(c: PContext, n: PNode): PNode =
if result == nil: result = n
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
result = forceBool(c, semConstExpr(c, n))
if result.kind != nkIntLit:
let nn = semExprWithType(c, n)
result = fitNode(c, getSysType(c.graph, n.info, tyBool), nn, nn.info)
if result == nil:
localError(c.config, n.info, errConstExprExpected)
return nn
result = getConstExpr(c.module, result, c.graph)
if result == nil:
localError(c.config, n.info, errConstExprExpected)
result = nn
proc semGenericStmt(c: PContext, n: PNode): PNode
proc semConceptBody(c: PContext, n: PNode): PNode
@@ -502,7 +506,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
n.add prc.ast
c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var c = newContext(graph, module)
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
@@ -518,7 +522,6 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
c.semTypeNode = semTypeNode
c.instTypeBoundOp = sigmatch.instTypeBoundOp
c.hasUnresolvedArgs = hasUnresolvedArgs
c.templInstCounter = new int
pushProcCon(c, module)
pushOwner(c, c.module)
@@ -594,7 +597,7 @@ proc recoverContext(c: PContext) =
while getCurrOwner(c).kind != skModule: popOwner(c)
while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} =
proc myProcess(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
# no need for an expensive 'try' if we stop after the first error anyway:
if c.config.errorMax <= 1:

View File

@@ -94,6 +94,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
if c.currentScope.symbols.counter == counterInitial or syms.len != 0:
matches(c, n, orig, z)
if z.state == csMatch:
#if sym.name.s == "==" and (n.info ?? "temp3"):
# echo typeToString(sym.typ)
# writeMatches(z)
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case best.state
@@ -230,9 +234,6 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.add typeToString(wanted)
when false:
if wanted.sym != nil:
candidates.add "(" & (c.config $ wanted.sym.info) & ")"
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
@@ -242,10 +243,6 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add "' is of type: "
var got = nArg.typ
candidates.add typeToString(got)
when false:
if got.sym != nil:
candidates.add "(" & (c.config $ got.sym.info) & ")"
doAssert wanted != nil
if got != nil: effectProblem(wanted, got, candidates, c)
of kUnknown: discard "do not break 'nim check'"
@@ -330,7 +327,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
var typeHint = ""
if sym == nil:
# Perhaps we're in a `compiles(foo.bar)` expression, or
# in a concept, e.g.:
# in a concept, eg:
# ExplainedConcept {.explain.} = concept x
# x.foo is int
# We could use: `(c.config $ n[1].info)` to get more context.
@@ -502,14 +499,9 @@ proc updateDefaultParams(call: PNode) =
proc getCallLineInfo(n: PNode): TLineInfo =
case n.kind
of nkAccQuoted, nkBracketExpr, nkCall, nkCallStrLit, nkCommand:
if len(n) > 0:
return getCallLineInfo(n[0])
of nkDotExpr:
if len(n) > 1:
return getCallLineInfo(n[1])
else:
discard
result = n.info
getCallLineInfo(n[0])
of nkDotExpr: getCallLineInfo(n[1])
else: n.info
proc semResolvedCall(c: PContext, x: TCandidate,
n: PNode, flags: TExprFlags): PNode =
@@ -539,10 +531,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
for s in instantiateGenericParamList(c, gp, x.bindings):
case s.kind
of skConst:
if not s.ast.isNil:
x.call.add s.ast
else:
x.call.add c.graph.emptyNode
x.call.add s.ast
of skType:
x.call.add newSymNode(s, n.info)
else:
@@ -564,7 +553,7 @@ proc tryDeref(n: PNode): PNode =
result.add n
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} =
filter: TSymKinds, flags: TExprFlags): PNode =
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
if r.state == csMatch:
@@ -648,7 +637,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
if s.ast[genericParamsPos].safeLen != n.len-1:
let expected = s.ast[genericParamsPos].safeLen
localError(c.config, getCallLineInfo(n), errGenerated, "cannot instantiate: '" & renderTree(n) &
"'; got " & $(n.len-1) & " typeof(s) but expected " & $expected)
"'; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(c, n)
@@ -688,14 +677,13 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
var x: PType
if param.typ.kind == tyVar:
x = newTypeS(param.typ.kind, c)
x = newTypeS(tyVar, c)
x.addSonSkipIntLit t.baseOfDistinct
else:
x = t.baseOfDistinct
call.add(newNodeIT(nkEmpty, fn.info, x))
if hasDistinct:
let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind}
var resolved = semOverloadedCall(c, call, call, filter, {})
var resolved = semOverloadedCall(c, call, call, {fn.kind}, {})
if resolved != nil:
result = resolved[0].sym
if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct):

View File

@@ -21,12 +21,11 @@ type
notes*: TNoteKinds
features*: set[Feature]
otherPragmas*: PNode # every pragma can be pushed
warningAsErrors*: TNoteKinds
POptionEntry* = ref TOptionEntry
PProcCon* = ref TProcCon
TProcCon* {.acyclic.} = object # procedure context; also used for top-level
# statements
TProcCon* = object # procedure context; also used for top-level
# statements
owner*: PSym # the symbol this context belongs to
resultSym*: PSym # the result symbol (if we are in a proc)
selfSym*: PSym # the 'self' symbol (if available)
@@ -35,6 +34,7 @@ type
inTryStmt*: int # whether we are in a try statement; works also
# in standalone ``except`` and ``finally``
next*: PProcCon # used for stacking procedure contexts
wasForwarded*: bool # whether the current proc has a separate header
mappingExists*: bool
mapping*: TIdTable
caseContext*: seq[tuple[n: PNode, idx: int]]
@@ -85,7 +85,6 @@ type
# this is used so that generic instantiations
# can access private object fields
instCounter*: int # to prevent endless instantiations
templInstCounter*: ref int # gives every template instantiation a unique id
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!)
@@ -144,7 +143,6 @@ type
# would otherwise fail.
unusedImports*: seq[(PSym, TLineInfo)]
exportIndirections*: HashSet[(int, int)]
lastTLineInfo*: TLineInfo
template config*(c: PContext): ConfigRef = c.graph.config
@@ -213,10 +211,9 @@ proc considerGenSyms*(c: PContext; n: PNode) =
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
new(result)
result.options = conf.options
result.defaultCC = ccNimCall
result.defaultCC = ccDefault
result.dynlib = nil
result.notes = conf.notes
result.warningAsErrors = conf.warningAsErrors
proc pushOptionEntry*(c: PContext): POptionEntry =
new(result)
@@ -225,14 +222,12 @@ proc pushOptionEntry*(c: PContext): POptionEntry =
result.defaultCC = prev.defaultCC
result.dynlib = prev.dynlib
result.notes = c.config.notes
result.warningAsErrors = c.config.warningAsErrors
result.features = c.features
c.optionStack.add(result)
proc popOptionEntry*(c: PContext) =
c.config.options = c.optionStack[^1].options
c.config.notes = c.optionStack[^1].notes
c.config.warningAsErrors = c.optionStack[^1].warningAsErrors
c.features = c.optionStack[^1].features
c.optionStack.setLen(c.optionStack.len - 1)
@@ -323,8 +318,7 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = newTypeS(tyTypeDesc, c)
incl typedesc.flags, tfCheckedForDestructor
internalAssert(c.config, typ != nil)
typedesc.addSonSkipIntLit(typ)
typedesc.addSonSkipIntLit(assertNotNil(c.config, typ))
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info,
c.config.options).linkTo(typedesc)
return newSymNode(sym, info)
@@ -382,7 +376,8 @@ proc makeNotType*(c: PContext, t1: PType): PType =
result.flags.incl tfHasMeta
proc nMinusOne(c: PContext; n: PNode): PNode =
result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n)
result = newNode(nkCall, n.info, @[
newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n])
# Remember to fix the procs below this one when you make changes!
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
@@ -391,8 +386,9 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
result.sons = @[intType]
if n.typ != nil and n.typ.n == nil:
result.flags.incl tfUnresolved
result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
makeStaticExpr(c, nMinusOne(c, n)))
result.n = newNode(nkRange, n.info, @[
newIntTypeNode(0, intType),
makeStaticExpr(c, nMinusOne(c, n))])
template rangeHasUnresolvedStatic*(t: PType): bool =
tfUnresolved in t.flags

View File

@@ -33,7 +33,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
# Note: This is n.info on purpose. It prevents template from creating an info
# context when called from an another template
pushInfoContext(c.config, n.info, s.detailedInfo)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, c.templInstCounter, efFromHlo in flags)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
popInfoContext(c.config)
@@ -62,18 +62,12 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})
if result.kind == nkEmpty:
# bug #12741, redundant error messages are the lesser evil here:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
# do not produce another redundant error message:
result = errorNode(c, n)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
if result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
@@ -82,7 +76,11 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})
if result.kind == nkEmpty:
# do not produce another redundant error message:
result = errorNode(c, n)
if result.typ == nil:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
@@ -178,7 +176,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
else:
discard
proc isCastable(c: PContext; dst, src: PType): bool =
proc isCastable(conf: ConfigRef; dst, src: PType): bool =
## Checks whether the source type can be cast to the destination type.
## Casting is very unrestrictive; casts are allowed as long as
## castDest.size >= src.size, and typeAllowed(dst, skParam)
@@ -191,14 +189,6 @@ proc isCastable(c: PContext; dst, src: PType): bool =
return false
if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc:
return false
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
return false
let conf = c.config
if conf.selectedGC in {gcArc, gcOrc}:
let d = skipTypes(dst, abstractInst)
let s = skipTypes(src, abstractInst)
if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal:
return false
var dstSize, srcSize: BiggestInt
dstSize = computeSize(conf, dst)
@@ -211,7 +201,7 @@ proc isCastable(c: PContext; dst, src: PType): bool =
result = false
elif srcSize < 0:
result = false
elif typeAllowed(dst, skParam, c) != nil:
elif typeAllowed(dst, skParam) != nil:
result = false
elif dst.kind == tyProc and dst.callConv == ccClosure:
result = src.kind == tyProc and src.callConv == ccClosure
@@ -339,7 +329,7 @@ proc semCast(c: PContext, n: PNode): PNode =
let castedExpr = semExprWithType(c, n[1])
if tfHasMeta in targetType.flags:
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
if not isCastable(c, targetType, castedExpr.typ):
if not isCastable(c.config, targetType, castedExpr.typ):
let tar = $targetType
let alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar
@@ -431,7 +421,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
m.diagnostics = @[]
m.diagnosticsEnabled = true
res = typeRel(m, t2, t1) >= isSubtype # isNone
# `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)`
# `res = sameType(t1, t2)` would be wrong, eg for `int is (int|float)`
result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ
@@ -632,12 +622,11 @@ proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
proc isUnresolvedSym(s: PSym): bool =
result = s.kind == skGenericParam
if not result and s.typ != nil:
result = tfInferrableStatic in s.typ.flags or
(s.kind == skParam and s.typ.isMetaType) or
(s.kind == skType and
s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
return s.kind == skGenericParam or
tfInferrableStatic in s.typ.flags or
(s.kind == skParam and s.typ.isMetaType) or
(s.kind == skType and
s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
# Checks whether an expression depends on generic parameters that
@@ -663,7 +652,7 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
return false
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or
if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or
sfCompileToCpp in c.module.flags):
checkSonsLen(n, 1, c.config)
result = n[0]
@@ -715,7 +704,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
for i in 1..<n.len:
if i < t.len and t[i] != nil and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
let it = n[i]
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
if it.kind != nkHiddenAddr:
@@ -736,7 +725,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
# calls and then they wouldn't be analysed otherwise
analyseIfAddressTakenInCall(c, n[i])
if i < t.len and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
if n[i].kind != nkHiddenAddr:
n[i] = analyseIfAddressTaken(c, n[i])
@@ -795,7 +784,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
return
if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
var call = newNodeIT(nkCall, n.info, n.typ)
call.add(n[0])
@@ -956,17 +945,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
hasErrorType = true
break
if not hasErrorType:
let typ = n[0].typ
msg.add(">\nbut expected one of: \n" &
typeToString(typ))
# prefer notin preferToResolveSymbols
# t.sym != nil
# sfAnon notin t.sym.flags
# t.kind != tySequence(It is tyProc)
if typ.sym != nil and sfAnon notin typ.sym.flags and
typ.kind == tyProc:
msg.add(" = " &
typeToString(typ, preferDesc))
typeToString(n[0].typ))
localError(c.config, n.info, msg)
return errorNode(c, n)
result = nil
@@ -1204,6 +1184,17 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
elif sfGenSym in s.flags:
# the owner should have been set by now by addParamOrResult
internalAssert c.config, s.owner != nil
if c.p.wasForwarded:
# gensym'ed parameters that nevertheless have been forward declared
# need a special fixup:
let realParam = c.p.owner.typ.n[s.position+1]
internalAssert c.config, realParam.kind == nkSym and realParam.sym.kind == skParam
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
elif c.p.owner.kind == skMacro:
# gensym'ed macro parameters need a similar hack (see bug #1944):
var u = searchInScopes(c, s.name)
internalAssert c.config, u != nil and u.kind == skParam and u.owner == s.owner
return newSymNode(u, n.info)
result = newSymNode(s, n.info)
of skVar, skLet, skResult, skForVar:
if s.magic == mNimvm:
@@ -1275,54 +1266,6 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
onUse(info, s)
result = newSymNode(s, info)
proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
case t.kind
of tyTypeParamsHolders:
result = readTypeParameter(c, t, i, n.info)
if result == c.graph.emptyNode:
result = n
n.typ = makeTypeFromExpr(c, n.copyTree)
of tyUserTypeClasses:
if t.isResolvedUserTypeClass:
result = readTypeParameter(c, t, i, n.info)
else:
n.typ = makeTypeFromExpr(c, copyTree(n))
result = n
of tyGenericParam, tyAnything:
n.typ = makeTypeFromExpr(c, copyTree(n))
result = n
else:
discard
proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode =
var ty = ty.skipTypes(tyDotOpTransparent)
case ty.kind
of tyEnum:
# look up if the identifier belongs to the enum:
var f = PSym(nil)
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty.sons[0] # enum inheritance
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(c, n.info, f)
onUse(n.info, f)
of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList:
let field = lookupInRecord(ty.n, i)
if field != nil:
n.typ = makeTypeDesc(c, field.typ)
result = n
of tyGenericInst:
result = tryReadingTypeField(c, n, i, ty.lastSon)
if result == nil:
result = tryReadingGenericParam(c, n, i, ty)
else:
result = tryReadingGenericParam(c, n, i, ty)
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access
checkSonsLen(n, 2, c.config)
@@ -1353,6 +1296,28 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
var f: PSym = nil
result = nil
template tryReadingGenericParam(t: PType) =
case t.kind
of tyTypeParamsHolders:
result = readTypeParameter(c, t, i, n.info)
if result == c.graph.emptyNode:
result = n
n.typ = makeTypeFromExpr(c, n.copyTree)
return
of tyUserTypeClasses:
if t.isResolvedUserTypeClass:
return readTypeParameter(c, t, i, n.info)
else:
n.typ = makeTypeFromExpr(c, copyTree(n))
return n
of tyGenericParam, tyAnything:
n.typ = makeTypeFromExpr(c, copyTree(n))
return n
else:
discard
var argIsType = false
if ty.kind == tyTypeDesc:
if ty.base.kind == tyNone:
# This is a still unresolved typedesc parameter.
@@ -1365,10 +1330,40 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
return nil
else:
return tryReadingTypeField(c, n, i, ty.base)
elif isTypeExpr(n.sons[0]):
return tryReadingTypeField(c, n, i, ty)
ty = ty.base
argIsType = true
else:
argIsType = isTypeExpr(n[0])
if argIsType:
ty = ty.skipTypes(tyDotOpTransparent)
case ty.kind
of tyEnum:
# look up if the identifier belongs to the enum:
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty[0] # enum inheritance
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(c, n.info, f)
onUse(n.info, f)
return
of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList:
let field = lookupInRecord(ty.n, i)
if field != nil:
n.typ = makeTypeDesc(c, field.typ)
return n
else:
tryReadingGenericParam(ty)
return
# XXX: This is probably not relevant any more
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
ty = n[0].typ
return nil
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
ty = ty.lastSon
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink})
@@ -1412,7 +1407,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we didn't find any field, let's look for a generic param
if result == nil:
let t = n[0].typ.skipTypes(tyDotOpTransparent)
result = tryReadingGenericParam(c, n, i, t)
tryReadingGenericParam(t)
proc dotTransformation(c: PContext, n: PNode): PNode =
if isSymChoice(n[1]):
@@ -1560,9 +1555,10 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
let aOrig = nOrig[0]
result = newTreeI(nkCall, n.info, setterId, a[0], semExprWithType(c, n[1]))
result = newNode(nkCall, n.info, sons = @[setterId, a[0],
semExprWithType(c, n[1])])
result.flags.incl nfDotSetter
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
if result != nil:
@@ -1575,22 +1571,17 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
# return a view into the first argument (if there is one):
let root = exprRoot(n)
if root != nil and root.owner == c.p.owner:
template url: string = "var_t_return.html".createDocLink
if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3" % [
root.name.s, renderTree(n, {renderNoComments}), url])
localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [
root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
elif root.kind == skParam and root.position != 0:
localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3" % [
root.name.s, renderTree(n, {renderNoComments}), url])
localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [
root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
case n.kind
of nkHiddenAddr, nkAddr: return n
of nkDerefExpr: return n[0]
of nkHiddenDeref, nkDerefExpr: return n[0]
of nkBracketExpr:
if n.len == 1: return n[0]
of nkHiddenDeref:
# issue #13848
# `proc fun(a: var int): var int = a`
discard
else: discard
let valid = isAssignable(c, n, isLent)
if valid != arLValue:
@@ -1604,7 +1595,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
if le.kind == nkHiddenDeref:
var x = le[0]
if (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView) and x.kind == nkSym and x.sym.kind == skResult:
if x.typ.kind in {tyVar, tyLent} and x.kind == nkSym and x.sym.kind == skResult:
n[0] = x # 'result[]' --> 'result'
n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
x.typ.flags.incl tfVarIsPtr
@@ -1714,9 +1705,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
var le = a.typ
if le == nil:
localError(c.config, a.info, "expression has no type")
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
isAssignable(c, a) in {arNone, arLentValue}) or (
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
isAssignable(c, a) in {arNone, arLentValue}) or
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
# Direct assignment to a discriminant is allowed!
localError(c.config, a.info, errXCannotBeAssignedTo %
renderTree(a, {renderNoComments}))
@@ -1736,7 +1727,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
internalAssert c.config, c.p.resultSym != nil
# Make sure the type is valid for the result variable
typeAllowedCheck(c, n.info, rhsTyp, skResult)
typeAllowedCheck(c.config, n.info, rhsTyp, skResult)
lhs.typ = rhsTyp
c.p.resultSym.typ = rhsTyp
c.p.owner.typ[0] = rhsTyp
@@ -1757,21 +1748,17 @@ proc semReturn(c: PContext, n: PNode): PNode =
if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or
(not c.p.owner.typ.isNil and isClosureIterator(c.p.owner.typ)):
if n[0].kind != nkEmpty:
if n[0].kind == nkAsgn and n[0][0].kind == nkSym and c.p.resultSym == n[0][0].sym:
discard "return is already transformed"
elif c.p.resultSym != nil:
# transform ``return expr`` to ``result = expr; return``
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
var a = newNodeI(nkAsgn, n[0].info)
a.add newSymNode(c.p.resultSym)
a.add n[0]
n[0] = a
n[0] = semAsgn(c, a)
# optimize away ``result = result``:
if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
n[0] = c.graph.emptyNode
else:
localError(c.config, n.info, errNoReturnTypeDeclared)
return
result[0] = semAsgn(c, n[0])
# optimize away ``result = result``:
if result[0][1].kind == nkSym and result[0][1].sym == c.p.resultSym:
result[0] = c.graph.emptyNode
else:
localError(c.config, n.info, "'return' not allowed here")
@@ -1833,11 +1820,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent)
else:
localError(c.config, n[0].info, errXExpected, "tuple constructor")
else:
when false:
# XXX investigate what we really need here.
if isViewType(t):
n[0] = takeImplicitAddr(c, n[0], false)
else: discard
proc semYield(c: PContext, n: PNode): PNode =
result = n
@@ -1865,32 +1848,29 @@ proc semYield(c: PContext, n: PNode): PNode =
elif c.p.owner.typ[0] != nil:
localError(c.config, n.info, errGenerated, "yield statement must yield a value")
proc semDefined(c: PContext, n: PNode): PNode =
checkSonsLen(n, 2, c.config)
# we replace this node by a 'true' or 'false' node:
result = newIntNode(nkIntLit, 0)
result.intVal = ord isDefined(c.config, considerQuotedIdent(c, n[1], n).s)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
if onlyCurrentScope:
result = localSearchInScope(c, i)
else:
result = searchInScopes(c, i) # no need for stub loading
proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
case n.kind
of nkIdent, nkAccQuoted:
result = if onlyCurrentScope:
localSearchInScope(c, considerQuotedIdent(c, n))
else:
searchInScopes(c, considerQuotedIdent(c, n))
of nkIdent:
result = lookUpForDefined(c, n.ident, onlyCurrentScope)
of nkDotExpr:
result = nil
if onlyCurrentScope: return
checkSonsLen(n, 2, c.config)
var m = lookUpForDeclared(c, n[0], onlyCurrentScope)
var m = lookUpForDefined(c, n[0], onlyCurrentScope)
if m != nil and m.kind == skModule:
let ident = considerQuotedIdent(c, n[1], n)
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = strTableGet(m.tab, ident)
of nkAccQuoted:
result = lookUpForDefined(c, considerQuotedIdent(c, n), onlyCurrentScope)
of nkSym:
result = n.sym
of nkOpenSymChoice, nkClosedSymChoice:
@@ -1899,11 +1879,15 @@ proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
result = nil
proc semDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
checkSonsLen(n, 2, c.config)
# we replace this node by a 'true' or 'false' node:
result = newIntNode(nkIntLit, 0)
result.intVal = ord lookUpForDeclared(c, n[1], onlyCurrentScope) != nil
if not onlyCurrentScope and considerQuotedIdent(c, n[0], n).s == "defined":
let d = considerQuotedIdent(c, n[1], n)
result.intVal = ord isDefined(c.config, d.s)
elif lookUpForDefined(c, n[1], onlyCurrentScope) != nil:
result.intVal = 1
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
@@ -2052,7 +2036,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
ids.add c.graph.emptyNode # no default value
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, dummyTemplate)
quotes[0] = tmpl[namePos]
@@ -2064,18 +2048,14 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
newIdentNode(getIdent(c.cache, "newIdentNode"), n.info)
else:
identNodeSym.newSymNode
quotes[1] = newTreeI(nkCall, n.info, identNode, newStrNode(nkStrLit, "result"))
result = newTreeI(nkCall, n.info,
quotes[1] = newNode(nkCall, n.info, @[identNode, newStrNode(nkStrLit, "result")])
result = newNode(nkCall, n.info, @[
createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
newTreeI(nkCall, n.info, quotes))
newNode(nkCall, n.info, quotes)])
result = semExpandToAst(c, result)
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# watch out, hacks ahead:
when defined(nimsuggest):
# Remove the error hook so nimsuggest doesn't report errors there
let tempHook = c.graph.config.structuredErrorHook
c.graph.config.structuredErrorHook = nil
let oldErrorCount = c.config.errorCounter
let oldErrorMax = c.config.errorMax
let oldCompilesId = c.compilesContextId
@@ -2084,7 +2064,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if c.compilesContextId == 0:
inc c.compilesContextIdGenerator
c.compilesContextId = c.compilesContextIdGenerator
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
# do not halt after first error:
c.config.errorMax = high(int)
# open a scope for temporary symbol inclusions:
let oldScope = c.currentScope
@@ -2124,9 +2105,6 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
c.config.m.errorOutputs = oldErrorOutputs
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
when defined(nimsuggest):
# Restore the error hook
c.graph.config.structuredErrorHook = tempHook
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we replace this node by a 'true' or 'false' node:
@@ -2165,7 +2143,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
# codegen would fail:
if sfCompilerProc in result.flags:
result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
result.flags = result.flags - {sfCompilerProc, sfExportc, sfImportc}
result.loc.r = nil
proc setMs(n: PNode, s: PSym): PNode =
@@ -2197,13 +2175,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = semTypeOf(c, n)
of mDefined:
markUsed(c, n.info, s)
result = semDefined(c, setMs(n, s))
of mDeclared:
result = semDefined(c, setMs(n, s), false)
of mDefinedInScope:
markUsed(c, n.info, s)
result = semDeclared(c, setMs(n, s), false)
of mDeclaredInScope:
markUsed(c, n.info, s)
result = semDeclared(c, setMs(n, s), true)
result = semDefined(c, setMs(n, s), true)
of mCompiles:
markUsed(c, n.info, s)
result = semCompiles(c, setMs(n, s), flags)
@@ -2590,43 +2565,6 @@ proc shouldBeBracketExpr(n: PNode): bool =
n[0] = be
return true
proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) =
# This takes care of complicated signatures such as:
# proc foo(a: int, b = a)
# proc bar(a: int, b: int, c = a + b)
#
# The recursion may confuse you. It performs two duties:
#
# 1) extracting all referenced params from default expressions
# into a let section preceding the call
#
# 2) replacing the "references" within the default expression
# with these extracted skLet symbols.
#
# The first duty is carried out directly in the code here, while the second
# duty is activated by returning a non-nil value. The caller is responsible
# for replacing the input to the function with the returned non-nil value.
# (which is the hoisted symbol)
if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
let paramPos = defExpr.sym.position + 1
if call[paramPos].kind != nkSym:
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.p.owner, letSection.info, c.p.owner.options)
hoistedVarSym.typ = call[paramPos].typ
letSection.add newTreeI(nkIdentDefs, letSection.info,
newSymNode(hoistedVarSym),
newNodeI(nkEmpty, letSection.info),
call[paramPos])
call[paramPos] = newSymNode(hoistedVarSym) # Refer the original arg to its hoisted sym
# arg we refer to is a sym, wether introduced by hoisting or not doesn't matter, we simply reuse it
defExpr = call[paramPos]
else:
for i in 0..<defExpr.safeLen:
hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
when defined(nimCompilerStackraceHints):
setFrameMsg c.config$n.info & " " & $n.kind
@@ -2755,15 +2693,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semDirectOp(c, n, flags)
else:
result = semIndirectOp(c, n, flags)
if nfDefaultRefsParam in result.flags:
result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
# We've found a default value that references another param.
# See the notes in `hoistParamsUsedInDefault` for more details.
var hoistedParams = newNodeI(nkLetSection, result.info)
for i in 1..<result.len:
hoistParamsUsedInDefault(c, result, hoistedParams, result[i])
result = newTreeIT(nkStmtListExpr, result.info, result.typ, hoistedParams, result)
of nkWhen:
if efWantStmt in flags:
result = semWhen(c, n, true)

View File

@@ -475,13 +475,15 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
else:
localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkBracket:
idx -= toInt64(firstOrd(g.config, x.typ))
idx = idx - toInt64(firstOrd(g.config, x.typ))
if idx >= 0 and idx < x.len: result = x[int(idx)]
else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < x.strVal.len:
result.intVal = ord(x.strVal[int(idx)])
elif idx == x.strVal.len and optLaxStrings in g.config.options:
discard
else:
localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n)
else: discard
@@ -547,13 +549,9 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
localError(g.config, s.info,
"{.intdefine.} const was set to an invalid integer: '" &
g.config.symbols[s.name.s] & "'")
else:
result = copyTree(s.ast)
of mStrDefine:
if isDefined(g.config, s.name.s):
result = newStrNodeT(g.config.symbols[s.name.s], n, g)
else:
result = copyTree(s.ast)
of mBoolDefine:
if isDefined(g.config, s.name.s):
try:
@@ -562,8 +560,6 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
localError(g.config, s.info,
"{.booldefine.} const was set to an invalid bool: '" &
g.config.symbols[s.name.s] & "'")
else:
result = copyTree(s.ast)
else:
result = copyTree(s.ast)
of skProc, skFunc, skMethod:
@@ -643,9 +639,9 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
discard
else:
result = magicCall(m, n, g)
except OverflowDefect:
except OverflowError:
localError(g.config, n.info, "over- or underflow")
except DivByZeroDefect:
except DivByZeroError:
localError(g.config, n.info, "division by zero")
of nkAddr:
var a = getConstExpr(m, n[0], g)

View File

@@ -28,7 +28,7 @@ proc getIdentNode(c: PContext; n: PNode): PNode =
type
GenericCtx = object
toMixin, toBind: IntSet
toMixin: IntSet
cursorInBody: bool # only for nimsuggest
bracketExpr: PNode
@@ -124,7 +124,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
if ident.id notin ctx.toMixin and withinMixin notin flags:
errorUndeclaredIdentifier(c, n.info, ident.s)
else:
if withinBind in flags or s.id in ctx.toBind:
if withinBind in flags:
result = symChoice(c, n, s, scClosed)
elif s.isMixedIn:
result = symChoice(c, n, s, scForceOpen)
@@ -155,7 +155,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config)
if s != nil:
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags or s.id in ctx.toBind:
if withinBind in flags:
result = newDot(result, symChoice(c, n, s, scClosed))
elif s.isMixedIn:
result = newDot(result, symChoice(c, n, s, scForceOpen))
@@ -211,8 +211,6 @@ proc semGenericStmt(c: PContext, n: PNode,
result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
of nkMixinStmt:
result = semMixinStmt(c, n, ctx.toMixin)
of nkBindStmt:
result = semBindStmt(c, n, ctx.toBind)
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1, c.config)
@@ -228,11 +226,8 @@ proc semGenericStmt(c: PContext, n: PNode,
var mixinContext = false
if s != nil:
incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr}
let whichChoice = if s.id in ctx.toBind: scClosed
elif s.isMixedIn: scForceOpen
else: scOpen
let sc = symChoice(c, fn, s, whichChoice)
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr}
let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
case s.kind
of skMacro:
if macroToExpand(s) and sc.safeLen <= 1:
@@ -265,7 +260,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# We're not interested in the example code during this pass so let's
# skip it
if s.magic == mRunnableExamples:
first = result.safeLen # see trunnableexamples.fun3
inc first
of skGenericParam:
result[0] = newSymNodeTypeDesc(s, fn.info)
onUse(fn.info, s)
@@ -497,14 +492,12 @@ proc semGenericStmt(c: PContext, n: PNode,
proc semGenericStmt(c: PContext, n: PNode): PNode =
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
proc semConceptBody(c: PContext, n: PNode): PNode =
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {withinConcept}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)

View File

@@ -66,7 +66,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
continue
let symKind = if q.typ.kind == tyStatic: skConst else: skType
var s = newSym(symKind, q.name, getCurrOwner(c), q.info)
s.flags.incl {sfUsed, sfFromGeneric}
s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(idTableGet(pt, q.typ))
if t == nil:
if tfRetType in q.typ.flags:
@@ -178,13 +178,13 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
internalAssert c.config, header.kind == tyGenericInvocation
var
typeMap: LayeredIdTable
cl: TReplTypeVars
initIdTable(cl.symMap)
initIdTable(cl.localCache)
cl.typeMap = LayeredIdTable()
initIdTable(cl.typeMap.topLayer)
initIdTable(typeMap.topLayer)
cl.typeMap = addr(typeMap)
cl.info = info
cl.c = c
cl.allowMetaTypes = allowMetaTypes
@@ -244,7 +244,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
#addDecl(c, prc)
pushInfoContext(c.config, info)
var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(c, typeMap, info, nil)
var cl = initTypeVars(c, addr(typeMap), info, nil)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
@@ -328,7 +328,7 @@ proc fillMixinScope(c: PContext) =
p = p.next
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym {.nosinks.} =
info: TLineInfo): PSym =
## Generates a new instance of a generic procedure.
## The `pt` parameter is a type-unsafe mapping table used to link generic
## parameters to their concrete types within the generic instance.

View File

@@ -42,6 +42,9 @@ type
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
proc skipAddr(n: PNode): PNode {.inline.} =
(if n.kind == nkHiddenAddr: n[0] else: n)
proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
result = newNodeI(nkBracketExpr, n.info)
for i in 1..<n.len: result.add(n[i])
@@ -399,18 +402,14 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
# Replace nkDerefExpr by nkHiddenDeref
# nkDeref is for 'ref T': x[].field
# nkHiddenDeref is for 'var T': x<hidden deref [] here>.field
proc transform(procSym: PSym; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
proc transform(n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
result = shallowCopy(n)
if sameTypeOrNil(n.typ, old):
result.typ = fresh
if n.kind == nkSym:
if n.sym == oldParam:
result.sym = newParam
elif n.sym.owner == orig:
result.sym = copySym(n.sym)
result.sym.owner = procSym
if n.kind == nkSym and n.sym == oldParam:
result.sym = newParam
for i in 0 ..< safeLen(n):
result[i] = transform(procSym, n[i], old, fresh, oldParam, newParam)
result[i] = transform(n[i], old, fresh, oldParam, newParam)
#if n.kind == nkDerefExpr and sameType(n[0].typ, old):
# result =
@@ -424,35 +423,21 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
let newParam = newSym(skParam, oldParam.name, result, result.info)
newParam.typ = newParamType
# proc body:
result.ast = transform(result, orig.ast, origParamType, newParamType, oldParam, newParam)
result.ast = transform(orig.ast, origParamType, newParamType, oldParam, newParam)
# proc signature:
result.typ = newProcType(result.info, result)
result.typ.addParam newParam
proc semQuantifier(c: PContext; n: PNode): PNode =
checkSonsLen(n, 2, c.config)
checkMinSonsLen(n, 2, c.config)
openScope(c)
result = newNodeIT(n.kind, n.info, n.typ)
result.add n[0]
let args = n[1]
assert args.kind == nkArgList
for i in 0..args.len-2:
let it = args[i]
var valid = false
if it.kind == nkInfix:
let op = considerQuotedIdent(c, it[0])
if op.id == ord(wIn):
let v = newSymS(skForVar, it[1], c)
styleCheckDef(c.config, v)
onDef(it[1].info, v)
let domain = semExprWithType(c, it[2], {efWantIterator})
v.typ = domain.typ
valid = true
addDecl(c, v)
result.add newTree(nkInfix, it[0], newSymNode(v), domain)
if not valid:
localError(c.config, n.info, "<quantifier> 'in' <range> expected")
result.add forceBool(c, semExprWithType(c, args[^1]))
for i in 0..n.len-2:
let v = newSymS(skForVar, n[i], c)
styleCheckDef(c.config, v)
onDef(n.info, v)
n[i] = newSymNode(v)
addDecl(c, v)
n[^1] = forceBool(c, semExprWithType(c, n[^1]))
closeScope(c)
proc semOld(c: PContext; n: PNode): PNode =
@@ -527,24 +512,14 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
elif optTinyRtti in c.config.globalOptions:
let nfin = skipConvCastAndClosure(n[^1])
let fin = case nfin.kind
of nkSym: nfin.sym
of nkLambda, nkDo: nfin[namePos].sym
else:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
nil
if fin != nil:
if fin.kind notin {skProc, skFunc}:
# calling convention is checked in codegen
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
# check if we converted this finalizer into a destructor already:
let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin:
discard "already turned this one into a finalizer"
else:
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
let fin = if n[^1].kind == nkLambda: n[^1][namePos].sym
else: n[^1].sym
# check if we converted this finalizer into a destructor already:
let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin:
discard "already turned this one into a finalizer"
else:
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
result = n
of mDestroy:
result = n
@@ -570,13 +545,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
let constructed = result[1].typ.base
if constructed.requiresInit:
message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
of mIsolate:
if not checkIsolate(n[1]):
localError(c.config, n.info, "expression cannot be isolated: " & $n[1])
result = n
of mPred:
if n[1].typ.skipTypes(abstractInst).kind in {tyUInt..tyUInt64}:
n[0].sym.magic = mSubU
result = n
else:
result = n

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