Compare commits

...

986 Commits

Author SHA1 Message Date
narimiran
018ae963ba add bufixes for 1.4 in its changelog
(cherry picked from commit 091ec916fd)
2020-10-16 08:14:05 +02:00
narimiran
cffbf5e778 create a changelog for 1.4.0
(cherry picked from commit 6349001879)
2020-10-16 07:17:09 +02:00
narimiran
cac0e01725 bump NimVersion to 1.4.0 2020-10-15 16:10:08 +02:00
shirleyquirk
4ef255b69d fix rlock compilation failure (#15584)
* change SysLockType_Reentrant

fix edge case where using SysLockType_Reentrant doesn't trigger an #include pthread.h

* syslocktype_reentrant now a var
* remove nodecl to remove empty system_syslocks.c
* let is better than var.

in reality SysLockType = enum, maybe that would be a better fix
2020-10-15 12:54:01 +02:00
Andreas Rumpf
da4aa2e1fb renamed '=' to '=copy' [backport:1.2] (#15585)
* Assign hook name changed to `=copy`
* Adapt destructors.rst
* [nobackport] Duplicate tests for =copy hook
* Fix tests
* added a changelog entry

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-10-15 12:52:30 +02:00
Igor Ribeiro de Assis
42c180c665 Fix crash in parsexml (#15582) (#15583)
Co-authored-by: Igor Ribeiro de Assis <igor.ribeiro_de_assis@zeiss.com>
2020-10-15 12:45:55 +02:00
Andreas Rumpf
fd9ab2ce6d ORC: API extensions for 1.4 (#15581) 2020-10-15 11:51:40 +02:00
Andreas Rumpf
1bbc20010e harden the ORC asyncleak3 test case (#15580)
* harden the ORC asyncleak3 test case

* add another ORC stress test
2020-10-15 09:42:43 +02:00
genotrance
a4c28394be Bump nimble (#15573) 2020-10-14 22:26:44 +02:00
Andreas Rumpf
644eb4dd54 ORC: critical bugfix for the cycle analyser, introduce -d:nimStressOrc for easier stress testing (#15572) 2020-10-14 22:26:21 +02:00
alaviss
c2ba4ef979 suggest: try to find the implementation of a symbol when def is used (#15555)
* suggest: try to find the implementation of a symbol when def is used

* suggest: return all declarations of the symbol on `def`
2020-10-14 17:08:56 +02:00
Clyybber
977bccdbff Make useVersion:1.0 disable the proc arg sym change (#15570)
* Make useVersion:1.0 disable the proc arg sym change

* Also do this for useVersion:1.2
2020-10-14 16:07:25 +02:00
Andreas Rumpf
8978112457 fixes a C code generator regression, no need to backport, only the 1.4 line is affected (#15569) 2020-10-14 13:58:36 +02:00
Timothee Cour
09cad44be9 ci docs: add config/nimdoc.cfg to paths (#15566) 2020-10-14 12:04:14 +02:00
Benjamin Lee
12c8ef5949 Update the list of GC options when raising an error (closes #15547) (#15553) 2020-10-14 11:20:59 +02:00
Andreas Rumpf
c664fb2843 sigmatch: hotfix [backport] (#15565) 2020-10-14 09:55:47 +02:00
narimiran
fc90eb9f27 change case in nimdoc [ci skip] 2020-10-14 09:26:44 +02:00
Timothee Cour
0c0f86b2c5 reference fusion docs (#15562) 2020-10-14 09:25:28 +02:00
alaviss
d1af9587b8 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.
2020-10-13 17:39:32 +01:00
Timothee Cour
0134e34e03 dup docs: add an example with addQuoted (#15548)
* dup docs: add addQuoted example

* fixup
2020-10-13 08:24:30 +02:00
Christopher Dunn
f1d81dc6e6 Fix doc for CountTable (#15561) [backport] 2020-10-13 06:33:53 +02:00
Christian Ulrich
1f51a33998 close socket in getPrimaryIPAddr even if exception occurs (#15558) 2020-10-12 22:02:17 +02:00
Timothee Cour
30b966bdf7 unbreak CI: fix logic for skipping ci (#15556) 2020-10-12 21:04:40 +02:00
cooldome
9668a1106d Fix 15543 (#15544)
* fix #15543

* fix spacing

* fix test

* simplify test for freebsd platform
2020-10-12 10:12:32 +01:00
Andreas Rumpf
d66e274e1a refactoring: moved setOutFile to where it belongs 2020-10-11 20:44:04 +02:00
Andreas Rumpf
3492178494 refactoring: removed cmdlinehelper.mainCommand callback 2020-10-11 20:44:04 +02:00
flywind
c2c7f60259 docs minor (#15550) 2020-10-11 20:43:44 +02:00
Timothee Cour
3eac9b2344 os: add overload copyFile*(source, dest: string, isDir = false) (#15537)
* os: add overload copyFile*(source, dest: string, isDir = false)
* renamed to copyFileToDir
2020-10-11 20:43:01 +02:00
Andreas Rumpf
992952d868 nimpretty: do not produce 'line too long' messages (#15541) 2020-10-10 17:46:22 +02:00
Christian Ulrich
c7ccbfac39 close socket in getPrimaryIPAddr (#15538) [backport] 2020-10-10 07:06:13 +02:00
Timothee Cour
8a5f550491 followup after #15529 and #15534 (#15536) 2020-10-10 07:05:27 +02:00
genotrance
442841037a Fix #12027 (#15519) 2020-10-10 07:04:57 +02:00
genotrance
0a560144ce Bump nimble (#15539) 2020-10-10 07:04:03 +02:00
Andreas Rumpf
d430216288 fixes #15532 (#15534) 2020-10-09 16:18:36 +02:00
Timothee Cour
16e8005031 fix gitignore for testament cruft (#15530)
* fix gitignore for testament cruft

* fix rendertree => renderTree
2020-10-09 11:28:21 +02:00
Timothee Cour
8fb57d7451 close #13081 (#15529)
* close #13081

* fixup
2020-10-09 08:56:09 +02:00
cooldome
91ce4515c8 fix gc:arc in nimscript (#15525) 2020-10-09 08:52:26 +02:00
lihaifeng
3eaacac230 Update parsecfg.nim (#15513)
* Update parsecfg.nim

Returns the specified default value if the specified key value does not exist.

* Update lib/pure/parsecfg.nim

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>

* Update lib/pure/parsecfg.nim

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>

* Update lib/pure/parsecfg.nim

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>
2020-10-08 17:17:00 +02:00
Andreas Rumpf
538a57a522 fixes #15511 (#15524) 2020-10-08 17:09:28 +02:00
Andreas Rumpf
cfba237d14 fixes #15510 (#15523) 2020-10-08 15:28:23 +02:00
ee7
aa0b73575c changelog.md: Group the new to procs (#15522)
* changelog.md: Group the new `to` procs [ci skip]

This also moves the `critbits.toCritBitTree` entry from the "Language
Changes" section to the "Standard library additions and changes"
section.

* changelog.md: Remove extra space
2020-10-08 14:21:20 +02:00
Andreas Rumpf
1e9d83efb0 fixes #15512 (#15521) 2020-10-08 14:17:27 +02:00
Araq
4d91cc7950 changelog improvements 2020-10-08 11:43:18 +02:00
Araq
0ac74ddd74 fixes a regression 2020-10-08 11:43:18 +02:00
cooldome
fe187719ab fix #15516 (#15518) 2020-10-08 09:12:03 +02:00
Andreas Rumpf
3b901d1e36 docgen: improve alignment of comments (still not perfect) (#15506)
* docgen: improve alignment of comments (still not perfect)

* fix error message text in `tunknown_named_parameter`

Co-authored-by: narimiran <narimiran@disroot.org>
2020-10-07 14:39:13 +02:00
Andreas Rumpf
0426a4d85a fixes #15508 (#15509) 2020-10-07 14:38:25 +02:00
Andreas Rumpf
acbe27b082 disable 'observable stores' warning message for 1.4 (#15507) 2020-10-07 13:05:19 +02:00
Andreas Rumpf
51e3e0c7c4 implements https://github.com/nim-lang/RFCs/issues/260 (#15505)
* implements https://github.com/nim-lang/RFCs/issues/260

* added a test case
2020-10-07 00:09:28 +02:00
Serban Constantin
dd86228548 update unittest docs with correct exit code info (#15502) 2020-10-06 18:05:57 +02:00
Paul Tan
fa84121421 effects: exclude swap() from "indirect calls" assumption (#15504)
swap() will never call any procs passed to it, and so it can be safely
excluded from the "assume indirect calls are taken" effects tracking
rule.
2020-10-06 18:05:31 +02:00
Juan Carlos
695f955f70 inline tiny proc (#15498) 2020-10-06 16:52:12 +02:00
IDF
9560e49e8f New hint for unused exceptions in .raises (#15492)
* New hint for unused exceptions in .raises

* Fix effects test

* Further adapt teffects1.nim
2020-10-06 16:49:30 +02:00
Andreas Rumpf
92163fa330 implements https://github.com/nim-lang/RFCs/issues/258 (#15503)
* implements https://github.com/nim-lang/RFCs/issues/258

* don't be too strict with custom pragma blocks

* cast pragmas: documentation

* added most missing inference query procs to effecttraits.nim
2020-10-06 16:47:15 +02:00
Benjamin Lee
acd71dd6bb Iterate over smaller set when computing intersection (#15497)
Closes #15496
2020-10-06 10:29:45 +02:00
Juan Carlos
aca1fae55a GitHub Actions Skip CI (#15289) 2020-10-06 04:52:49 +00:00
Araq
37758826ff typo 2020-10-06 06:33:43 +02:00
Araq
e9d7e21dbe minor reformating 2020-10-06 06:10:47 +02:00
Andreas Rumpf
4e438f9096 const view types; fixes some cases from https://github.com/nim-lang/Nim/issues/15428 (#15488) 2020-10-05 18:31:46 +02:00
Juan Carlos
1e28cea0d1 inline tiny func on httpcore (#15480) 2020-10-05 17:08:50 +02:00
David Krause
f25ca0d304 added testament documentation link to tools.rst (#15481) 2020-10-05 17:04:47 +02:00
flywind
af9cc2882f use func in uri module (#15486) 2020-10-05 17:04:08 +02:00
Miran
112b11c154 group procs of the same name in TOC (#15487)
* group procs of the same name in TOC

* correctly show `sink` parameters in TOC

* no need to reinvent the wheel - `mgetorPut` exists

* better setting of text color [ci skip]

* fix CSS for better alignment
2020-10-05 17:03:14 +02:00
Luis Felipe Manfroni
5967b6f60f doc(sugar): added description and examples to dup (#15455) 2020-10-05 12:02:08 +02:00
Euan
cc4c546f8f Fix #15493 - disable TLS emulation for NetBSD (#15494)
TLS emulation was already disabled for FreeBSD due to the same issue.
2020-10-05 12:00:06 +02:00
flywind
b760fdc9ca make testing for prologue more stable (#15491) 2020-10-05 09:57:23 +02:00
supakeen
bbe2eb20df Provide a configurable progressInterval. (#15477) 2020-10-04 11:32:07 +01:00
Abhishek Dubey
ccd1f58183 Installation Instruction (#15485)
The instruction command was missing `install` for Ubuntu.
2020-10-04 10:58:19 +02:00
alaviss
fc973b2c0c renderer: use the biggest integer type for masking literals (#15482)
On 32-bit system the mask would have a size of 32-bit, which is smaller
than the BiggestInt (usually 64-bit) it was masked against.

For some reason this only affect 32-bit Windows but not 32-bit Linux.
Might just be a difference in how gcc handle out of bound shifts for
Windows and Linux.
2020-10-04 00:39:56 +02:00
Andreas Rumpf
2288188fe9 fixes https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] (#15479) 2020-10-03 17:34:42 +02:00
supakeen
662c508075 Return type of asyncftpclient to fix example. (#15476)
Related to: #13641
2020-10-03 13:43:43 +02:00
alaviss
dcd0ce1775 niminst: restore ZIP building functionality (#15472)
This is necessary for building Windows releases, was erroneously removed
by #15451.
2020-10-02 22:48:35 +02:00
ee7
0a05176057 heapqueue.nim: Add toHeapQueue proc (#15459)
Similar to:
- `critbits.toCritBitTree`
- `deques.toDeque`
- `sets.toHashSet`
- `tables.toTable`

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-10-02 16:01:03 -04:00
ee7
d48b356e49 intsets.nim: Add toIntSet proc (#15460)
Similar to:
- `critbits.toCritBitTree`
- `deques.toDeque`
- `sets.toHashSet`
- `tables.toTable`
2020-10-02 21:10:24 +02:00
alaviss
7ef22bf912 koch: remove c2nim from windows release builds (#15471)
We don't ship this tool with any other OS, and the c2nim bundle is
non-deterministic due to the lack of a pinned commit.
2020-10-02 19:18:44 +02:00
Andreas Rumpf
9828392df3 implements https://github.com/nim-lang/RFCs/issues/257 (#15466) 2020-10-02 18:53:22 +02:00
alaviss
e3eae3f7c7 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.
2020-10-02 18:52:20 +02:00
Andreas Rumpf
ff70ff529d remove nim.cfg file change lefover [backport:1.2] (#15469) 2020-10-02 18:51:49 +02:00
Andreas Rumpf
7d8c1be8fb parser hotfix: don't run into endless loops; regression (#15468) 2020-10-02 18:26:52 +02:00
Andreas Rumpf
1f4b9cebd4 Added std/effecttraits.nim (#15462) 2020-10-02 17:22:31 +02:00
Andreas Rumpf
aa1d7fe1e9 closureiters: fixes #15243 (#15454) [backport:1.2]
* fixes #15243 [backport:1.2]
2020-10-02 12:38:16 +02:00
Euan
f785174c60 Ref #14094 - disable hot code reloading tests on NetBSD (#15458) 2020-10-02 11:17:31 +02:00
flywind
6e32a9e88c use func in httpcore (#15457) 2020-10-02 08:47:24 +02:00
Juan Carlos
d1eb76184b Clean out niminst (#15451) 2020-10-01 22:19:06 +02:00
Euan
b4fe0c8862 Fix #15452 - ip protocol not defined on NetBSD (#15453) 2020-10-01 22:15:34 +02:00
Clyybber
37e0d6f32d Fix typo 2020-10-01 19:58:53 +02:00
Clyybber
800d6204cd Fix "arraq" typo :) 2020-10-01 19:58:08 +02:00
shirleyquirk
84d9b1227d fixes #15430, pop pragma takes invalid input (#15449)
* fix #15430, pop pragma

{.pop, experimental.} should be allowed, but not {.pop experimental.}
2020-10-01 18:07:55 +02:00
c-blake
26d656e73e Add first draft of new osproc.readLines (#15429)
* Add first draft of new osproc.readLines

* Add test for new osproc.readLines

* Rename test to start w/t to run; Also add newline to output

* Suppress hint messages.

* Output should match this time.

* Shoulda picked a program with simpler syntax than ..lol

* Address https://github.com/nim-lang/Nim/pull/15429#issuecomment-701890898
and https://github.com/nim-lang/Nim/pull/15429#issuecomment-701985976 by
factoring `readLines` into `iterator lines` and a wrapper `proc`.

* Address https://github.com/nim-lang/Nim/pull/15429#issuecomment-702127289
and also add a `ReadIOEffect` tag to the iterator (called by the wrapper..
so it should need no separate tag, if I understand correctly).
2020-10-01 18:06:38 +02:00
cooldome
531ed2dc36 fix #15405. deepcopy arc (#15410)
* fix #15405
* fix tests
* deepcopy for ARC has to be enabled via --deepcopy:on

Co-authored-by: Araq <rumpf_a@web.de>
2020-10-01 17:39:48 +02:00
alaviss
3919f0aa54 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.
2020-10-01 17:20:38 +02:00
flywind
0bfa0fcaea [docs minor] unify generates and Generates (#15434)
* [docs] unify generates and Generates

* fix typo
2020-10-01 15:17:16 +02:00
Juan Carlos
5e160bff1b Add critbits.toCritBitTree (#15444)
* Add critbits.toCritBitTree

* https://github.com/nim-lang/Nim/pull/15444#discussion_r498035342
2020-10-01 15:11:10 +02:00
Juan Carlos
8f90ac6af1 Clean out (#15448) 2020-10-01 15:07:57 +02:00
Andreas Rumpf
ab405c936e views: yet another bugfix (#15447)
* views: yet another bugfix

* views: extended the spec

* views: take into account potential hidden mutations via proc calls
2020-10-01 15:04:36 +02:00
Juan Carlos
79a92da8ef Clean out (#15440) 2020-10-01 12:39:50 +02:00
Juan Carlos
4e7d383f29 Clean out jssys (#15442) 2020-10-01 11:21:27 +02:00
Andreas Rumpf
2b91845f1d refactoring, fixes yet another strictFuncs regression (#15446) 2020-10-01 11:16:04 +02:00
Andreas Rumpf
b703f02ad2 added missing .noalias support for object fields (#15445) 2020-10-01 09:46:50 +02:00
Juan Carlos
6b3654c48d Add 1 overload to apply (#15439) 2020-10-01 09:22:22 +02:00
Andreas Rumpf
86d7b63e2a better support for view types (#15436)
* you can put borrows into tables

* enforces mutating views only mutate mutable data
2020-09-30 20:44:18 +02:00
flywind
9c86f4867e fix doc search(escape HTML code) (#15433)
* use release version

* fix doc search
2020-09-30 10:52:49 +02:00
Miran
eb2a4961c7 various documentation fixes [backport] (#15422) 2020-09-29 23:43:12 +02:00
Andreas Rumpf
4058801607 spec for view types (#15424)
* spec for view types
* spec additions
* refactoring; there are two different kinds of views
* refactorings and spec additions
* enforce that view types are initialized
* enforce borrowing from the first formal parameter
* enforce lifetimes for borrowing of locals
* typo in the manual
* clarify in the implementation what a borrow operation really is
2020-09-29 23:42:38 +02:00
shirleyquirk
f8866598e7 odbc regression from #14357 (#15417)
#14357 changed from sending 'val', an int, to a pointer to int, which is understandable, but not how SQLSetEnvAttr works.
"Depending on the value of Attribute, ValuePtr will be a 32-bit integer value or point to a null-terminated character string"
2020-09-29 17:08:24 +02:00
Yuriy Glukhov
22d0a39932 Dont assert on setstacksize result in iOS (#15427) [backport:1.2] 2020-09-29 16:55:53 +02:00
Timothee Cour
5f9b366180 document that items no longer works with enum with holes (#15426) 2020-09-29 07:54:17 +02:00
Andreas Rumpf
50b6f6996a .noalias annotation; frontend support (#15419)
* .noalias annotation; frontend support

* added .noalias support to Nim; implements https://github.com/nim-lang/RFCs/issues/204
2020-09-28 13:51:39 +02:00
Andreas Rumpf
453167a41e cleanup lib/system/stacktraces.nim; refs #15416 (#15418) 2020-09-28 10:51:13 +02:00
Andreas Rumpf
f1ac01459c produce runtime type information for reified openArrays (#15415)
* produce runtime type information for reified openArrays

* added a test case
2020-09-27 20:44:22 +02:00
hlaaftana
0ea559611d Fix proc generic params ident defs, missing empty (#15412) 2020-09-27 19:47:58 +02:00
Andreas Rumpf
57b7841c18 better support for slices as views (#15414)
* moved view tests to tests/views
* refactoring
* more refactorings
* better support for system.toOpenArray for first class view types
2020-09-27 09:20:10 +02:00
Andreas Rumpf
e6616115e6 cursor inference: makes combparser work; refactorings (#15411)
* cursor inference: makes combparser work; refactorings
2020-09-26 13:11:35 +02:00
alaviss
d4892e9388 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.
2020-09-26 09:31:55 +02:00
Miran
2de6e18774 fix #11537, correct parse inline code without surrounding spaces (#15399) 2020-09-25 09:25:47 +02:00
Andreas Rumpf
e9fa486493 fixes #14983 (#15320)
* fixes #14983

* allow bootstrapping with 0.20

* added a test case for the new system.add with a sink parameter

* make npeg green again
2020-09-25 08:49:21 +02:00
cooldome
68ec7a018b Revert "fix #15035 (#15236)" (#15408)
This reverts commit f8c48fc186.
2020-09-24 22:21:14 +02:00
Andreas Rumpf
e3b5f80a89 more precise borrow checking of 'result' (#15406) 2020-09-24 22:07:23 +02:00
Andreas Rumpf
ce72d7ffc5 fixes #15403 (#15404) 2020-09-24 19:34:59 +02:00
Miran
496e9f74e1 fix #14474, crash inside of a sole code-block (#15402) 2020-09-24 16:41:08 +02:00
Andreas Rumpf
4ec5cbac0d fixes #15361 (#15401)
* fixes #15361; better cursor inference
2020-09-24 15:41:45 +02:00
flywind
8a6c5edc43 use release version (#15400) 2020-09-24 14:14:23 +02:00
flywind
e85c5ad379 fix #15333 (#15336) 2020-09-24 08:54:13 +02:00
genotrance
7a6f4eca19 Bump nimble (#15398) 2020-09-24 08:07:32 +02:00
cooldome
f21a49b2c4 Fix #15389 (#15390)
* allow result symbol reuse

* try different approach

* Revert "try different approach"

This reverts commit abcfb6b759.
2020-09-24 00:07:30 +01:00
Miran
fe3211fbcf fix the indentation in --help and --fullhelp (#15387)
* fix the indentation in `--help` and `--fullhelp`

* a better way to fix it
2020-09-23 12:44:41 +02:00
Araq
94c8d53a03 'koch temp' bugfix 2020-09-23 10:41:33 +02:00
Andreas Rumpf
e2d80b15a6 finish the stacktraces.nim implementation [backport:1.2] (#15393) 2020-09-23 10:01:52 +02:00
Clyybber
4b9eea2fcc Fix forward declarations in shadow scope contexts (#15386)
* Fix forward declarations in shadow scope contexts

* Add testcase for #15385

* Less empty lines

* Fix tests

* Inline isShadowScope

* Add original testcase (with reduced amount of iterations)

* Add testcase without forward decl
2020-09-22 18:24:13 +02:00
Miran
11c377c114 add enumerate macro (#15297)
* add `enumerate` macro

* address the comments

* put `enumerate` in its own module
2020-09-22 13:08:36 +02:00
flywind
ab05e141c0 deinitLock (#15383)
* deinitLock

* minor
2020-09-22 13:07:31 +02:00
Andreas Rumpf
1fae66e4df 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>
2020-09-22 13:03:24 +02:00
Clyybber
d67c5cb751 Add strutils.indentation and make unindent use it (#15264)
* Add strutils.indentation and make unindent use it

* Code style

* Fix bootstrapping

* Improve wording

* Fix test

* Introduce without breaking change

* Fix

* Reduce diff

* Fix docs link

* Add since annotation

* Update changelog
2020-09-22 10:43:12 +02:00
alaviss
aca9c5fb30 os: make getApplFreebsd available for NetBSD (#15381)
NetBSD was switched to getApplFreebsd() in #15359, however the proc was
not made available for the said target.

This commit exposes `getApplFreebsd()` to NetBSD.
2020-09-21 19:52:44 +02:00
genotrance
8f511fd0e6 Bump nimble (#15380) 2020-09-21 11:48:00 -05:00
Miran
4645183272 fix #6430, support :target: for images (#15379) 2020-09-21 17:01:12 +02:00
flywind
40a868bccc add testcase for #6060 (#15366)
* add testcase for #6060

* Remove overspecific testament spec

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-09-21 13:37:14 +02:00
flywind
6c83eb48c2 add testcase for #7165 (#15368)
* add testcase for #7165

* Remove overspecific testament spec

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-09-21 13:32:05 +02:00
Juan Carlos
db9ab2a4c0 Documentation prelude (#15377) 2020-09-21 12:37:14 +02:00
Andreas Rumpf
c2434d939e fixes #15360 [backport:1.2] (#15378) 2020-09-21 12:35:23 +02:00
flywind
0a1e4cad7f add testcase for #9710 (#15365)
* string is not nil anymore

* tatus
2020-09-21 12:21:05 +02:00
Andreas Rumpf
4d75059e8b added a basic ORC test I still had lying around (#15376) 2020-09-20 22:47:48 +02:00
Andreas Rumpf
04cecdf9c2 async: removed the 'unown' references, async never worked with --newruntime anyway and --newruntime is dead (#15374) 2020-09-20 18:01:07 +02:00
Araq
cdac67376c arc: added tmarshal.nim test case 2020-09-20 10:43:57 +02:00
Araq
33be7c6f5e arc: =deepcopy fixes 2020-09-20 10:43:57 +02:00
Andreas Rumpf
ebb632ccba fixes #15369 (#15371) 2020-09-20 01:07:13 +02:00
Andreas Rumpf
a15d77df7e ORC/ARC async progress (#15370)
* ARC/ORC: fixes memory leak for empty seqs that have a non-zero capacity

* async: minor refactorings

* it helps to finish a refactoring
2020-09-20 00:27:32 +02:00
Andreas Rumpf
cbdda631db base64: fixes the error message for an invalid base64 input character [backport:1.2] 2020-09-20 00:05:41 +02:00
Andreas Rumpf
9a34009f00 ORC and stdlib optimizations (#15362) 2020-09-19 00:27:43 +02:00
Timothee Cour
8ae4a774b7 doc fix typo in lib/pure/httpclient.nim (#15364) 2020-09-19 00:20:41 +02:00
Euan
ae1f5c1559 Use sysctl on NetBSD to get exe name (#15359) 2020-09-18 22:26:53 +02:00
yatsen1
341cd844b2 fix coro proc crash for stack problem when run long enough than a GC cycle (#7612) (#11410)
Co-authored-by: drswinghead <drswinghead@gmail.com>
Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-09-18 17:17:09 +02:00
Andreas Rumpf
d19316bbb9 more ORC bugfixes (#15355)
* introduced --define:nimArcIds

* ORC: bugfixes
2020-09-18 11:55:58 +02:00
narimiran
59b7857167 bump NimVersion to 1.3.7 2020-09-18 11:50:15 +02:00
Andreas Rumpf
2671efab78 async: minor refactorings (#15354) 2020-09-18 11:22:34 +02:00
jcosborn
e56d50d747 fix infinite recursion in typeRel (#15241)
* fix generic constraints

Co-authored-by: James Osborn <osborn@Jamess-MacBook-Pro.local>
2020-09-18 11:21:37 +02:00
flywind
c57023f324 string is not nil anymore (#15352) 2020-09-18 10:02:31 +02:00
Miran
cbd78ec1f6 close #6071, remove the mentions of deprecated docSeeSrcUrl (#15350) 2020-09-17 19:55:18 +02:00
Andreas Rumpf
bc9967f05a Revert "Introduce explicit copy (#15330)" (#15346)
This reverts commit a3e9cc5234.
2020-09-16 23:24:17 +02:00
cooldome
d938c6411e fix #15326 (#15341) 2020-09-16 21:37:23 +02:00
Juan Carlos
913ffbb92d Add documentation for Testament (#15344) 2020-09-16 21:31:35 +02:00
Yuriy Glukhov
28a64869f0 Fixed undeclared nimIdentNormalize compilation error in parseEnum (#15343) 2020-09-16 19:41:57 +02:00
Andreas Rumpf
8b66412a8b fixes #9754 [backport] (#15342) 2020-09-16 19:41:14 +02:00
cooldome
341be0b61c proc params as syms (#15332)
* proc params are now syms

* Fix typesrenderer

* Add testcase for disrupteks issue

* fix test

* Trigger build

* Trigger build

* Trigger build

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-09-16 17:25:24 +01:00
cooldome
a3e9cc5234 Introduce explicit copy (#15330) 2020-09-16 17:26:45 +02:00
Andreas Rumpf
ae4ede6b00 fixes #15325 (#15340) 2020-09-16 17:26:13 +02:00
flywind
de7f2372be docs minor and #15335 (#15337) 2020-09-16 14:58:50 +02:00
Andreas Rumpf
fd31e8ff6f allow old styled RTTI for arc/orc (#15331) 2020-09-16 14:57:01 +02:00
flywind
0aaf4e2dfa Methods docs improvement (#15338)
* docs improvement

* minor
2020-09-16 14:51:01 +02:00
Andreas Rumpf
bc179ccc3f fixes #15076 (#15329) 2020-09-15 12:40:23 +02:00
Juan Carlos
073bea6606 Remove Deprecated {.this:self.} from Documentation so people dont use it anymore (#15328) 2020-09-15 11:59:33 +02:00
Andreas Rumpf
c38487aa22 fixes a critical ORC bug, refs #15076 (#15323) 2020-09-14 12:50:23 +02:00
flywind
e111b610ca test cookies with comma for #15319 (#15322)
* test cookies with comma for #15319

* space
2020-09-14 12:20:42 +02:00
flywind
366216da64 fix cookie with comma (#15319) 2020-09-14 09:00:29 +02:00
Juan Carlos
a667475aaf dom.Navigator add missing attributes (#15310)
* Add missing attributes and methods to dom.Navigator

* Add missing attributes and methods to dom.Navigator

* Add missing attributes and methods to dom.Navigator
2020-09-14 08:58:21 +02:00
Jaremy Creechley
6c49767a6c Fixing issue #15302 -- lwip doesn't support signals (#15303)
* Fixing issue #15302 -- lwip doesn't support signals

* Adding test to catch issue #15302 -- lwip/freertos net library
don't try to build / run on windows, it'll compile only but not run

Fixing issue #15302 -- reworking test to compile on other platforms
2020-09-14 08:57:49 +02:00
Andreas Rumpf
1df5cfba52 fixes #15147 (#15315) 2020-09-12 23:11:38 +02:00
Clyybber
60ad95f799 Add testcase for invalid if statement (#15313) 2020-09-12 14:28:19 +02:00
Clyybber
1881fc5812 Fix #15305 (#15311)
* Fix #15305

* Fix test
2020-09-12 12:39:46 +01:00
flywind
a41b243fea remove annoying messages when creating orderedTables (#15309)
* nativesockets docs minor [backport: 1.2]

* remove annoying messages
2020-09-12 10:34:11 +02:00
narimiran
5f08d39398 fix broken links in the documentation 2020-09-12 09:22:14 +02:00
genotrance
f1f694dccb Bump nimble (#15304) 2020-09-11 11:57:54 -05:00
Araq
9e4920c068 fixes #15021 2020-09-11 14:21:09 +02:00
Juan Carlos
c4e03b540e Fix #15183 (#15300) 2020-09-11 08:57:57 +02:00
Andreas Rumpf
0c41ac792b fixes #15122 (#15301) 2020-09-11 01:50:42 +02:00
Miran
6a621b35e7 fix warnings for deprecated low and high (#15291) 2020-09-11 01:04:07 +02:00
hlaaftana
625edf6a98 Add /lib/fusion to gitignore (#15295) 2020-09-11 00:43:10 +02:00
Juan Carlos
b03d221d0b Improve prelude so it does not hijacks documentation when used (#15299) 2020-09-11 00:25:09 +02:00
Andreas Rumpf
9a110047cb testament improvement: allow inline error messages inside test cases (#15294)
* testament support for inline error messages
* adapt teffects1.nim test to show the potential
2020-09-10 16:30:20 +02:00
cooldome
61c85e034d Fix #15286 (#15292)
* fix #15286

* fix spacing
2020-09-10 12:40:39 +02:00
Andreas Rumpf
3f00a738db fixes #15280 [backport:1.2] (#15281)
* fixes #15280 [backport:1.2]

* make tests green again

* adapt tests
2020-09-09 14:20:10 +02:00
Andreas Rumpf
217675cf84 borrow checking refinements (#15290)
* added basic borrowing test
2020-09-09 14:19:22 +02:00
Ivan Bobev
ccd77b42af Add some enhancements to jsonutils.nim (#15133)
* Add some enhancements to `jsonutils.nim`

* Use `jsonutils.nim` hookable API to add a possibility to deserialize
  JSON arrays directly to `HashSet` and `OrderedSet` types and
  respectively to serialize those types to JSON arrays.

* Also add a possibility to deserialize JSON `null` objects to Nim
  option objects and respectively to serialize Nim option object to JSON
  object if some or to JSON `null` object if none.

* Move serialization/deserialization functionality for `Table` and
  `OrderedTable` types from `jsonutils.nim` to `tables.nim` via the
  hookable API.

* Add object `jsonutils.Joptions` and parameter from its type to
  `jsonutils.fromJson` procedure to control whether to allow
  deserializing JSON objects to Nim objects when the JSON has some
  extra or missing keys.

* Add unit tests for the added functionalities to `tjsonutils.nim`.

* improve fromJsonFields

* Add changelog entry for the jsonutils enhancements

* Add TODO in `jsonutils.nim`

* Added an entry to "Future directions" section in `jsonutils.nim` as
  suggestion for future support of serialization and de-serialization of
  nested variant objects.

* Added currently disabled test case in `tjsonutils.nim` for testing
  serialization and de-serialization of nested variant objects.

* Move JSON hooks to `jsonutils.nim`

Move `fromJsonHook` and `toJsonHook` procedures for different types to
`jsonutils.nim` module to avoid a dependency of collections modules to
the `json.nim` module.

The hooks are removed from the following modules:

  * `tables.nim`

  * `sets.nim`

  * `options.nim`

  * `strtabs.nim`

* Add some tests about `StringTableRef`

Add tests for `StringTableRef`'s `fromJsonHook` and `toJsonHook` to
`tjsonutils.nim`.

* Disable a warning in `jsonutils.nim`

Mark `fun` template in `jsonutils` module with `{.used.}` pragma in
order to disable `[XDeclaredButNotUsed]` hint. The template is actually
used by the `initCaseObject` macro in the same module.

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
2020-09-09 14:18:59 +02:00
narimiran
8a2cd7b24b [ci skip] fix typo in the manual 2020-09-09 12:59:14 +02:00
flywind
8c82144ba5 add getprotobyname (#15273)
* add getprotobyname

* tests, docs, changelog

* add since
2020-09-09 12:47:22 +02:00
Miran
7d4f0df107 deprecate high(value) and low(value) (#15283) 2020-09-09 12:43:04 +02:00
Clyybber
f3552b86c1 Better semiStmtList parsing (#15123)
* Better semiStmtList parsing
* Add examples from forums and wiki
* Move parseIfExpr near parseIfOrWhen
* Update grammar
2020-09-09 07:36:31 +02:00
Andreas Rumpf
10988d4840 borrow checking (#15282)
* refactoring: move procs to typeallowed.nim
* frontend preparations for first class openArray support
* prepare the code generator for first class openArray
* code generation for first class openArray; WIP
* code generation for open arrays, progress
* added isViewType proc
* preparations for borrow checking
* added borrow checking to the front end
2020-09-09 07:32:03 +02:00
Miran
c49b88163c "for-loop macros" are no longer an experimental feature (#15288) 2020-09-08 14:25:25 +02:00
flywind
a81610230d nativesockets docs minor [backport: 1.2] (#15285) 2020-09-08 11:27:43 +02:00
Scott Wadden
098a8a7c52 nimeval errorHook support (#15255) 2020-09-07 20:05:07 +02:00
Andy Davidoff
0b74d26d0c don't raise index defects on malformed ast (#15278)
* don't raise index defects on malformed ast

* style
2020-09-07 20:04:07 +02:00
flywind
e08b802d79 more Protocol supports in windows (#15274) [backport:1.2] 2020-09-07 12:10:20 +02:00
Andreas Rumpf
2f6d04fd5d strict funcs: use control flow information for a more precise analysis (#15271)
* strict funcs: use control flow information for a more precise analysis

* cursor inference uses control flow information
2020-09-06 22:01:39 +02:00
genotrance
072c655653 Bump nimble (#15272) 2020-09-06 07:05:35 +02:00
shirleyquirk
57f98dae9a Fix c_malloc inside syslocks.nim to take size_t (#15268) [backport]
* update c_malloc's to csize_t
2020-09-05 23:00:59 +02:00
Clyybber
35ff17410f Expand hoisted default params in sem (#15270)
* Expand hoisted default params in sem
Introduce ast.newTree{I,IT}
Add test for default params in procs

* Cleanup

* Simplify hoist transformation and expand test
2020-09-05 22:01:47 +02:00
IDF
70d6238756 Add SSL_CTX_set_session_id_context (#15233)
* Added SSL_CTX_set_session_id_context()

* Added basic nimdoc

* Raise an error if sessionIdContext is longer than the maximum length

* Update nimdocs
2020-09-04 22:27:51 +01:00
Bung
c16ee37a71 Fix #15219 SQL escape in db_mysql is not enough (#15234) 2020-09-04 11:04:27 +02:00
cooldome
77df02313d fix #15238 (#15262)
* fix_15238

* fix test
2020-09-04 10:26:14 +02:00
Miran
4fb17bc03b fix #15257, toHex couldn't handle large uint64 (#15261) [backport:1.2] 2020-09-04 09:23:27 +02:00
Andreas Rumpf
48f2997221 fixes system.add for strict funcs (#15259)
* fixes system.add for strict funcs

* fixes #15248
2020-09-03 12:59:34 +02:00
Silvio
3172ca5475 replace / with _ in trId (#15256)
Fixes jquery error when clicking to collapse/expand a panel
2020-09-02 20:53:02 +02:00
PMunch
244760197c Fix sets for architectures with default integers smaller than 32 bits (#15258) [backport] 2020-09-02 10:07:08 +02:00
Andreas Rumpf
ff13f8cc3c fixes #15210 [backport:1.2] (#15237)
* fixes #15210 [backport:1.2]

* use patched version of bigints library
2020-08-31 14:46:23 +02:00
Jaremy Creechley
a76ae8f795 Changes for FreeRTOS/LwIP Port for the ESP32 (ESP-IDF) (#15250)
* Changes for FreeRTOS/LwIP Port for the ESP32 (ESP-IDF)

Adding FreeRTOS/LwIP to compiler:

* adding freertos option
* dyncalls for freertos
* add freertos to posix os list
* adding lwip option

Setting up networking FreeRTOS/LwIP Port:

* setting up lwip network for freertos
* fixing posix / networking for freertos
* disable setInheritable for freerots
* using lwip for net control items

* Fix builds by ignoring lib/posix/posix_freertos_consts.nim similar to lib/posix/posix_other_consts.nim
2020-08-31 11:48:54 +02:00
Andy Davidoff
b5424b826e template hygiene (#15240) 2020-08-29 08:06:11 -04:00
Clyybber
13e659cfec Big compiler Cleanup (#14777) 2020-08-28 22:18:09 +02:00
cooldome
f8c48fc186 fix #15035 (#15236) 2020-08-28 17:57:52 +02:00
Clyybber
fb58066b61 Fix #5691 (#15158)
* Fix #5691
* Cleanup and thoughts
* Use scope approach
* Seperate defined/declared/declaredInScope magics
* Fix declaredInScope
* Update spec accordingly
2020-08-27 15:50:59 +02:00
jcosborn
d11933ad99 fix some issues overloading with generics and inheritance (#15211)
* fix some issues overloading with generics and inheritance

* fix passing procs with subtype matches
2020-08-27 12:56:38 +02:00
Andreas Rumpf
ccccd30cf6 fixes #15221 (#15230) 2020-08-27 11:25:20 +02:00
Scott Wadden
a9a9860b0b Raise KeyError if passed an invalid row entry (#15227) 2020-08-26 20:00:54 +02:00
Juan Carlos
d85015e922 Remove unroll pragma from stdlib (#14706) 2020-08-26 16:51:41 +02:00
Araq
40969296e9 fixes #15207 [backport:1.2] 2020-08-26 15:27:15 +02:00
Araq
71025b8a8f deleted dead code, writetracking.nim was replaced by varpartitions.nim 2020-08-26 15:27:15 +02:00
Miran
5163fe7d87 remove deprecation from math.round (#15224) 2020-08-25 15:59:42 +02:00
Bung
7cee63bba3 avoid #8231, bitwise move to mul,div (#15070)
* avoid #8231, bitwise move to mul,div

* add test for #8231

* fix bitwise move when div result is float

* bitwise move depends on typ.size
2020-08-25 09:58:32 +02:00
Miran
15ff89cec1 [backport] fix #15064, strscans.scanf edge case for '$+' (#15223) 2020-08-25 09:57:15 +02:00
narimiran
5651a2f711 PRs with no activity in last year are marked as stale 2020-08-24 13:44:19 +02:00
Jon
8321617a78 fix in doc: incomplete output (#15222) [ci skip] 2020-08-24 08:33:51 +02:00
Mamy Ratsimbazafy
07d82b5cc4 Use more lent in options (#15208) 2020-08-24 08:05:17 +02:00
alaviss
575697e1f4 doc/nimdoc.css: align field names to the right (#15217) 2020-08-23 09:48:37 +02:00
wltsmrz
9bae1ed205 Unsigned iovlen (#15216) 2020-08-22 23:14:50 +02:00
John Dupuy
66eba3388a Added more SSL documentation to net module. (#15206)
* Added more SSL documentation to `net` module.

* Changed two of the net.nim doc refs to links.

* Update lib/pure/net.nim doc wording.

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

* Update lib/pure/net.nim - added space to doc URI

Co-authored-by: alaviss <leorize+oss@disroot.org>

* Fixed another doc URI in net module.

* For net module doc added warning to connect procedure.

* Update net.nim

Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>
Co-authored-by: alaviss <leorize+oss@disroot.org>
2020-08-22 11:00:38 +01:00
Elijah Shaw-Rutschman
8a004e2fc0 Add test coverage for atomics (#15193)
* Add test coverage for atomics

Signed-off-by: Elijah Shaw-Rutschman <elijahr@gmail.com>

* Fix compareExchange bugs for non-trivial objects

Bugs fixed:

1. compareExchange would not set the desired value in the success case.
2. compareExchange would not set var expected to the found value in the failure case.
3. withLock would spin forever running the unit tests. try..body..finally prevents this. Not sure why this makes a difference, since an exception wasn’t being raised, but clearing the guard in a finally block seems correct anyways.

Signed-off-by: Elijah Shaw-Rutschman <elijahr@gmail.com>
2020-08-18 18:02:10 +02:00
Andreas Rumpf
ddff13f01b better strict funcs, WIP (#15199)
* better strict funcs, WIP

* progress
2020-08-18 12:45:22 +02:00
jcosborn
e194cb41a4 fix overloading issue with generic invocation (#15135)
* fix overloading issue with generic alias

* add test for inheritance depth
2020-08-18 08:23:19 +02:00
alaviss
e9df8ebcfd gc_regions: cleanup & fixes for deallocation (#11920)
* gc_regions: withRegion nows return the modified MemRegion

* gc_regions: make withScratchRegion dealloc correctly

* tests/gc: add tregionleak test

This test checks if memory within regions are freed properly.
2020-08-17 20:20:48 +02:00
Andreas Rumpf
6feb3900b1 fixes #15177, the error message is now what it should have been (#15195) 2020-08-17 14:32:52 +02:00
Bung
cd28fe2ef7 add openssl missing procs (#15180) 2020-08-17 10:54:34 +02:00
narimiran
39906c52c4 stale bot is now active only for pull requests 2020-08-17 09:11:33 +02:00
Juan Carlos
c9fdad2c21 db_postgres document how to use it with unix socket (#15187) 2020-08-17 08:39:58 +02:00
slangmgh
ba042af9cc std/with support field assign (#14484)
* std/with support filed assign

* add changelog

* add support x.dup.with

* add example

* revert support x.dup.with; add example

* update changelog; fix assignment in parameter

* Update changelog.md

* add example for assignment in parameter

* Remove colon style assign

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-08-15 01:33:21 +02:00
alaviss
957bf15a08 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.
2020-08-12 08:04:54 +02:00
Cléber Zavadniak
ce2da87eca Fix typo on CoroutineRef* doc (#15179)
Just a small fix for a typo ("for for").
2020-08-12 04:46:16 +02:00
Clyybber
2cea52ee7e Allow pragmas on parameters (#15178) 2020-08-11 22:28:49 +02:00
Andreas Rumpf
813f16a2a3 Fix #8473 (#15169)
* Make explicit {.nimcall.} a seperate calling convention

* Add testcase for #5688

* Fix bootstrapping

* Remove little lies :)

* Use typeflag instead
2020-08-11 14:50:46 +02:00
Silvio
963db9e7da docs: dlimport -> dynlib (#15175) 2020-08-11 14:49:57 +02:00
Ico Doornekamp
2260ede247 Added array type definition to manual (#15173)
Co-authored-by: Ico Doornekamp <git@zevv.nl>
2020-08-10 14:01:47 +02:00
Clyybber
b022576ce9 Use typeflag instead 2020-08-10 12:57:32 +02:00
haxscramper
e5dbdc1d37 [FIX] strtabs interpolation in nimscript (#15172)
* [FIX] strtabs interpolation in nimscript

* [TEST] Use `static` in strtabs test
2020-08-09 14:12:53 +02:00
Andreas Rumpf
2a8bf470af fixes #15101 [backport] (#15171) 2020-08-08 23:08:34 +02:00
Clyybber
26a867c83c Remove little lies :) 2020-08-08 13:22:53 +02:00
Clyybber
2a8d010742 Fix bootstrapping 2020-08-08 12:50:06 +02:00
Clyybber
78b2012a92 Add testcase for #5688 2020-08-08 12:45:07 +02:00
Clyybber
38068f9778 Make explicit {.nimcall.} a seperate calling convention 2020-08-08 12:36:20 +02:00
c-blake
0bc8dd0b00 Add iterator inotify_events which is *almost always* needed logic for (#15152)
client code since Linux `inotify` is much like Linux `getdents64`.

Expanding on "almost always"..The only time that this `iterator` logic
is ***not*** needed on the output of a `read` from inotify fd's is when
one passes a length to `read` *guaranteed* to only pass one event struct
in the buffer.  That unusual circumstance requires (at least!) knowing
the length of the delivered filename before an event occurs, and the
filename itself is optional for some event types.

It is *far* more common to not know lengths in advance which means one
passes a buffer big enough for at least one maximum length directory
entry (256 bytes) which is then also big enough for *many* "typical"
length entries and therefore many events.  In such more common scenarios
this iterator logic is definitely needed.

Further, not using this logic, yet treating the return from read as "the
whole answer" can test ok on "thin" event streams (e.g. 1 event per ms),
hiding a latent bug of processing only the first event.
2020-08-08 07:26:20 +02:00
flywind
eee3b189ff fix #15148 (#15149)
* fix #15148

Co-authored-by: alaviss <leorize+oss@disroot.org>
2020-08-08 07:24:54 +02:00
ee7
6f482ab934 deques.nim: Refactor the toDeque functionality (#15166)
This commit polishes the new proc introduced by d9ed816b10.

Changes:
- Rename to `toDeque` for more consistency with well-known procs like
  `toHashSet` and `toTable`.
- Rename the `openArray` parameter. The name `arr` was potentially less
  clear given that the proc can be used with a seq (or string).
- Add a `since` annotation.
- Reword the doc comment, and clarify that ordering is preserved.
- Add runnableExamples.
- Add "see also" cross linking between `initDeque` and `toDeque`.
- Remove duplicate `nextPowerOfTwo`. The `initImpl` template already
  includes it.
- Implement the proc using the `items` iterator, rather than indexing.
  This matches the implementation of `sets.toHashSet` and
  `tables.toTable`.
- Add a test within `when isMainModule`.
- Add a changelog entry.
2020-08-07 22:54:34 +02:00
cooldome
a528382e05 fix sqlgetdata regression in odbc (#15161)
* fix sqlgetdata import

* fix db_odbc

* more fixes

* fix style
2020-08-07 22:37:54 +02:00
archnim
d9ed816b10 Added the ability to initialize a deque with an openArray (#15138)
* Add ability to initialize a deque with a sequence

Example:
var dq = initDeque[char](@['a', 'b', 'c'])

* Update deques.nim

* Optimized deque initialization

* Sequence replaced by open array in deque initialization
2020-08-05 12:41:42 -04:00
cooldome
ef6358f0b0 implement (#15153) 2020-08-04 19:22:35 +02:00
narimiran
eb3ba0ae5f limit stalebot a bit more 2020-08-04 13:00:09 +02:00
Andreas Rumpf
64aec6eb85 fixes a collect() bug reported on the forum (#15156) [backport:1.2] 2020-08-04 12:45:15 +02:00
flywind
2d494f42f3 minor improvement (#15155) 2020-08-04 11:29:57 +02:00
narimiran
836660a297 put stale limit at 3 years
It needs to be slowly brought down to limit the notifications
and prevent excessive spamming.
2020-08-04 11:00:04 +02:00
narimiran
e4710f893e stalebot: don't send messages to keep spam down 2020-08-04 10:47:16 +02:00
narimiran
9b08c7b375 add stale bot 2020-08-04 09:03:20 +02:00
Andreas Rumpf
d6161e7e9e fixes #15129 [backport:1.2] (#15144) 2020-08-01 22:03:15 +02:00
sschwarzer
98eb8410f2 Remove noSideEffect pragmas (#15143)
These don't seem to make sense for the purpose of the procs and lead
to errors when the `--experimental:strictFuncs` feature is enabled.

See also https://github.com/nim-lang/Nim/issues/15142
2020-08-01 22:00:25 +02:00
alaviss
c619cedd7c net: allow close() to ignore SSL failures due to disconnections (#15120)
* net: allow close() to ignore SSL failures due to disconnections

Comes with this PR is also a SIGPIPE handling contraption.

* net: don't do selectSigpipe() on macOS

macOS sockets have SO_NOSIGPIPE set, so an EPIPE doesn't necessary mean
that a SIGPIPE happened.

* net: fix alreadyBlocked logic

* net: WSAESHUTDOWN is also a disconnection error
2020-08-01 21:27:55 +02:00
flywind
3ce32a7e40 export asyncdispatch handles (#15140)
* improve epoll docs

* export handles

* add comments and changelog
2020-08-01 21:27:21 +02:00
Andreas Rumpf
8e3f51f06c fixes #15130 (#15141)
* fixes #15130

* you really have to copy from cursors
2020-08-01 18:04:04 +02:00
Andreas Rumpf
9ff2c50155 fixes #15122 [backport:1.2] (#15139) 2020-08-01 13:16:50 +02:00
alaviss
e192e07bf0 ci_docs: build fusion docs (#15127) 2020-08-01 11:33:19 +02:00
flywind
a7736b6b43 improve epoll docs (#15137) 2020-08-01 11:30:51 +02:00
Andreas Rumpf
4ab6887a67 fixes #15111 (#15136) 2020-08-01 07:39:00 +02:00
Andreas Rumpf
6b88cd0d42 Revert "Small typo (#15132)" (#15134)
This reverts commit 4bf8d38248.
2020-07-31 20:27:58 +02:00
Oliver Daniel
4bf8d38248 Small typo (#15132)
The expected output necessarily cannot match the formatted string.
2020-07-31 16:35:50 +02:00
Andreas Rumpf
d23ae49535 fixes #15071 [backport] (#15131) 2020-07-31 12:13:33 +02:00
genotrance
f1971243d3 Bump nimble (#15126) 2020-07-30 13:13:34 -05:00
Andreas Rumpf
355b275175 fixes #15112 (#15124) 2020-07-30 19:19:59 +02:00
Andreas Rumpf
d130175342 cursor and mutation tracking fixes (#15113)
* fixes #15110
* fixes #15096

* prepare varpartitions for cursor inference
* new cursor inference begins to work
* make tests green
2020-07-30 17:32:48 +02:00
jcosborn
32c6146200 fix overloading case with generic alias (#15116)
* fix overloading case with generic alias

* revert reorganization of tests
2020-07-30 15:34:11 +02:00
treeform
604f7461d7 Fix tables.CountTable largest and smallest (#15115)
It needs to have len defined first because of the assert .len > 0.  I just moved it up a bit to make them work.
2020-07-29 23:49:51 -04:00
alaviss
20315637aa asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred (#15066)
* asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred

Per TLS standard and SSL_shutdown(3ssl). This should prevent errors
coming from a close() after a bad event (ie. the other end of the pipe
is closed before shutdown can be negotiated).

Ref #9867

* tssl: try sending until an error occur

* tssl: cleanup

* tssl: actually run the test

I forgot to make the test run :P

* tssl: run the test on ARC, maybe then it'll be happy

* tssl: turns off ARC, switch tlsEmulation on for freebsd

* tssl: document why tlsEmulation is employed

* net: move SafeDisconn handling logic to socketError
2020-07-30 00:35:02 +02:00
genotrance
0788a7f970 Bump nimble (#15114) 2020-07-29 15:42:08 -05:00
flywind
c645dba038 fixes #14139 (#15107)
* fix #14139
* Update lib/pure/collections/heapqueue.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-07-29 16:18:27 +02:00
Clyybber
2629d619a1 Fix forward declaration issues in template/macro context (#15091)
* Fix forward declaration issues in template/macro context

* Correct forward declaration resolving for overloads

* Remove old dead code

* WIP consistent gensym ids

* Minimize diff

* Remove obsoleted hack

* Add templInstCounter to give unique IDs to template instantiations

* Remove obsoleted code

* Eh, init in myOpen, not myProcess...

* Remove optNimV019

* Add testcase for #13484
2020-07-29 16:17:20 +02:00
c-blake
196e747df1 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.)
2020-07-29 11:19:02 +02:00
Andreas Rumpf
a3a87cdb29 fixes #14616 [backport:1.2] (#15109) 2020-07-29 11:11:58 +02:00
c-blake
b2a1944587 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.
2020-07-28 23:48:50 +02:00
Andreas Rumpf
86c9b78339 disable sink inference, only enable it for the stdlib. Reason: better source code compatibility (#15105) 2020-07-28 19:18:46 +02:00
Euan
e4e4931432 Change clibdir and cincludes for NetBSD (#15102) 2020-07-28 12:01:25 -04:00
Bung
e2b1491905 Fix #11352 strutil.insertSep() fails on negative numbers (#15087)
* fix #11352 strutil.insertSep handle negtive number

* test for #11352

* optimize

* not parts string var

* Update lib/pure/strutils.nim

Thanks!

Co-authored-by: alaviss <leorize+oss@disroot.org>

* need to be countdown

Co-authored-by: alaviss <leorize+oss@disroot.org>
2020-07-28 11:47:22 +02:00
Miran
39487f9728 deprecate tables.allValues; continuation of #15047 (#15092) 2020-07-28 11:40:56 +02:00
Andreas Rumpf
be78b35bb8 cleanup ARC documentation (#15100) 2020-07-28 11:34:44 +02:00
narimiran
a2f330569c yet another fusion fix 2020-07-28 10:57:24 +02:00
narimiran
75083979f9 another bump 2020-07-28 09:27:00 +02:00
narimiran
d6a0c35330 bump FusionStableCommit to the latest commit 2020-07-28 08:51:10 +02:00
Ray Imber
d60fae576f Improvements to Windows install instructions (#15099) 2020-07-28 02:04:04 -04:00
Andreas Rumpf
e6f0d4a5a5 fixes #15076 (#15095) 2020-07-27 23:27:20 +02:00
Timothee Cour
377f716766 fix #14698 nkRecWhen caused internalAssert in semConstructFields when generic type not mentioned in fields (#14709)
* fix #14698 nkRecWhen caused internalAssert in semConstructFields when generic type not mentioned in fields

* address comment

* Update compiler/semtypinst.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-07-27 22:32:21 +02:00
Bung
cac09a43ae fix #11354 jsgen not carefully handle genAddr with nkHiddenAddr,nkStm… (#15078)
* fix #11354 jsgen not carefully handle genAddr with nkHiddenAddr,nkStmtListExpr; genAsgn with lvalue tyVar and rvalue tyPtr

* correct logic

* add test for #11354

* handle nkHiddenAddr when n.len == 1

* Update compiler/jsgen.nim

* Update compiler/jsgen.nim

* Apply suggestions from code review

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-07-27 21:13:49 +02:00
Bung
191c388792 fixes #14189 (#15080) [backport] 2020-07-27 14:06:54 +02:00
Araq
947ecd1257 more renamings 2020-07-27 13:07:09 +02:00
Araq
46bd6787b8 code cleanup 2020-07-27 13:07:09 +02:00
Araq
318f0992ea fixes a closure iterator memory leaks, progress on #15076 2020-07-27 13:07:09 +02:00
Danil Yarantsev
4c43915b59 Add test-cases for #12576 and #12523 (#15085)
* Add a test-case for #12576

* Add a test-case for #12523
2020-07-27 13:01:50 +02:00
alaviss
c292c57e48 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.
2020-07-27 10:38:20 +02:00
Jjp137
a62bc55955 parsecsv: fix '\0' being displayed as '0' in docs (#15086) [backport] 2020-07-27 08:17:23 +02:00
Araq
a0049d1fb0 compiler: minor code cleanups 2020-07-27 08:05:52 +02:00
genotrance
c229df95a4 Bump nimble (#15077) 2020-07-26 08:44:14 +02:00
Andreas Rumpf
aae998feff fixes #15038 [backport:1.2] 2020-07-26 01:16:06 +02:00
Andreas Rumpf
624762cfb7 fixes #15052 2020-07-26 01:16:06 +02:00
Miran
5c4e2bf68e fix nightlies: smaller log files (#15074)
Hopefully this will fix
"The job exceeded the maximum log length, and has been terminated."
2020-07-25 22:56:37 +02:00
alaviss
33c2d7bfc4 koch: bundle nim-lang/fusion with Nim (#15061)
Initial work on bundling nim-lang/fusion as part of the Nim distribution.
2020-07-25 22:52:18 +02:00
Danil Yarantsev
080bed8b6b Add a test-case for #12990 (#15072)
* closes #12990
* Add a test-case for #12990
2020-07-25 20:35:20 +02:00
Andreas Rumpf
2aca748ddd strict func: much better error messages (#15068)
* strict func: much better error messages
* documented the 'strict funcs' mode
2020-07-25 19:36:53 +02:00
Andreas Rumpf
7ca32c86bb writing to a location counts as "side effect"; implements https://github.com/nim-lang/RFCs/issues/234 (#15030) 2020-07-25 15:14:28 +02:00
Miran
1330597f6d deprecate tables.add (#15047) 2020-07-25 09:53:47 +02:00
Bung
2dddf32726 fix #14684 (#15059) 2020-07-25 09:52:29 +02:00
Bung
9746868832 fix #14534 (#15060) [backport] 2020-07-25 09:51:59 +02:00
genotrance
8211d38569 Bump nimble commit (#15053) 2020-07-25 01:16:25 -05:00
jcosborn
add003a074 fix assignment to converted concept type (#15051)
* fix assignment to converted concept type

* check for resolved concepts

* add extra test
2020-07-24 21:19:11 +02:00
Miran
4b93c61f0d jsre: try to fix nightlies (#15057) 2020-07-24 21:15:20 +02:00
Araq
12a9fe017e fixes #15056 [backport] 2020-07-24 17:49:25 +02:00
Andreas Rumpf
18a70a7563 fixes #15036 2020-07-23 20:27:17 +02:00
Andreas Rumpf
c90c53e8bb fixes #15044 [backport:1.2] 2020-07-23 20:27:17 +02:00
Miran
14d16c2174 json.nim: smaller init size (#15048)
There was a recent `rightSize` change in tables.nim, so the existing
value (4) was creating too large tables.
2020-07-23 15:42:12 +02:00
Andreas Rumpf
925dd92e07 enforce browsers.nim only handles URLs [backport] (#15045) 2020-07-23 11:03:39 +02:00
Miran
ec65bfae3a Change testing commands for some packages (#15041) 2020-07-22 14:57:40 +02:00
Andreas Rumpf
d84894de2e fixes #15026 [backport] (#15040)
no test case since only a special case was affected and the special case got removed
2020-07-22 13:02:03 +02:00
Hugo Granström
32ac1b7c9d fix #15033 (#15034) 2020-07-22 10:30:46 +02:00
Danil Yarantsev
f25454d5c6 Add a testcase for #14480. Fixes #14480 (#15037) 2020-07-22 09:52:38 +02:00
Mildred Ki'Lya
503c5e0520 smtp: Fix STARTTLS, request HELO once TLS is established (#15032) 2020-07-22 00:30:33 -04:00
Andreas Rumpf
911e39351e ARC: optimize the code better when --panics:off (#15031) 2020-07-21 23:23:33 +02:00
Miran
5fafa2fd5c fix several newline problems (#15028) [backend]
* prevent newlines where they shouldn't be
* 'contentLength' shouldn't be negative
2020-07-21 22:49:08 +02:00
genotrance
450a3e3179 Fix #2408 - add -d:globalSymbols (#14904) 2020-07-21 19:14:36 +02:00
Bung
64d629c617 Shadow Dom apis (#14979)
* shadow dom api

* fix typos

* host to Element type

* fix code style

* move elementsFromPoint to dom_extensions.nim
2020-07-21 19:11:12 +02:00
Andreas Rumpf
c8a72e0748 Merge pull request #15027 from nim-lang/araq-cursor-fix
cursor inference bugfix
2020-07-21 07:33:37 +02:00
Andreas Rumpf
3a4e4cec4d cursor inference bugfix 2020-07-20 18:37:14 +02:00
Andreas Rumpf
80d3ef9952 hotfix: firstOrd/lastOrd for 'tyLent' as it shows up in strange places, as usual 2020-07-20 17:44:35 +02:00
Andreas Rumpf
70acba7f0d readLine: Unicode support for Windows console (#14782)
* readLine: Unicode support for Windows console

When input is read from the Windows console, input encoding is UTF16. This is translated internally to UTF8.

* readLine: Remove recursive imports

* readLine: Fix issues with --gc:arc

**--gc:arc** defines **nimv2**. This changes the definition of **WideCStringObj**.
Also an empty string should be returned in case of EOF.
2020-07-20 14:39:27 +02:00
Andreas Rumpf
49d4b50fe5 fixes #14194 (#15023) 2020-07-20 14:28:00 +02:00
alaviss
9a76398ec6 koch: use in-tree Nim to run test if possible (#15018)
Fixes #15013
2020-07-20 08:02:48 +02:00
Andreas Rumpf
71dd5f85b9 'isolate' builtin; refs https://github.com/nim-lang/RFCs/issues/244 (#15011) 2020-07-20 07:50:19 +02:00
alaviss
bb1adf6a70 io: fix SetHandleInformation signature to match Windows' (#15017)
* io: fix SetHandleInformation signature to match Windows'

Fixes #14980

* rename Handle -> IoHandle because system.nim is a mess
2020-07-20 00:17:33 -04:00
narimiran
b16284633e enable 'nimterop' test 2020-07-20 05:44:06 +02:00
Dominik Picheta
1e3a0ef1e1 [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 (!).
2020-07-19 08:41:36 +02:00
Araq
ffe7b3a9bf threadpool.nim: minor code style changes 2020-07-18 21:40:57 +02:00
Andy Davidoff
ae358a0c7a fix docs for nativesocket read/write selects (#15010)
The sockets which *cannot* be _[read from or written to]_ will also be removed from ``readfds``.
2020-07-18 16:39:41 +02:00
Timothee Cour
169ca37d26 enable,document,test getImplTransformed, very useful for understanding how nim transforms code (#14924)
* enable,document,test getImplTransformed, very useful for understanding how nim transforms code
2020-07-18 10:49:36 +02:00
Tomohiro
c983466c15 Fix #14906 (#14949)
* Fix #14906 by wrapping outputStream with PipeOutStream

* Fix compile error when ./build_all.sh

* Use PipeOutStream on posix

* Fix compile error when build_all.sh

* Use ptr UncheckedArray

* Replace copyRefObj

* Remove tmp buffer from posPeekData

* Add more tests for outputStream

* Add comments about PipeOutStream.buffer

* Fix bug in posReadLine

* Move implementation of newPipeOutStream to streamwrapper module
2020-07-18 10:41:33 +02:00
cooldome
edbbbdf1a8 fix odbc regressions (#15009) [backport]
* fix odbc regressions

* make only necessary changes
2020-07-18 10:21:09 +02:00
Andreas Rumpf
d4984e069a arc: cursors for simple for loop variables (#15008)
* arc: cursors for simple for loop variables

* merged devel
2020-07-17 15:24:36 +02:00
Bung
c2f80de1c7 fix #14822 copy test into var in matrix process, so can reset startTime before actully run (#15000)
* TTest pass by ref , so can reset startTime before actully run

* change TTest to ref type

* clone test in matrix process
2020-07-17 11:01:47 +02:00
Miran
c62513049c fix #14082, don't crash on incorrectly formatted input (#14977) [backport]
* fix #14082, don't crash on incorrectly formatted input

* address code review

* remove duplication
2020-07-17 10:59:53 +02:00
Clyybber
1355b461aa Show that a variable is cursor in --expandArc (#15002) 2020-07-17 10:56:17 +02:00
flywind
9fb7467fda fix #15006 (#15007) 2020-07-17 10:53:26 +02:00
Andreas Rumpf
6b607413e9 cursor inference: hotfix (#14999) 2020-07-16 12:07:06 +02:00
Bung
ba5604b96d fix #13621, the nim-livereload is mentioned as proposal in #8927 (#14998) 2020-07-16 11:18:59 +02:00
Clyybber
282128ab66 Fix #14994 (#14996)
* Fix #14994

* Revert misplaced "optimization"

* Typo
2020-07-15 23:33:58 +02:00
Andreas Rumpf
617c1f16d7 disable debug output 2020-07-15 23:04:18 +02:00
Andreas Rumpf
c5358b0d4b An optimizer for ARC (#14962)
* WIP: an optimizer for ARC
* do not optimize away destructors in 'finally' if unstructured control flow is involved
* optimized the optimizer
* minor code cleanup
* first steps to .cursor inference
* cursor inference: big steps to a working solution
* baby steps
* better .cursor inference
* new feature: expandArc for easy inspection of the AST after ARC transformations
* added topt_cursor test
* adapt tests
* cleanups, make tests green
* optimize common traversal patterns
* moved test case
* fixes .cursor inference so that npeg compiles once again
* cursor inference: more bugfixes

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-07-15 23:00:06 +02:00
Clyybber
813dd1b670 repr_v2 improvements (#14992)
* Support proc in arc repr

* Typo

* Improve repr for strings and chars
2020-07-15 22:04:15 +02:00
Clyybber
e057b1d839 Fix #14990 (#14991)
* Fix #14990

* Add testcase
2020-07-15 19:00:52 +02:00
Clyybber
08159733cd Fix #14985 (#14988) 2020-07-15 11:34:10 +02:00
flywind
c5f64f101b fix #13086 (#14987)
* fix #6608

* minor

* fix

* clean tests

* make testamnet happy

* again

* minor

* fix #13086
2020-07-15 03:46:17 -04:00
Clyybber
f2b041f168 Reenable a few tests 2020-07-14 19:50:42 +02:00
Clyybber
ddfb7d9877 Closes #10396 2020-07-14 19:50:42 +02:00
Clyybber
695a537c05 Closes #13253 2020-07-14 19:50:42 +02:00
Clyybber
03b0374e5c Closes #8426 2020-07-14 19:50:42 +02:00
Juan Carlos
9465b5db44 Clean up macros (#14959) 2020-07-14 16:44:56 +02:00
Clyybber
2b0e336c97 injectdestructors fixes and refactor (#14964)
* injectdestructors fixes and refactor

* Tiny cleanup

* Refactor and expand testcase

* Closes #14902 by adding testcase

* Better naming

* Fix test failures

* Misc cleanup

* Add testcase for #14968

* Better approach; expand testcases

* Optimizations and fixes

* Add testcase

* typo

* Tiny cleanup
2020-07-14 14:15:39 +02:00
Bung
f999f916f3 add missing props,procs (#14978) 2020-07-14 13:53:41 +02:00
Hendrik
9ed0dbfa6e fix index error (#14974)
Co-authored-by: Hendrik Albers <mail@hendrik.dev>
2020-07-14 13:15:22 +02:00
Timothee Cour
e07d661d16 fix #14475; unittest.require now works with nim c; require and check now works with -d:nodejs (#14676)
* fix #14475; make unittest work with -d:nodejs

* fixup

* fixup

* disable inim, delaunay which failed after unittest.require got fixed

* re-enable tests that have been fixed
2020-07-14 13:14:32 +02:00
jcosborn
ffaf4797be add full tests from #9463 (#14975) 2020-07-14 11:24:17 +02:00
flywind
086efac49b fix #6608 (#14963)
* fix #6608
2020-07-14 09:22:48 +02:00
Miran
f4f21c89e5 asyncftpclient.nim - don't assume a sufficiend line length (#14973) 2020-07-14 02:18:02 -04:00
Andreas Rumpf
6cc0061a72 optimize the new nimPrepareStrMutationV2 with inlining (#14969) 2020-07-12 16:50:56 +02:00
Alexander Wolfe
124feb2af8 nimpretty support for multiple files (#14890) 2020-07-12 16:07:31 +02:00
flywind
9ec9a31f46 Fix #12759 (#14967)
* add testcase for #5926

* fix #12759
2020-07-12 03:31:03 -04:00
Clyybber
d409694b02 :D 2020-07-11 19:17:40 +02:00
flywind
21772b6419 add testcase for #5926 (#14965) 2020-07-11 17:09:41 +02:00
Juan Carlos
6d10baa339 https://github.com/nim-lang/Nim/pull/14948#issuecomment-656498426 (#14958) 2020-07-11 06:21:59 -04:00
Clyybber
425972c4e8 Add testcase for some old fixed issues (#14960)
* Add testcase for #2703

* Add testcase for #2586

* Small fix
2020-07-10 19:21:50 +02:00
Clyybber
1850efbb6c Add testcase for #14383 (#14957) 2020-07-10 18:10:32 +02:00
Clyybber
db6ffeba8e Add testcase for #13815 (#14956) 2020-07-10 17:31:15 +02:00
Clyybber
0db32e9885 Add testcase for #12571 (#14955) 2020-07-10 17:13:37 +02:00
Clyybber
b21782a667 Add testcase for #4722 (#14954) 2020-07-10 17:02:49 +02:00
kwgchi
229a623849 Update readme.md (#14953) 2020-07-10 16:45:26 +02:00
Miran
371b416ac8 fix #14912, make --useVersion:1.0 work again (#14945)
* fix #14912, make `--useVersion:1.0` work again
* a better fix
* add test
2020-07-10 16:44:12 +02:00
Manuel Bojato
04232d92cd Fix theme switch load from local storage (#14897)
* fix theme switch load from local storage

* Fix tests

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-07-10 15:06:07 +02:00
Araq
4603197fe8 fixes a minor regression 2020-07-10 13:36:02 +02:00
Araq
112511084d fixes the tcontrolflow regression, clen idea of an escaping expression 2020-07-10 13:36:02 +02:00
Araq
b59385f22b no wasMoved() calls after destructors necessary 2020-07-10 13:36:02 +02:00
Araq
37a98c77f3 optimize sinks even when in a loop 2020-07-10 13:36:02 +02:00
Araq
78513a9204 renderer.nim: more obvious debug output 2020-07-10 13:36:02 +02:00
Clyybber
bf51cee431 Update docs and changelog 2020-07-10 13:36:02 +02:00
Clyybber
4a1128d16c Move wasMoved out of =destroy 2020-07-10 13:36:02 +02:00
Clyybber
3e52136f26 Cosmetics 2020-07-10 13:36:02 +02:00
Araq
f92d2eaa35 cleanup of PR #14833 (VM profiler) 2020-07-09 19:21:20 +02:00
Ico Doornekamp
d7ccd82eac VM profiler (#14833)
* Crude VM profiler

* Added --profileVM flag, refactoring

* fixed FileLine hash

* Use TLineInfo instead of own FileLine, updated formatting

* Refactoring, moved PStackFrame to vmdefs for cleaner data structure

* Moved vmprofiler to separate file

* Simplified TLineInfo hash, use toFileLineCol for output

* Hash

* Moved profile data into Config, dump only once at end of run

* Changed profile output header to show '#instr' instead of 'count'

* Do not accumulate instrcount for non-top frames

Co-authored-by: Ico Doornekamp <git@zevv.nl>
2020-07-09 19:18:35 +02:00
Andreas Rumpf
c38a459582 fixes #14925 (#14947) 2020-07-09 17:24:23 +02:00
flywind
64815f59b2 add testcase for #4668 (#14946)
closes #4668
closes #9463
2020-07-09 12:53:12 +02:00
flywind
40b58a0a18 fix #11009 (#14935) 2020-07-09 09:57:35 +02:00
treeform
399b2e3134 Add missing dom.nim things (#14944) 2020-07-09 09:18:27 +02:00
flywind
00528cbc3c Add testcase for #10465 (#14943)
* add debug format string

* remove try except

* add changelog

* add docs and more tests

* Update lib/pure/strformat.nim

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>

* minor

* add testcase

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
2020-07-09 01:51:18 +02:00
flywind
3db6d9ea0c add docs and more tests for debug format strings (#14861)
* add debug format string

* remove try except

* add changelog

* add docs and more tests

* Update lib/pure/strformat.nim

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>

* minor

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
2020-07-08 22:21:30 +02:00
Clyybber
9016dd96ee Add testcase for #12129 (#14940)
* Add testcase for #12129

* Fix test
2020-07-08 22:04:21 +02:00
Andreas Rumpf
bc712c28fc fixes #14865 (#14937) 2020-07-08 18:59:34 +02:00
Clyybber
27579cfd3a Make arc compile laser again 2020-07-08 16:20:16 +02:00
Miran
3de5296337 remove a condition that table size must be passed as power of 2 (#14926)
* remove a condition that table size must be passed as power of 2
* remove power-of-2 condition from sets and sharedtables
* remove power-of-2 condition from deques
* use 'correctSize' for both branches
* prettify changelog.md and fix typos
* add a changelog entry
* fix double-call of 'right-size'
* fix the same thing in sets.nim
* introduce a new internal proc `slotsNeeded`

Deprecate the public proc `rightSize`, which is not needed anymore.
Now it is an identity function, allowing the old code to work
correctly and without extra allocations.
2020-07-08 15:01:47 +02:00
Andreas Rumpf
06d776a582 fixes #14900, this time for real, maybe (#14934) 2020-07-08 14:47:14 +02:00
Araq
cb1ecbf956 closes #14878 2020-07-08 12:22:55 +02:00
Araq
e42ce877a6 fixes #14805 2020-07-08 12:22:55 +02:00
Araq
ecf8cbbbe0 fixes #14900 2020-07-08 10:48:12 +02:00
Araq
cdce245a23 fixes #14899 2020-07-08 10:48:12 +02:00
Araq
b17e1efc67 progress 2020-07-08 10:48:12 +02:00
Andreas Rumpf
87f6a9592c fixes #14402 (#14908)
* fixes #14402

* added a test case
2020-07-08 08:21:55 +02:00
narimiran
e82a14b273 fix mistake in times.nim docs 2020-07-07 22:57:06 +02:00
Clyybber
8480bef1c4 Add testcase for #14864 (#14928)
* Add testcase for #14864

* :D
2020-07-07 22:43:36 +02:00
Dominik Picheta
25ceacbe4f Revert commit 3e843ab335. Closes #14930. 2020-07-07 19:18:02 +01:00
Andreas Rumpf
a61a7889b8 injectdestructors: refactoring, added more cases explicitly (#14929) 2020-07-07 17:47:57 +02:00
Araq
95808c2806 speed up Nim's lexer by using cstring instead of string. C optimizers are fragile. 2020-07-07 15:17:58 +02:00
Araq
49cea86d8b weaken tosproc test for my Windows machine which doesn't have 'ls' 2020-07-07 15:17:58 +02:00
awr1
37253d660f Minor improvements to typecast section of manual (#14896)
* Minor improvements to typecast section of manual

* Clarification to casting w/ concrete types

* Added less ambiguous language
2020-07-07 10:22:55 +02:00
Tomohiro
61a6098f2d Limit number of error messages from gcc/clang backend (#14852)
* Limit number of error messages from backend

* Avoid duplication of -fmax-errors

* make tests/misc/trunner.nim success
2020-07-07 10:22:10 +02:00
Clyybber
5bd2da3f64 Fix #14911 (#14922) [backport]
* Fix #14911

* Add testcase

* Fix test
2020-07-07 10:21:18 +02:00
Clyybber
ebd97884a0 Add testcase for #14472 (#14921) 2020-07-06 20:53:38 +02:00
ee7
a754160d65 tables.nim: Add named fields in smallest and largest (#14919)
The `smallest` and `largest` procs for `CountTable` returned a tuple
with named fields, but the same procs for `CountTableRef` returned an
anonymous tuple.

This commit makes those `CountTableRef` procs more consistent, and adds
a test.

Fixes: #14918
2020-07-06 14:02:03 +02:00
Araq
65af99a203 added security.md; refs #14882 2020-07-06 14:01:25 +02:00
Araq
6f962a4b36 fixes #14830 2020-07-06 13:41:56 +02:00
narimiran
46aacf917f Fix style inconsistencies due to the previous commit 2020-07-06 11:24:43 +02:00
narimiran
ebaf603c84 revert 0944b0f4 2020-07-06 10:55:51 +02:00
Dean Eigenmann
842efab8ae Update btrees.nim (#14916) 2020-07-06 10:23:42 +02:00
Juan Carlos
21b3ca636f Fix logging tiny bug (#14910)
* Fix logging tiny bug

* Update changelog.md

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>

* Update changelog.md

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>

* Update changelog.md

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>

* https://github.com/nim-lang/Nim/pull/14910#discussion_r450012032

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>
2020-07-06 04:00:25 -04:00
Clyybber
af27e6bdea Fix #14396 (#14793)
* Correct Left-To-Right evaluation of proc args
* Fix CPP backend
* Add testcase
* closes #14396
* closes #14345
* Improve test and optimize
* Improve testcase and optimize literals
* Fix bug
* Expand testcase and use DFA to optimize
* Turn genParams into proc
* Turn withTmpIfNeeded into a proc
* Cleanup
* Fix crash
* Better analysis
* Cleanup
* Trailing newline..
* Fix build
* Tiny cleanup

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-07-04 17:45:07 +02:00
Andreas Rumpf
1854d29781 scoped memory management (#14790)
* fixes the regressions
* closes #13936
* scope based memory management implemented
* enabled tcontrolflow.nim test case
* final cleanups
2020-07-04 07:37:24 +02:00
Timothee Cour
695154970d deprecate existsDir; use dirExists instead (#14884) 2020-07-03 23:04:23 +02:00
Juan Carlos
4f6acf24ff Add jsre (#14870) 2020-07-03 20:13:10 +02:00
Timothee Cour
a6cbe58e8c typetraits.$: $((int, float), int) is now "((int, float), int)" instead of "(tuple of (int, float), int)" (#14812)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-07-02 16:19:43 +02:00
Timothee Cour
dc5a40f3f3 {.deprecated: [existsFile: fileExists].} (#14735)
* {.deprecated: [existsFile: fileExists].}

* s/existsFile/fileExists/ except under deps

* workaround pending #14819

* fix test
2020-07-02 16:19:13 +02:00
Tomohiro
366b9a7e4a Fix #12745 (#14879) 2020-07-02 13:20:34 +02:00
Juan Carlos
d590611fc5 Clean out sharedlists (#14857) 2020-07-02 08:40:58 +02:00
Juan Carlos
cbcaf2bbc4 Clean out strutils (#14859)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-07-01 23:16:50 +02:00
Timothee Cour
930a0c999b cleanup comment now that #14434 was fixed (#14874) 2020-07-01 14:16:22 -07:00
Clyybber
1440e70c62 allow packed union (#14868)
Co-authored-by: Arne Döring <arne.doering@gmx.net>
2020-07-01 11:41:03 +02:00
Miran
1edb9a6178 fix #14401, trailing comma confuses nimpretty (#14867) 2020-07-01 11:40:13 +02:00
Timothee Cour
2867a33ebc fix #14846; add macros.extractDocCommentsAndRunnables (#14849)
* fix #14846; add macros.extractDocCommentsAndRunnables

* fixup

* update tests

* address comment
2020-07-01 09:26:23 +02:00
Juan Carlos
05384efec5 Clean out sharedtables (#14858)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-06-30 19:09:13 +02:00
Juan Carlos
a519f3b038 Removed asyncdispatch.newAsyncNativeSocket, was deprecated since 0.18 (#14854)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-06-30 16:29:53 +02:00
alaviss
56b3d422b0 typetraits: features and fixes (#14791)
* typetraits: add support for nnkTypeOfExpr

* typetraits: don't wrap typedesc symbols in StaticParam

* typetraits: add nested generics support to genericParams

* typetraits: make genericParams understand array[I, T] whackiness

Also moved tests to ttypetraits

* typetraits: clarify comment on genericParams
2020-06-30 15:25:53 +02:00
Ray Imber
36fa79a524 Fix asyncdispatch drain behavior (#14820) (#14838)
* Fix asyncdispatch drain behavior (#14820)

* Changed test to use asyncCheck instead of discard after code review (#14820)

* Added some debug statements to help understand what is happening in Azure.

* Removed debug statements and increased timeouts by 1 order of magnitude to account for slow Azure VMs

Co-authored-by: Ray Imber <ray@crankuptheamps.com>
2020-06-30 15:23:53 +02:00
flywind
8be54b8fa7 add debug fmt string like python's (#14808)
* add debug format string

* remove try except

* add changelog
2020-06-30 15:21:37 +02:00
Timothee Cour
89a15e417d CI openbsd: 3x batching via NIM_TESTAMENT_BATCH ; overall CI finishes in 21m instead of 34m (#14851)
* CI openbsd: 2x batching via NIM_TESTAMENT_BATCH

* auto-generate .builds/openbsd_x.yml to avoid code duplication

* 3x batching
2020-06-30 14:21:30 +02:00
Juan Carlos
04deb6c942 Clean out dom (#14855)
* Clean out dom

* Clean out dom
2020-06-30 10:08:16 +02:00
Juan Carlos
74d1f25010 Clean out oldast (#14837)
* Clean out old Deprecated CLI switch
* Update to remove --oldast CLI option
2020-06-30 10:01:25 +02:00
lbartoletti
5c1fa142d6 New freebsd platforms (#14801)
* add riscv as riscv64

* add all platforms supported by FreeBSD
2020-06-29 10:31:25 +02:00
Timothee Cour
1b41c3122b fix #13432 typetraits.$: $(int,) is now (int,); $tuple[] is now tuple[] (#14799)
* typetraits.$: $(int,) is now (int,); $tuple[] is now tuple[]

* changelog
2020-06-29 09:34:05 +02:00
Juan Carlos
5d5df4a394 Clean out Deprecated proc (#14797)
* Remove and/or clean out Deprecated 'add' proc for floats
* Update a test
2020-06-29 09:33:07 +02:00
aguspiza
d968163cd1 SSL_CTX_load_verify_locations parameters are reversed (#14815) [backport] 2020-06-29 08:50:37 +02:00
Clyybber
299ddda5f6 Make unreachable code a warning instead of an error (#14816)
* Make unreachable code a warning

* Adapt test

* Trigger CI
2020-06-29 08:49:53 +02:00
Timothee Cour
3732556468 fix ./koch tests following #14823 (#14845) 2020-06-28 14:34:34 -07:00
Clyybber
62394616e8 DFA and injectdestructors cleanup (#14824)
* DFA and injectdestructors cleanup

* More precise write analysis

* Cleanup obsoleted path

* Unify defInstrTargets and useInstrTargets

* Misc cleanups

* Nicer CFG printing

* Misc cleanups 2
2020-06-28 19:36:30 +02:00
Danil Yarantsev
7936768560 Fix some typos (#14843) 2020-06-28 19:17:18 +02:00
Clyybber
4f70180a58 Fix typo 2020-06-28 18:03:39 +02:00
Danil Yarantsev
c285739d55 Remove double entry for thiscall (#14842) 2020-06-28 18:00:43 +02:00
Andrey Makarov
d9c1501757 get rid of $READLINK variable (#14841) 2020-06-28 17:59:57 +02:00
Clyybber
394a56650a Fix #14647 (#14776)
* Fix #14647

* Correct fix

* Typo and add test

* For real now :p
2020-06-28 17:47:47 +02:00
Clyybber
037990bc78 Changelog: Tiny style improvement 2020-06-28 15:38:24 +02:00
lqdev
5d5271b789 fixed #14839 (#14840) 2020-06-28 13:38:57 +02:00
Clyybber
54a52e7d08 Update link to parseSpec proc 2020-06-28 00:13:54 +02:00
rockcavera
252f668829 add a second asyncnet.recvFrom (#14237)
* add a second asyncnet.recvFrom

* fixes

* pre-allocating address

* add a new nativesockets.getAddrString()
2020-06-27 22:59:08 +01:00
Manuel Bojato
bc66788b3f docs: Make ..<, .. ^ more discoverable (#14835) 2020-06-27 23:42:58 +02:00
Manuel Bojato
22f1b5120e Fix nimdoc invalid css on theme switch class (#14834) 2020-06-27 23:36:31 +02:00
Sizhe Zhao
ad00d616e8 Warn about calling wrappers at compile time until #14049 is fixed. (#14828) 2020-06-27 16:51:48 +02:00
Timothee Cour
90808877c5 testament: generic N-fold batching: windows CI 37mn=>16m (#14823)
* testament: run CI faster thanks to batching
* move ta_in, tstdin into existing tosproc
* move ta_out,tafalse,texitcode,tstderr into existing tosproc
* joinable osproc
* move tstdout into existing tosproc
* spec: batchable; fix tests
* fixup
2020-06-27 16:51:17 +02:00
Clyybber
fdb37400cb Testament: Reenable arraymancer (#14831) 2020-06-27 15:58:19 +02:00
Sizhe Zhao
70b07edf42 Fix missing comma (#14829) 2020-06-27 12:11:29 +02:00
treeform
f926dc53f1 Add all missing css properties to dom.nim. (#14825)
* Add all missing css properties

* remove extra space
2020-06-26 19:15:21 +01:00
Timothee Cour
4dfb062f4d update contributing.rst and docstyle.rst: refer to a bug via bug #1234 + other guidelines (#14796)
* add a testing convention in nep1
* misc updates to contributing.rst and docstyle.rst
* address comments
2020-06-26 10:40:34 +02:00
Timothee Cour
49fcda3330 followup after https://github.com/Vindaar/ggplotnim/pull/74 wrt #14447 lent iterators (#14817)
* followup after https://github.com/Vindaar/ggplotnim/pull/74 wrt #14447 lent iterators

* ggplotnim: remove -d:nimHasWorkaround14720
2020-06-26 04:10:22 +02:00
treeform
baa80ca9d4 Add hasAttribute method to dom.nim. (#14814)
See: https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute
2020-06-25 14:45:37 -07:00
ktamp
41c97e4b70 readLine: Fix issues with --gc:arc
**--gc:arc** defines **nimv2**. This changes the definition of **WideCStringObj**.
Also an empty string should be returned in case of EOF.
2020-06-26 00:31:06 +03:00
narimiran
13193b2964 turn 'runnableExample' into 'code-block' to make nightlies green
This example doesn't work on our nightlies CI.
Other procs in this module already use 'code-block'.
2020-06-25 16:55:11 +02:00
Clyybber
0a9a639230 Add testcase for #4796 (#14784)
* Add testcase for #4796

* Fix test
2020-06-25 15:12:30 +02:00
alaviss
1a0725f022 koch: add --localdocs to allow building only local docs (#14783)
* koch: add --localdocs to allow building only local docs

This flag also make koch doc use the passed arguments when building
the offline docs.

This is useful when generating nightlies as we would want to use
--doccmd:skip and also skipping a pass of docgen speed things up
drastically (for non-native targets).

This flag superseded the undocumented --docslocal.

* kochdocs: filter google analytics code from the arg list instead

This commit introduce a small PEG expression to filter out the google
analytics code before building local docs when --localdocs is not
specified. This lets us keep any arguments unrelated to google analytics
when building local docs, useful for use with --doccmd:skip
2020-06-25 10:28:57 +02:00
Timothee Cour
0c56eeda0e expr => untyped; stmt => typed (#14804)
* expr => untyped; stmt => typed

* changelog + comment
2020-06-25 10:22:08 +02:00
Timothee Cour
32f335f594 fix #14802 (#14803) 2020-06-25 08:00:19 +02:00
Danil Yarantsev
0327159344 Add test-cases to some fixed issues to close them (#14795) 2020-06-24 20:38:08 -07:00
ktamp
c6e09e335a readLine: Remove recursive imports 2020-06-25 00:22:24 +03:00
Danil Yarantsev
80952cadaa Reject casts to builtin typeclasses (#14788)
* Closes #14231, closes #14452

* Merge test to tcast.nim
2020-06-24 22:32:01 +02:00
Timothee Cour
3e5743d6f7 add typetraits.elementType (#14780)
* add typetraits.elementType

* add a test for 0-sized seq
2020-06-24 22:31:07 +02:00
Euan
0434aef4cd Patch #14716 - add missing when (#14792) 2020-06-24 18:44:10 +02:00
Timothee Cour
37081e2945 fromJson: support object variants (#14694) 2020-06-24 18:03:01 +02:00
Euan
a3ae52de1a Fix #14715 - detect tool fails on FreeBSD (#14716) 2020-06-24 18:02:18 +02:00
Timothee Cour
b49ac11a77 fix #10343 (#14789) 2020-06-24 18:00:35 +02:00
Clyybber
302e3b7f44 CI: Install the pkg we cloned (#14770) 2020-06-24 17:27:46 +02:00
narimiran
2220ff70be cleanup [ci skip] 2020-06-24 13:16:40 +02:00
Constantine Molchanov
1b196d85aa Fix Norm test path. (#14779) 2020-06-24 00:36:41 +02:00
ktamp
a3b9516249 readLine: Unicode support for Windows console
When input is read from the Windows console, input encoding is UTF16. This is translated internally to UTF8.
2020-06-23 23:31:41 +03:00
treeform
9ebbe000a8 Enable fidget in important_packages. (#14742)
* Enable fidget in important_packages.

Fidget now works with `nimble test` and there is a CI: https://github.com/treeform/fidget/commits/master

* Add libx11-dev to make fidget compile.

* try libxcursor-dev

* try xorg-dev
2020-06-23 20:37:29 +02:00
Miran
6bf2990f66 [backport] fix #14748, move gdb files to other section of installer.ini (#14772) 2020-06-23 20:36:59 +02:00
Miran
881d1ee57b fix #14750, don't allocate too much in newWideCString (#14773) 2020-06-23 16:15:37 +02:00
Clyybber
685d03e2e0 Correct changelog (#14775)
These switches were removed, not deprecated :)
2020-06-23 15:20:31 +02:00
Andreas Rumpf
16bdc547b7 fixes #14760 (#14769) 2020-06-23 15:17:17 +02:00
Clyybber
4cb41f53f0 Add testcase for #14440 (#14771) 2020-06-23 14:17:12 +02:00
Juan Carlos
28510a9da9 Deprecated laxStrings for mutating the internal zero terminator on strings and its Deprecated code cleaned out (#14766)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-06-23 13:20:53 +02:00
Juan Carlos
c3459c7b14 Deprecate oldNewlines, clean out deprecated code from oldNewlines (#14763) 2020-06-23 11:22:07 +02:00
Juan Carlos
79ed8e79ef Documentation GC (#14739) 2020-06-23 11:21:33 +02:00
Araq
ebd1cc0265 minor bugfixes for 'func' and .borrow 2020-06-23 10:58:55 +02:00
Andreas Rumpf
da29222f86 init checks and 'out' parameters (#14521)
* I don't care about observable stores
* enforce explicit initializations
* cleaner code for the stdlib
* stdlib: use explicit initializations
* make tests green
* algorithm.nim: set result explicitly
* remove out parameters and bring the PR into a mergable state
* updated the changelog
2020-06-23 10:53:57 +02:00
Timothee Cour
a9eee6db65 misc testament cleanups (#14764)
* misc testament cleanups extracted cleanups from #14530

* make sure all CI failures can be searched with `FAIL: ` including megatest failures
2020-06-23 10:53:03 +02:00
Juan Carlos
8e54bc5b0c Deprecate and/or remove ospaths (#14767) 2020-06-23 10:51:33 +02:00
Timothee Cour
511bd947d3 fix bug in semgnrc: runnableExamples should not semcheck, even with > 1 arg (#14768) 2020-06-23 10:06:36 +02:00
Timothee Cour
235d8ba069 unbreak CI, refs https://github.com/timotheecour/Nim/issues/167 (#14765) 2020-06-22 18:38:23 -07:00
Clyybber
03c8bbcc6e Remove outdated comment and copy of length (#14759) 2020-06-22 22:05:18 +02:00
b3liever
59ba4d8c03 added normal variate function (#14725)
* added normal variate function
* change method only slightly faster
* changelog + since

Co-authored-by: b3liever <b3liever@yandex.com>
2020-06-22 20:48:33 +02:00
Andreas Rumpf
451129de42 fixes #14240 [backport:1.2] (#14757) 2020-06-22 14:11:13 +02:00
Andreas Rumpf
8df20276c9 fixes #14458 [backport:1.2] (#14756) 2020-06-22 13:06:22 +02:00
alaviss
c8554ebc0c 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.
2020-06-22 09:23:24 +02:00
ee7
1e484ed62b [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.
2020-06-22 08:12:50 +02:00
treeform
1ffe113450 Export fields from the Selection object. (#14752)
See: https://developer.mozilla.org/en-US/docs/Web/API/Selection
2020-06-21 20:41:24 +02:00
Andreas Rumpf
3ba0c30758 sizeof for empty objects/tuples should be 1; fixes #14690 (#14751) 2020-06-21 19:58:37 +02:00
alaviss
c7dee55b87 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).
2020-06-21 19:28:03 +02:00
treeform
ca71a60ff6 Add css white-space property to dom.nim. (#14743)
https://developer.mozilla.org/en-US/docs/Web/CSS/white-space
2020-06-21 19:25:29 +02:00
Timothee Cour
79c90b30ee nep1: use subjectVerb, not verbSuject (#14732) 2020-06-19 23:38:43 +02:00
Kaushal Modi
ac8ab4c549 Clarify the use of the backwards index operator (^N) in tut1 (#14681)
* Clarify the use of the backwards index operator (^N) in tut1

For consistency:
- Do `[a .. ^b]` (notice spaces on both sides of `..`)
- Do `[c ..< d]` (notice spaces on both sides of `..<`)

Fixes https://github.com/nim-lang/Nim/issues/14671.

* tut1: Add a note that ^ template calls can be saved to consts
2020-06-19 10:22:48 -04:00
Juan Carlos
99c198625c Deprecate unroll pragma, remove from documentation (#14705) 2020-06-19 15:08:45 +02:00
Timothee Cour
2039e3e883 fix #13899 defer now works with async (#14723) 2020-06-19 15:08:00 +02:00
Araq
65c7884a3c fixes #14718 [backport] 2020-06-19 15:02:38 +02:00
Clyybber
45d1e55e72 Add testcases for #11811 and #14315 (#14726)
* Add testcase for #11811

* Add testcase for #14315
2020-06-19 14:56:38 +02:00
Araq
45bc6954c5 improve the parser's error message 2020-06-19 10:50:39 +02:00
Araq
522bc8dda1 added a space 2020-06-19 10:32:16 +02:00
Timothee Cour
5ad8b9e8eb fix #14685 tests/async/t7758.nim flaky (#14721)
* fix #14685 tests/async/t7758.nim flaky

* address comment

* address comment
2020-06-19 09:53:45 +02:00
Timothee Cour
9c42ae91b7 add legacy workaround; improve test so that it actually tests for the bugfix 2020-06-19 09:53:06 +02:00
solo989
408518c9fe Update tuple newLit 2020-06-19 09:53:06 +02:00
BarrOff
99ad65fdd6 make nim-gdb compatible with BSD systems (#14700) 2020-06-18 20:48:55 +02:00
Timothee Cour
bb62feff72 fix #14691 docgen works again for methods (#14701)
* fix #14691 docgen methods

* fixup
2020-06-18 08:47:16 +02:00
Timothee Cour
7df27b5035 [cleanups] doassert => doAssert; mark deadcode (#14711) 2020-06-17 20:25:25 -07:00
Miran
e7f280bd26 Remove deprecated stuff from stdlib (#14699)
* update to the latest Jester

* remove deprecated procs from some stdlib modules

* 'criterion' is not maintained anymore and relies on obsolete stuff
2020-06-17 15:25:02 +02:00
Timothee Cour
8619534293 remove compilerproc from newIdentNode (#14692) 2020-06-17 08:10:34 +02:00
Juan Carlos
15a45e8e73 Documentation update nims.rst (#14683)
* Update nims.rst to add modules that work on NimScript as mentioned in the changelog.md

* https://github.com/nim-lang/Nim/pull/14683#issuecomment-644976921
2020-06-17 07:58:03 +02:00
solo989
bdd2c25e9f Update macros.nim (#14697) 2020-06-17 07:57:04 +02:00
Timothee Cour
ff93302f69 use check to investigate #14685 flaky tests/async/t7758.nim (#14689) 2020-06-16 15:57:57 -07:00
Timothee Cour
7ded490ec0 cleanup tests/test_nimscript.nims (#14686) 2020-06-16 14:38:30 -07:00
Dylan Modesitt
e35b21e553 Close#5586 (#14682)
* re-enable macos and bsd on some coro tests

* re-enable macos and bsd on some coro tests
2020-06-16 16:24:26 +02:00
Euan
1bc2e19498 Set cincludes and clibdir for FreeBSD, OpenBSD and NetBSD. (#14680) 2020-06-16 11:44:28 +02:00
Timothee Cour
dfe51d10a1 addQuitProc now works with closures, and c, js(node/browser) backend; fix some bugs in testament (#14342)
* make addQuitProc great again

* fix bugs in testament

* fix test

* change 2016 => 2020

* addQuitProc => addExitProc + locks

* move to std/exitprocs
2020-06-16 11:43:48 +02:00
Timothee Cour
45cac4afda fix #14179, fix #14142, make CI 1.4x faster (2x faster locally) (#14658)
* fix #14142: no more clash with: import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims

* remove a comment

* Revert "fixes the regression #12860 caused; hotfix"

This reverts commit 3d2459bdc0.

* Revert "Undefine `paramCount` & `paramStr` in nimscript.nim for *.nims (#12860)"

This reverts commit d38853c504.

* noNimScript => noWeirdTarget + noNimJs
2020-06-16 08:56:12 +02:00
Euan
7b12f13946 Use cc on OpenBSD and link to libm when building result (#14672) 2020-06-16 08:50:57 +02:00
Timothee Cour
de5cde473a hintMsgOrigin now works in VM code (#14678)
* `hintMsgOrigin` now works in VM code

* remove a simplification for now
2020-06-16 08:49:57 +02:00
Timothee Cour
faedb14a16 misc cleanups in compiler msgs: use toHumanStr, etc (#14677) 2020-06-15 21:17:24 -07:00
Timothee Cour
49033eb531 make tests/stdlib tests joinable (#14626)
* make tests/stdlib tests joinable

* fixup
2020-06-15 13:27:33 +02:00
Timothee Cour
d51beb7b20 make fromJson/toJson work with array[range, typ], + 1 bugfix (#14669)
* make toJson more robust

* properly handle array
2020-06-15 13:22:43 +02:00
Timothee Cour
bf604c6829 normalizeExe (#14668) 2020-06-15 10:57:34 +02:00
solo989
3cbf59336d Update newLit set[T] to work when set is empty. (#14662)
* Update macros.nim

* Update lib/core/macros.nim

Co-authored-by: Clyybber <darkmine956@gmail.com>

Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-06-15 09:15:17 +02:00
Ico Doornekamp
571bc011ea Added --benchmarkVM to times.cpuTime() documentation (#14663) 2020-06-15 08:58:11 +02:00
Juan Carlos
a056b4c3f1 Change 'Future Directions' to link memory management documentation (#14664) 2020-06-15 08:55:24 +02:00
jcosborn
5a22d6b57b fix codegen bug due to changing existing symbol declaration in template (#14666) 2020-06-15 08:40:12 +02:00
alaviss
d749c8cd87 compiler/commands: make gitHash settable at compile-time. (#14654)
This is useful for building nightlies, since we will be building from a
generated source archive and git metadata is lost there.
2020-06-14 11:22:55 +02:00
Andy Davidoff
4e3edf5836 add arc and orc to gc list (#14653) 2020-06-14 11:12:08 +02:00
Timothee Cour
0fc5d3f13b fix #14655 setLen(seq) now zeros memory (#14656)
* simplify sysstr.nim

* fix #14655
2020-06-14 11:11:26 +02:00
Dominik Picheta
d3b25a2948 Clarify imported exceptions note in manual 2020-06-13 11:44:01 +01:00
Timothee Cour
d149823019 fix #13166 tioselectors flaky test on freebsd+OSX (#14634) 2020-06-12 21:19:23 -07:00
Araq
5a26c3799b reorder.nim: fixed typos 2020-06-12 11:57:29 +02:00
Timothee Cour
e30a08103d remove tyOpt, mOpt (#14636)
* remove tyOpt, mOpt

* fixup
2020-06-12 11:03:52 +02:00
Juan Carlos
82e424189e Add rstgen.rstToLatex convenience proc for renderRstToOut and initRstGenerator with outLatex output, see https://github.com/nim-lang/fusion/pull/11#issuecomment-641804899 (#14629) 2020-06-12 10:51:55 +02:00
djazz
1168c75381 httpcore: Add http code 308 Permanent Redirect (#14639)
* httpcore: Add http code 308
* httpclient: Add 308 to redirection proc
* fix typo
2020-06-12 10:16:38 +02:00
alaviss
67d34366dc tools/kochdocs: add log folding supports for more CI services (#14643)
Added log folding for:
- Github Actions
- Azure Pipelines
2020-06-12 10:06:29 +02:00
Timothee Cour
c83a22b76e Disable tfdleak_multiple on platforms other than Windows (#14624) 2020-06-11 12:54:32 -07:00
c-blake
6aa971d39f Add proc find to heapqueue (#14628)
* Unwind just the "pseudorandom probing" (whole hash-code-keyed variable
stride double hashing) part of recent sets & tables changes (which has
still been causing bugs over a month later (e.g., two days ago
https://github.com/nim-lang/Nim/issues/13794) as well as still having
several "figure this out" implementation question comments in them (see
just diffs of this PR).

This topic has been discussed in many places:
  https://github.com/nim-lang/Nim/issues/13393
  https://github.com/nim-lang/Nim/pull/13418
  https://github.com/nim-lang/Nim/pull/13440
  https://github.com/nim-lang/Nim/issues/13794

Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in
identity hashes) are a better solution that is more general (no illusion
of one hard-coded sequence solving all problems) while retaining the
virtues of linear probing such as cache obliviousness and age-less tables
under delete-heavy workloads (still untested after a month of this change).

The only real solution for truly adversarial keys is a hash keyed off of
data unobservable to attackers.  That all fits better with a few families
of user-pluggable/define-switchable hashes which can be provided in a
separate PR more about `hashes.nim`.

This PR carefully preserves the better (but still hard coded!) probing
of the  `intsets` and other recent fixes like `move` annotations, hash
order invariant tests, `intsets.missingOrExcl` fixing, and the move of
`rightSize` into `hashcommon.nim`.

* Fix `data.len` -> `dataLen` problem.

* Add neglected API call `find` to heapqueue.

* Add a changelog.md entry, `since` annotation and rename parameter to be
`heap` like all the other procs for consistency.

* Add missing import.
2020-06-10 19:53:18 +01:00
Timothee Cour
8bbdb8f43f fix #14545 windows CI docs (#14590)
* fix #14545 windows paths
* add lib/std/private/strutils2.nim
* remove dependency strutils2 => strutils
* address comment: lib/std/private/strutils2.nim => compiler/strutils2.nim
2020-06-10 14:10:57 +02:00
ee7
5131af1a44 exceptions.nim: Fix a bad Error -> Defect renaming (#14621)
This commit fixes a mistake from 7d6cbf290a.
2020-06-10 09:34:20 +02:00
Timothee Cour
b7b84fa165 parseutils: integerOutOfRangeDefect => integerOutOfRangeError (#14627) 2020-06-09 23:57:27 -07:00
Timothee Cour
d81bc69587 enable tioselectors on osx; more diagnostic for #13166 (#14625) 2020-06-09 19:15:18 -07:00
Juan Carlos
387e337a2a Documentation update a description (#14619)
* Documentation update a description in a page listing links

* Update doc/docs.rst

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>

Co-authored-by: Danil Yarantsev <tiberiumk12@gmail.com>
2020-06-09 22:17:32 +01:00
Andreas Rumpf
6085ad95ff fixes #14279 (#14618) 2020-06-09 20:39:26 +02:00
Andreas Rumpf
b3029ba213 fixes #14578 (#14615) 2020-06-09 17:05:01 +02:00
Juan Carlos
881fa94b57 Documentation Fix Typo, Add Table (#14609) 2020-06-09 15:43:42 +02:00
ynfle
aa70cfdea2 Fix(astspec.txt): type of repeated word (#14612) 2020-06-08 20:14:26 -07:00
Max Grender-Jones
cc3409e264 Make the example better describe the desired outcome (#14611) 2020-06-08 18:49:07 -07:00
lbartoletti
30c09e4607 [OpenBSD] Add arm support (#14608)
* add arm support to openbsd

* use clang on openbsd
2020-06-08 20:06:04 +02:00
Andreas Rumpf
c308c2e60b optimized wrapWords; fixes #14579 (#14606) [backport:1.2] 2020-06-08 14:34:26 +02:00
Andreas Rumpf
e3f80e434a fixes #14557 (#14607) 2020-06-08 14:32:45 +02:00
Timothee Cour
c7a1a7b8bf toJson, jsonTo, json (de)serialization for custom types; remove dependency on strtabs thanks to a hooking mechanism (#14563)
* json custom serialization; application for strtabs
* serialize using nesting
* make toJson more feature complete
* add since
* Revert "Improve JSON serialisation of strtabs (#14549)"

This reverts commit 7cb4ef26ad.

* better approach via mixin
* toJson, jsonTo
* fix test
* address comments
* move to jsonutils
* doc
* cleanups
* also test for js
* also test for vm
2020-06-08 10:35:23 +02:00
Tomohiro
733bd76f6b Fix sugar.dump: It doesn't work correctly with compile time expression (#14580) 2020-06-08 10:28:42 +02:00
Timothee Cour
0d814f2d44 hotfix disable nitter refs https://github.com/timotheecour/Nim/issues/167 (#14603) 2020-06-08 08:15:34 +02:00
alaviss
8edac9cf1d openssl: use explicit result for SSL_in_init (#14597)
Sometimes the analysis might get funky and decide that the if-expression
below is not an if-expression. Details of how this can happen is largely
unknown, but it's easy to prevent so we will just go forward with that.

Fix #14591
2020-06-08 08:15:10 +02:00
Clyybber
52841dba09 Fix #14568 (#14583)
* Fix #14568
* Add testcase
* Fix bogus test
* Adapt other failing tests
* Declarations are always first writes
2020-06-07 23:32:41 +02:00
Andreas Rumpf
754a196d47 fixes #14315 (#14594) 2020-06-07 23:29:26 +02:00
Andreas Rumpf
419dbd573d fixes #14118 (#14595) 2020-06-07 20:11:42 +02:00
Andreas Rumpf
66c50c2ffc implement the 'bind' statement for generics, it was an oversight that this was never implemented (#14584) 2020-06-07 09:55:56 +02:00
lbartoletti
51b71e35f2 Fix link to "rebuilding the compiler" (#14567) 2020-06-06 21:53:18 +02:00
Andreas Rumpf
32083c7ff8 more precise analysis about 'observable stores' [backport:1.2] (#14582) 2020-06-06 21:28:46 +02:00
Leorize
4fdf9cb808 wrappers/openssl: defer loading SSL_CTX_set_ciphersuites 2020-06-06 21:11:53 +02:00
Leorize
6b2d8bfc8b net: also set TLSv1.3 cipher suites 2020-06-06 21:11:53 +02:00
Leorize
3cd74c6408 wrappers/openssl: mark casts as gcsafe
Nim will pretend that these proc are not gcsafe if they are not marked.
2020-06-06 21:11:53 +02:00
Leorize
b323bccd81 wrappers/openssl: enable SSL_CTX_set_ecdh_auto for LibreSSL
This procedure is not no-op for older LibreSSL, and the ABI is kept for
newer versions, so there's no harm in enabling it unconditionally for
all LibreSSL versions.
2020-06-06 21:11:53 +02:00
Leorize
e80a23f4d2 net: revert compatibility changes for Windows
This reverts commit d53a6355f3 and
688b1f250e.
2020-06-06 21:11:53 +02:00
Leorize
d406f588d8 wrappers/openssl: the version number comes from the utility library
Previously we loaded the SSL library for this, but that's not where the
symbol resides.
2020-06-06 21:11:53 +02:00
Leorize
0ca069b4f8 net: use CiphersOld list for Windows
The default DLLs shipped are too old, switch to CiphersOld list to
ensure compatibility.

This commit should be reverted before any future release.
2020-06-06 21:11:53 +02:00
Leorize
279438f1df net: don't call set_ecdh_auto for super old OpenSSL
And the fun thing is that currently we use a super old OpenSSL on
Windows.
2020-06-06 21:11:53 +02:00
Leorize
b5b191af4b wrappers/openssl: fix SSL_CTX_set_mode
Follow up of 794042080b
2020-06-06 21:11:53 +02:00
Leorize
61d4fbce4f wrappers/openssl: getOpenSSLVersion is gcsafe
Yet another weird {.gcsafe.} triggering when it shouldn't.
2020-06-06 21:11:53 +02:00
Leorize
6c0f86c486 net: enable automatic EC curve selection for OpenSSL 1.0.2
This setting is required for servers running OpenSSL < 1.1.0 to support
EC-based secure ciphers that is now part of the default cipher list.
2020-06-06 21:11:53 +02:00
Leorize
9278e785bd wrappers/openssl: fix SSL_CTX_ctrl signature 2020-06-06 21:11:53 +02:00
Leorize
e4e3d99ee2 asyncnet: clear SSL error queue before performing I/O
Follow up of 476be6cc27
2020-06-06 21:11:53 +02:00
Leorize
256841cf2c changelog.md: clarify that only the default has changed [ci-skip] 2020-06-06 21:11:53 +02:00
Leorize
1715935846 ssl_config_parser: refactor for sanity reasons 2020-06-06 21:11:53 +02:00
Leorize
3d4d3f4ac2 untestable/thttpclient_ssl: some tests are no longer broken
With the changes to the default cipher suites, certain tests are no
longer broken and are acting as they should.
2020-06-06 21:11:53 +02:00
Leorize
23cc4091d9 untestable/thttpclient_ssl: move incomplete-chain to dubious_broken
It's unsure why this test fail for macOS, but it doesn't hurt if it's
not passing.
2020-06-06 21:11:53 +02:00
Leorize
1fb2a58674 net: use a secure cipher list by default
Previously, the `net` module use the blanket "ALL" as the default cipher
list. This list may contain security ciphers that are weak and/or outdated
according to the current standard.

This commit introduces a new module `ssl_config` that contains the
latest OpenSSL configurations as recommended by Mozilla OpSec, and
make the `net` module use the cipher list targeting `intermediate`
compatibility level as the default.
2020-06-06 21:11:53 +02:00
Leorize
6cb94b5da6 asyncnet, net: clear openssl error queue before performing I/O
Per SSL_get_error(3):

  The current thread's error queue must be empty before the TLS/SSL I/O
  operation is attempted, or SSL_get_error() will not work reliably.

There has been records of not clearing the error queue causing weird SSL
errors when there shouldn't be any, see:

https://github.com/openssl/openssl/issues/11889
2020-06-06 21:11:53 +02:00
Leorize
f243f9aeb5 openssl: fix erroneous function signatures
Now matches the declaration in openssl/err.h
2020-06-06 21:11:53 +02:00
Leorize
78982b52f0 net: don't clear error queue unless shutdown() will be performed 2020-06-06 21:11:53 +02:00
Leorize
19ccce2617 Revert "net: don't clear all errors on close"
You're supposed to clear the error queue before any I/O operations. Per
SSL_get_error(3) man page.

This reverts commit ee3ed37300.
2020-06-06 21:11:53 +02:00
Leorize
44d0b4bdfd thttpclient_ssl: be less specific
The error we're looking for is "certificate verify failed". The routine
that reports this will be different between openssl versions, so it
makes no sense to track the routine name as well.
2020-06-06 21:11:53 +02:00
Leorize
d06e6eec79 net: don't clear all errors on close
Closing a socket clears the error queue of the entire thread, which
seems to be a bit too invasive.

Also I don't find any reason in the PR that added this.
2020-06-06 21:11:53 +02:00
Leorize
65b350f112 untestable/thttpclient_ssl: fix macos 2020-06-06 21:11:53 +02:00
Leorize
df91f61e20 untestable/thttpclient_ssl: fix 10000-sans test 2020-06-06 21:11:53 +02:00
Leorize
19ccc5fd8d untestable/thttpclient_ssl: catch errors caused by the bad catergory
Previously the errors caused by `SSL_shutdown()` masked these, so now we
catch them.
2020-06-06 21:11:53 +02:00
Leorize
82092b3bb7 asyncnet, net: call SSL_shutdown only when connection established
This commit prevents "SSL_shutdown while in init" errors from happening.

See https://github.com/openssl/openssl/issues/710#issuecomment-253897666
2020-06-06 21:11:53 +02:00
Timothee Cour
61f2f1f5c5 fix #14576 addr of param (including for lent) now works with nim js (#14577)
* fix #14576 addr(param) now works in nim js

* workaround https://github.com/nim-lang/Nim/issues/14578
2020-06-06 20:15:24 +02:00
Araq
336f1e63d0 reorder.nim: fixes the indentation 2020-06-06 20:08:57 +02:00
Zed
ea761419ad Fix asynchttpserver newline breaking content-length (#14565) [backport] 2020-06-06 12:20:11 +02:00
Timothee Cour
d573581eb7 remove isMainModule from json,os,sequtils (#14572)
* move json.isMainModule => tjson

* move isMainModule => tos,tsequtils
2020-06-06 11:50:46 +02:00
Danil Yarantsev
b19ad22b90 Fix #14570 (#14571)
* Fix #14570
2020-06-06 09:31:19 +02:00
Timothee Cour
7cdf470269 refs #14545 fix snippet errors: avoid showing confusing errors when they are expected (#14569) 2020-06-05 19:04:39 -07:00
Araq
0824fdd061 fixes #14562 2020-06-05 16:15:13 +02:00
PMunch
7cb4ef26ad Improve JSON serialisation of strtabs (#14549)
This creates a more compact serialisation of strtabs that is more in
line with the normal tables.
2020-06-05 10:54:38 +02:00
alaviss
c1ca06b452 tfdleak: fix flakyness on Windows (#14550)
* tfdleak_multiple: introduce stress tester for tfdleak

Imported from #14548 and tweaked for consumption by testament.

This test seems to be really good at bringing out the flakyness of
tfdleadk.

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* tfdleak: increase accuracy of the test on Windows

This commit implements a new testing strategy for Windows:
1. We duplicate the handle that will be tested and enable inheritance.
   This duplicate will serve as a reference handle.
2. In addition to checking whether the handle is valid, we also verify
   whether the handle is the same as the reference. This gives us
   complete certainty on whether the handle in question is inherited
   from the parent.
   A side effect is that this uses Windows 10+ APIs. But since
   this is just for the test, we don't have to be picky about it.

Ideally we would want to do something like this for other POSIX-based
system, but most of them lack a facility to do this, and as of writing
there isn't any false positive for them, so we won't need the additional
checks.

MemFile.fHandle will also no longer be tested, as this handle defaults
to being invalid.

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
2020-06-04 13:25:38 +02:00
Timothee Cour
01f6e505c8 bug fixes with sfMainModule, hints, mainPackageNotes, mainPackageId, hintSuccessX (#14555)
* SuccessX `out` now works with --compileOnly and jsonscript; fix bugs in jsonscript
* several bug fixes; eg: `nim doc lib/system/io` now is sane
* dummy edit to force docs CI
2020-06-04 10:40:17 +02:00
Timothee Cour
4ba34522f6 [cleanup] docgen: remove docOutdir now that outDir is always set (#14554) 2020-06-03 19:20:41 -07:00
alaviss
55f0df164b io: correct signature for some win32 apis (#14551)
See https://github.com/nim-lang/Nim/pull/14550#issuecomment-637937649
2020-06-03 18:17:06 +02:00
Timothee Cour
4301a3da9d * honor --errorMax even for tools (eg drnim, nim doc) (#14546)
* fix a bug that prevented nim doc compiler/nim on windows
2020-06-02 18:54:33 +02:00
Timothee Cour
621384b8ef fix https://github.com/timotheecour/Nim/issues/266 retry on failure to avoid common 503 github errors (#14547) 2020-06-02 10:47:19 +02:00
cooldome
e5b64af831 Implement rendering of []=, {}, {}= braces (#14539)
* render curly braces
* fix typo
* fix test

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-06-01 19:56:17 +02:00
Timothee Cour
3cf88c2b49 walkDirRecFilter, update doc CI filter, compiler/index.nim for docs + various other fixes (#14501)
* update doc CI filter to include the files mostly likely to require doc rebuild
* remove code duplication in ./config/nimdoc.cfg; show link to compiler docs, various fixes
* walkDirRecFilter, factor nativeToUnixPath workaround
* glob for getRst2html
* docslocal: 40s to build all docs
* revert code dedup in github actions which did not work alas...
* fixups
2020-06-01 19:21:41 +02:00
Andreas Rumpf
75e579ff8e parser.nim: minor refactorings (#14540) 2020-06-01 19:04:28 +02:00
Danil Yarantsev
3698f197f1 Change severity of template instantiation message [backport] (#14526)
* Change severity of template instatiation msg

* Add a test

* Trailing newline argh
2020-06-01 17:07:01 +02:00
Frank Paulo Filho
4bb301dbe2 Make build_all.sh file executable (#14518) 2020-06-01 15:57:16 +02:00
Timothee Cour
0a27cca4b5 runnableExamples: correctly handle multiline string litterals (#14492)
* runnableExamples: correctly handle multiline string litterals

* address comments: improve doc comments + variable namings
2020-06-01 15:56:29 +02:00
Andreas Rumpf
0db148163b fixes --warningAsError implementation (#14538) 2020-06-01 15:41:14 +02:00
Danil Yarantsev
00ec43305e Fix compiles for nimsuggest [backport] (#14527)
* Handle nimsuggest in tryExpr
* Added test
2020-06-01 15:06:45 +02:00
Khronos
5900d8442c Fix a problem with extra build commands. (#14528)
When --compileOnly is on, extraCmds are not added to JsonBuildInstructions.

```
$ echo 'echo 123'>test.nim
$ nim c --debuginfo --nimcache:cache test
$ ls
cache test test.dSYM test.nim
$ tail -n3 cache/test.json
"extraCmds": ["dsymutil /Users/khronos31/src/tmp/test"],
"stdinInput": false
}
```

```
$ echo 'echo 123'>test.nim
$ nim c --debuginfo --nimcache:cache --compileOnly test
$ nim jsonscript --nimcache:cache test
$ ls
cache test test.nim
$ tail -n3 cache/test.json
"extraCmds": [],
"stdinInput": false
}
```
2020-06-01 14:06:25 +02:00
Ico Doornekamp
0489e76da7 manual: removed subjective phrase from 'macros' section (#14536)
Removed phrase "However, this is no real restriction because
Nim's syntax is flexible enough anyway." from the manual - I find it
very subjective, and I sometimes *do* find myself restricted by Nim's
syntax when writing DSLs
2020-06-01 14:02:17 +02:00
Andreas Rumpf
8710395a0f fixes #14514 [backport:1.2] (#14533) 2020-06-01 12:33:13 +02:00
Danil Yarantsev
5d0cf883c1 Disable unused warnings for error await template too (#14531) 2020-06-01 11:56:07 +02:00
Timothee Cour
004b0759c5 fix CI doc windows: style error in lib/std/time_t.nim (#14523) 2020-05-31 14:57:16 -07:00
Danil Yarantsev
5150186c68 Disable unused warnings for await in async macro (#14517)
* Disable unused warnings for await in async macro

* Remove used for the error template
2020-05-31 12:43:27 +02:00
Araq
177c7f96e9 spec: be explicit that NRVO will evolve further 2020-05-30 19:55:01 +02:00
Araq
984af3d64e document NVRO and exception handling 2020-05-30 19:50:11 +02:00
Andreas Rumpf
52c3633223 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) 2020-05-30 19:38:51 +02:00
Andreas Rumpf
7ccc7d7e93 fixes #14498 [backport:1.2] (#14503) 2020-05-30 15:32:31 +02:00
Andreas Rumpf
3105909f88 fixes #14495 [backport:1.2] (#14496) 2020-05-29 23:35:57 +02:00
Timothee Cour
cb6eb5268f enable compiler docs with their own index+search (#14493)
* enable compiler docs (with its own index)
2020-05-29 22:11:41 +02:00
Timothee Cour
63d1a0289e fix #14421 items uses lent T (#14447)
* fix #14421 items uses lent T for seq + openArray
* add -d:nimWorkaround14447
* fix test
2020-05-29 17:10:59 +02:00
Timothee Cour
e646c16e06 hotfix doc comments for procs without body (#14494) 2020-05-29 05:30:36 -07:00
Andreas Rumpf
e31ac81899 more checking for --gc:arc, no need for valgrind (#14467)
* sigmatch: removed dead code
2020-05-29 12:08:17 +02:00
Neelesh Chandola
4c08e64e98 disallow typedesc in arrays & move existing checks to types.typeAllowedAux (#13261)
* disallow typedesc in arrays and move previous checks to types.typeAllowedAux
2020-05-29 11:48:15 +02:00
Timothee Cour
579456d520 fix #14485 (#14487) 2020-05-28 19:00:36 -07:00
Timothee Cour
e013ebc91a fix #8871 runnableExamples now preserves source code comments, litterals, and all formatting; other bug fix (#14439)
* fix #8871 runnableExamples now preserves source code comments, litterals, and all formatting
* remove orig deadcode from getAllRunnableExamplesImpl
* fix expected examples
* add test to close https://github.com/nim-lang/Nim/issues/14473
* correctly handle regular comments before 1st token inside runnableExamples
* add test to answer https://github.com/nim-lang/Nim/pull/14439#discussion_r431829199
* update tests
2020-05-28 20:46:06 +02:00
Timothee Cour
17d08ff71c close #14284 document semantics for start for re,nre; improve examples (#14483) 2020-05-28 20:43:36 +02:00
Timothee Cour
fe7a2d60f9 make it easier to figure out how to debug issues (#14477) 2020-05-28 01:19:12 -07:00
Kaushal Modi
e62ccaa4dc Propagate the outDir to rstgen to fix hrefs for modules in subdirs (#14479) 2020-05-28 00:13:24 -07:00
Andreas Rumpf
1fc40db984 drnim improvements (#14471) 2020-05-27 18:14:24 +02:00
Huy Doan
00fa7a5747 Add thiscall calling convention, mostly for hooking purpose (#14466)
* Add thiscall calling convention, mostly for hooking purpose
* add changelog and documentation
2020-05-27 16:24:47 +02:00
Ivan Bobev
cc65ae6011 Change UnpackError with UnpackDefect (#14457)
* Change `UnpackError` with `UnpackDefect`

The deprecation warning for `UnpackError` exception raised by some
`inline` procedures in the Nim standard library propagates to the user
code. If the user code has a requirement for building without warnings
this is a problem for the successful execution of the tests. In order
to resolve this, all occurrences of `UnpackError` in the Nim code base
are changed to `UnpackDefect`. Only the type alias is retained to not
break other people's user code since `UnpackError` is exported type.

* Remove the catching of `UnpackDefect`

Defect exceptions should not be cached, because they indicate problem in
the API usage. The code in `nimblesocket.nim` is rewritten to first
check whether there is a value set into the `knownDomain` variable from
the `Option` type before usage.
2020-05-27 08:34:13 +02:00
alaviss
0533c43547 Revert "niminst: use threaded compression when supported (#14455)" (#14462)
This reverts commit b749d58ea1.
2020-05-27 08:33:24 +02:00
Andreas Rumpf
dadc97d91e typo 2020-05-26 14:49:44 +02:00
alaviss
b749d58ea1 niminst: use threaded compression when supported (#14455) 2020-05-26 14:05:51 +02:00
Timothee Cour
38cb277653 docgen: mangling using _. instead of @@ to avoid issue (#14454) 2020-05-26 10:08:35 +02:00
Bung
2a4a43b05f add bindParams to db_sqlite (#14408)
* add bindParams to db_sqlite
* no need typeinfo
* remove extro spaces
* reduce bindParams to two branches,raise DbError
* Update lib/impure/db_sqlite.nim
* change bindParams to macro,accept varargs[untyped] as params
* change bind blob val to openArray[byte]
* remove unused err type
* explicitly using i32 param
* using import std/private/since
* SQLITE_OK to right hand

* bindParam val int using bindParam overload
* copy data by default
* change exec to template
* remove SqlPrepared procs unused varargs
* fix setupquery for prepared,reset first for exec prepared,add bindNull for literal nil

Co-authored-by: alaviss <leorize+oss@disroot.org>
2020-05-26 07:44:47 +02:00
Timothee Cour
55758920f4 docgen: fix #14448 show @@ as .. in href text (#14451) 2020-05-25 18:16:00 -07:00
Timothee Cour
acadda8da2 tnimblepathdollarfail.nim -> tests/nimble/tnimblepathdollar_fault to reduce false positives when searching for fail in CI logs (#14450) 2020-05-25 13:54:30 -07:00
Timothee Cour
f96555bd10 fix #9227 procs can now have multiple interleaved doc comments + runnableExamples and be docgen'd correctly (#14441)
* fix #9227 proc doc comments after 1st runnableExamples are not ignored anymore
2020-05-25 15:44:23 +02:00
cooldome
6635874a85 make get for options use lent T (#14442)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-25 15:31:02 +02:00
Timothee Cour
58282547f6 fix #6583, fix #14376, index+search now generated for all projects, many bug fixes with nim doc (#14324)
* refs #6583 fix nim doc output
* changelog
* change default for outDir when unspecified
* cleanups
* --project implies --index
2020-05-25 13:25:40 +02:00
Max Grender-Jones
cbfe9325c5 Add support for mktemps (#14347) 2020-05-25 12:18:35 +02:00
Andreas Rumpf
79e85cb0b5 manual.rst: updates [backport] (#14445) 2020-05-25 12:16:32 +02:00
Timothee Cour
a008f591e2 add test for define, undef (#14443) 2020-05-25 11:17:25 +02:00
treeform
acae3b02c7 Add clipPath to dom.nim. (#14435)
Just adds a single new css atribute, see: https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path .
2020-05-24 07:32:24 +02:00
hlaaftana
f70d01a7d5 fix repr(char) example assert (#14437) 2020-05-23 21:26:49 -07:00
genotrance
b012205b2e Fix #14057 - moveFile should overwrite on Windows (#14433) 2020-05-23 17:06:04 +01:00
Andreas Rumpf
c61f746629 avoid unsafe Nim features in preparation for --gc:arc (#14431) 2020-05-22 20:24:37 +02:00
Bung
6668b43409 add insert,tryInsert unify for postgres that need pk name (#14416)
* add insert,tryInsert unify for postgres that need pk name
* add ReadDbEffect to new procs
* add .since and changelog
* change since to 1.3
* Update lib/impure/db_postgres.nim

Co-authored-by: bung87 <crc32@qq.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: alaviss <leorize+oss@disroot.org>
2020-05-22 19:24:52 +02:00
Mildred Ki'Lya
7b3dcfde20 Add missing attributes and methods to JavaScript DOM (#14428)
- content attribute to access HTML template element:
  https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content

- ownerDocument to access the owning document from a DOM Node:
  https://developer.mozilla.org/en-US/docs/Web/API/Node/ownerDocument

- outerHTML to get/set the outer HTML representation of a Node:
  https://developer.mozilla.org/en-US/docs/Web/API/Node/ownerDocument

- createComment() to create comment Nodes:
  https://developer.mozilla.org/en-US/docs/Web/API/Document/createComment

- querySelector() and querySelectorAll() on Nodes:
  https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector
  https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll
2020-05-22 14:34:20 +02:00
Timothee Cour
0d0ea3a11e no more code duplication bw liMessage and rawMessage + several bug fixes (#14415)
* no more code duplication bw rawMessage and liMessage; fixes some bugs in rawMessage
* all compiler messages work with hint:msgorigin
2020-05-22 12:02:10 +02:00
Andreas Rumpf
f7b73e6bfd make malloc.nim consistent in style (#14427) 2020-05-22 09:55:10 +02:00
Timothee Cour
149251cab9 [cleanup] fix UnusedImport sempass2 compiler/semparallel.nim (#14426) 2020-05-21 23:28:47 -07:00
Andreas Rumpf
3eaa870c0a ARC/ORC: optimize s.setLen(0) to match the old runtime's behaviour (#14423) 2020-05-21 22:38:13 +02:00
Andreas Rumpf
ddee8a362a change the [Processing] messages into dots (#14418)
* change the [Processing] messages into dots

* better implementation

* maybe I should work on something else...
2020-05-21 22:36:34 +02:00
Andreas Rumpf
063229a301 fixes a bug reported in https://forum.nim-lang.org/t/6361 (#14422) 2020-05-21 22:18:58 +02:00
Mamy Ratsimbazafy
f71f8b0239 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)
2020-05-21 17:52:40 +02:00
Timothee Cour
5caaa4bf6f fix #14404 foldr had the classic multiple evaluation bug (#14413) 2020-05-21 11:01:43 +02:00
Timothee Cour
e600ddc555 fix comment from e909486e5c (r39287564) (#14412) 2020-05-20 18:34:14 -07:00
Clyybber
6969a468ce Remove #PRTEMP leftover comment 2020-05-20 13:04:52 +02:00
Clyybber
7fe4c66f35 Small improvements for string and char repr with gc:arc (#14400)
* Small improvements for string and char repr with gc:arc

* Fix test
2020-05-20 12:54:04 +02:00
Timothee Cour
3d20f14193 fix #10731 ; runnableExamples "-b:cpp --run:off": code works (#14384)
* runnableExamples "-b:cpp -r:off": code
2020-05-20 09:45:34 +02:00
alaviss
4ae341353d asyncdispatch, asyncnet: add inheritance control (#14362)
* asyncdispatch, asyncnet: add inheritance control

* asyncnet, asyncdispatch: cleanup
2020-05-20 09:42:55 +02:00
Danil Yarantsev
1450924b1e Fix some typos in the manual [backport] (#14399) 2020-05-20 09:28:47 +02:00
Andreas Rumpf
16003bffe1 fixes #14126 [backport:1.2] (#14390)
* fixes #14126 [backport:1.2]

* used more logic to optimize it further; updated Nimble version
2020-05-20 00:41:57 +02:00
Andreas Rumpf
b35d370d88 specialize genericReset (#14398)
* progress
* make tests green
* maybe we also want to reset pointers, dunno
* progress
* cleanup; fixes #13879 [backport:1.2]
2020-05-19 21:42:53 +02:00
Timothee Cour
e909486e5c trunner was not actually being tested in non-CTFFI mode; minor testament cleanups (#14377)
* use check
* trunner now works with cpp
* cleanup: move compiler/unittest_light => stdtest/unittest_light
* fix tests/readme.md
* remove deadcode references to rodfiles
* fix for windows
2020-05-19 09:41:31 +02:00
Ștefan Talpalaru
27741d6a5c fix #14364 (#14372) [backport:1.2]
Turn on the TLS emulation when using Boehm, since it doesn't scan the
real TLS.
2020-05-18 23:44:04 +02:00
Clyybber
ac65986aae Fix #14394 (#14395) 2020-05-18 17:43:06 +01:00
Timothee Cour
2627e1e945 refs #14369 improve docs for importcpp exceptions (#14391)
* refs #14369 improve docs for importcpp exceptions

* address comments
2020-05-18 17:10:30 +01:00
cooldome
810039ec0b docs:getCurrentException() and getCurrentExceptionMsg() are not available for imported exceptions (#14392) 2020-05-18 08:15:10 -07:00
Timothee Cour
5beed56d0a fix #14174 do not collapse pragma inside runnableExamples (#14385) 2020-05-18 11:03:34 +02:00
cooldome
bc42e9aa98 fix #14369 (#14386)
* fix #14369

* empty commit
2020-05-18 09:38:36 +02:00
Timothee Cour
b11ff518fa fix #12293 findNimStdLibCompileTime should not break with nimble install compiler (#14334)
* fix #12293 findNimStdLibCompileTime should not break with nimble install compiler

* address comment to unblock PR
2020-05-18 09:38:12 +02:00
Miran
69cc1ddc4d install gtk3 on osx for package testing (#14388) 2020-05-18 09:03:01 +02:00
Timothee Cour
51578be296 close #12746; minor cleanup (#14379) 2020-05-17 13:28:18 +02:00
Frank Schmitt
42e80829c7 docs: fix syntax error in hotCodeReloading example (fixes #14380) (#14381)
Co-authored-by: Frank Schmitt <frankschmitt@gmx.de>
2020-05-17 12:44:36 +02:00
John
40ac19572a add OpenBSD MAP_STACK for coroutines (#14353) 2020-05-16 21:56:52 +02:00
Andreas Rumpf
7f377da1d2 fixes #14370 (#14371) 2020-05-16 17:03:25 +02:00
Dominik Picheta
7361e2627b Emscripten: disable epoll (#14361)
Epoll is not supported by epoll.
2020-05-16 15:50:41 +02:00
Bung
390ff428f0 add SqlPrepared api fix #13559 (#14365)
Co-authored-by: bung87 <crc32@qq.com>
2020-05-16 15:50:04 +02:00
Timothee Cour
c777f2fb60 fix some issues with --backend (#14363)
* fix some issues with --backend
* fix https://github.com/timotheecour/Nim/issues/175; improve upon #14306
2020-05-16 13:09:18 +02:00
Bung
c32e1378eb docfix: fix wrong link in doc/manual.rst (#14367) 2020-05-16 03:04:39 -07:00
Kaushal Modi
bf0e1c696f Remove the uses of {.procvar.} pragma (#14359)
This pragma did nothing.

Ref:
- https://github.com/nim-lang/Nim/issues/2172#issuecomment-383276469
- https://github.com/nim-lang/Nim/issues/12975
2020-05-15 23:37:24 +02:00
Bung
ce0552c100 fix #9771 (#14357)
* fix #9771
* map SQLLEN SQLULEN
* fix proc params take TSqlLen

Co-authored-by: bung87 <crc32@qq.com>
2020-05-15 21:00:06 +02:00
Clyybber
9f78f116b2 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
2020-05-15 19:24:43 +01:00
PMunch
13cfaf5fd5 Improve nimeval, changes some defaults (#14351)
* Improve nimeval, changes some defaults

This improves nimeval to make it easier to use NimScript as an embedded
scripting languages. It does change some of the defaults, so in case
anything used the old version and depended on the old behaviour these
would have to be changed.

* Remove dependency on nimhcr for nimscript
2020-05-15 19:32:52 +02:00
Danil Yarantsev
105079e88a Speed up testing of some packages (#14358) 2020-05-15 16:26:03 +02:00
hlaaftana
80c360fceb fix #14350, cstrings in JS init as null (#14355)
* fix #14350, cstrings in JS init as null
2020-05-15 10:07:30 +02:00
Araq
278b4582f5 fixes #14340 2020-05-14 08:51:47 +02:00
Kaushal Modi
a2a3fa1039 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 .
2020-05-14 07:27:57 +02:00
cooldome
5fb40af57e fix #14333 (#14336)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-13 23:57:05 +02:00
Andreas Rumpf
82870e0737 fixes #13998 [backport:1.2] 2020-05-13 23:56:40 +02:00
Araq
8a339d1178 fixes #13862 2020-05-13 23:56:40 +02:00
Andreas Rumpf
f3e17e7c77 fixes #13104 [backport] 2020-05-13 22:29:02 +02:00
Andreas Rumpf
79fe87500f fixes #13935 2020-05-13 22:17:38 +02:00
Timothee Cour
3573a4f9c1 no more guessing where compiler msgs came from (#14317) 2020-05-13 17:19:44 +02:00
Araq
a3719df8b3 fixes #14331 2020-05-13 14:29:53 +02:00
Timothee Cour
041ee92bba osproc.execCmdEx now takes an optional input for stdin, env, workingDir (#14211)
* `osproc.execCmdEx` now takes an optional `input` for stdin

* execCmdEx now also takes an optional ``workingDir` and `env`
2020-05-13 13:45:36 +02:00
Timothee Cour
1648f1dd99 fix #14320 (tasyncawait.nim is recently very flaky) + avoid hardcoding service ports everywhere + flakyAssert (#14327)
* hotfix #14320 tasyncawait.nim is recently very flaky
* fix #14327
* add flakyAssert
2020-05-13 11:05:47 +02:00
PMunch
9acbf99efb Allow let to not have value when using importc (#14258)
* Allow let to not have value when using importc

This allows a let statement with the `{.importc.}` pragma to not be
initialised with a value. This allows us to declare C constants as Nim
lets without putting the value in the Nim code (which can lead to
errors, and requires us to go looking for the value). Fixes #14253

* Proper fix and documentation + changelog entry

* Improve testcase with one from timotheecour

* Add test to verify it working with macros
2020-05-12 20:28:18 +02:00
Araq
82f008158c cycle collector: make it threadsafe 2020-05-12 20:13:06 +02:00
b3liever
09ea8f9cf8 fix detecting closure env for nested asts (#14326)
Co-authored-by: b3liever <b3liever@yandex.com>
2020-05-12 20:09:56 +02:00
Timothee Cour
dddfbcf211 close #13071 by adding test: nim cpp -r --gc:arc` segfaults on caught AssertionError (#14323) 2020-05-12 19:19:31 +02:00
Timothee Cour
de74362213 fix #14314 do not analyze importc procs for effects (#14319) 2020-05-12 16:19:03 +02:00
Andreas Rumpf
06dfd31612 fixes #13881
* fixes #13881
* documented changed requirements for system.onThreadDestruction
* destructors.rst: update the documentation
2020-05-12 15:46:24 +02:00
cooldome
4277ab470a fix one motr dicriminator bug 2020-05-12 12:45:34 +01:00
cooldome
dfae796ac3 fix test 2020-05-12 11:45:14 +01:00
cooldome
2d7ccf0928 fix #14312 2020-05-12 10:23:05 +01:00
Avahe Kellenberger
55446c05a4 Added a reference to ternary operators. (#14309)
`if expressions` are similar to ternary operators in other languages.
In order to make this easier to find in the manual, I've added a
sentence about it.
2020-05-12 08:28:10 +02:00
Timothee Cour
b8ec07f19e properly fixes #13758 so that import std/macros stays legal (#14291)
* properly fix https://github.com/nim-lang/Nim/issues/12389
* use --lib:lib in koch.nim.cfg instead
* third time is the charm
2020-05-12 08:27:47 +02:00
cooldome
a39123c93c fix #14219 (#14225)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-11 23:11:20 +02:00
Kaushal Modi
86669ef5b4 Make --backend:cpp|js work for :test: code-blocks as well (#14306)
Continues 9502e39b63

Ref:
- 9502e39b63 (commitcomment-39087584)
- https://github.com/nim-lang/Nim/pull/14278

Fixes https://github.com/nim-lang/Nim/issues/13129 .
2020-05-11 20:45:35 +02:00
slangmgh
76f7e95814 Fix #14289 (#14304) [backport] 2020-05-11 19:17:37 +02:00
Andreas Rumpf
0f344a70c9 fixes #13946 (#14302) 2020-05-11 19:12:40 +02:00
b3liever
a081b10b54 small refactoring (#14303)
Co-authored-by: Antonis <b3liever@yandex.com>
2020-05-11 19:12:25 +02:00
cooldome
fee71d466c fix #14294 (#14301)
* fix #14294

* fix orc as well

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-11 19:10:54 +02:00
Andreas Rumpf
03c146cd93 do not track 'raise Defect' in the .raises: [] clause anymore (#14298)
* do not track 'raise Defect' in the .raises: [] clause anymore

* --panics:on maps 'raise Defect' to an unrecoverable fatal error

* make tests green again

* update the documentation too
2020-05-11 16:25:56 +02:00
Antonis
517dd800f8 better error message 2020-05-11 15:39:44 +02:00
Antonis
3616b0698b fix closure env check 2020-05-11 15:39:44 +02:00
Antonis
73c9d2c9d7 Fix for --styleCheck:error 2020-05-11 15:39:44 +02:00
Jovial Joe Jayarson
14f76f721d refactor: renamed readme to readme.md (#14283) 2020-05-11 13:50:40 +02:00
Timothee Cour
9502e39b63 nim doc --backend:js, nim doc --doccmd:-d:foo, nim r --backend:js, --doccmd:skip + other improvements (#14278)
* `nim doc --backend:js|cpp...`
`nim doc --doccmd:'-d:foo --threads:on'`
`nim r --backend:cpp...` (implies --run --usenimcache)
* --usenimcache works with all targets
* --docCmd:skip now skips compiling snippets; 50X speedup for doc/manual.rst
2020-05-11 12:01:18 +02:00
Timothee Cour
d11cb9d495 fix a critical bug in windows.osproc leading to resource leaks and blocking IO [backport] (#14296) 2020-05-11 11:14:21 +02:00
Andy Davidoff
8018449319 simple typo in locks.nim (#14297) 2020-05-11 02:59:31 -04:00
Timothee Cour
7c24250a57 diable nimx (CI failure) refs https://github.com/timotheecour/Nim/issues/167 (#14293) 2020-05-10 18:56:00 -04:00
Timothee Cour
dda6f3f6d4 nim doc -r main and nim rst2html -r main now call openDefaultBrowser (#14285) 2020-05-10 09:23:01 +02:00
Clyybber
8e93105606 Fix #14269 (#14286) 2020-05-09 18:22:25 +02:00
Timothee Cour
411be506a3 --hint:processing (+friends) is now supported and means --hint:processing:on, like all other bool flags (#14271) 2020-05-08 18:54:16 +02:00
Andreas Rumpf
ce16115e79 Merge pull request #14265 from alaviss/quickfix
nativesockets: add missing inheritable pass-through
2020-05-08 17:33:38 +02:00
Andreas Rumpf
bae8e95b73 fix root cause of https://github.com/dom96/choosenim/issues/193; config/config.nims should get installed (#14267) 2020-05-08 16:14:10 +02:00
Clyybber
4bd77cf045 Fix typo 2020-05-08 16:13:53 +02:00
Timothee Cour
363b7ff3b8 fix https://github.com/nim-lang/Nim/issues/14275 querySetting(nimcacheDir) works even if implicitly set (#14277) 2020-05-08 16:13:07 +02:00
Clyybber
120ea906fb Fix #14270 and add testcases (#14276) 2020-05-08 15:54:34 +02:00
hlaaftana
de27910ab7 make from an operator (#14241) 2020-05-08 07:54:46 +02:00
Timothee Cour
ee15437aed fix root cause of https://github.com/dom96/choosenim/issues/193; config/config.nims should get installed 2020-05-07 15:01:46 -07:00
cooldome
5fa7d374c4 fix #14243 (#14257)
* fix #14243

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-07 22:15:25 +02:00
alaviss
83435fe696 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.
2020-05-07 22:07:08 +02:00
Leorize
73a42ce941 nativesockets: add missing inheritable pass-through 2020-05-07 14:43:53 -05:00
Clyybber
42db75c970 Fix the DFA for "unstructured controlflow" (#14263)
* Fix the DFA for "unstructured controlflow"

* Add testcase from #14233
2020-05-07 21:41:55 +02:00
alaviss
1a1e9986a3 net: remove more erroneous set constructions (#14252) [backport]
Refs #13764
2020-05-07 13:37:54 +02:00
Miran
5a9b3c27c1 Split testing important packages into two jobs (#14256)
* split testing packages in two separate jobs
* speed-up the slowest tests
* special treatment for two packages
2020-05-07 10:08:05 +02:00
cooldome
0d8507cd3d fix #14236 (#14250)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-07 00:13:59 +02:00
cooldome
6dba06f9e6 fixes #14244 (#14248)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-06 20:43:18 +02:00
awr1
b70b8a7cdd Fix runnable examples for bitops (#14247) 2020-05-06 19:29:36 +02:00
Andreas Rumpf
c64db68f0b added a new feature: --cc:env so that you can use any C compiler as long as it works like GCC 2020-05-06 18:41:24 +02:00
Andreas Rumpf
1b2b32169a cleanup the CC setting, only leave in there what is at least semi-officially supported 2020-05-06 18:41:24 +02:00
Timothee Cour
330b3c4453 fix regression: -d:nimHasLibFFI was not being tested anymore (#14234)
* * fix regression: -d:nimHasLibFFI was not being tested anymore,
in part because testament was silently treating some errors as easy to overlook messages
* turned that message into an error
* -d:nimHasLibFFI is now being tested with nim cpp
* use correct signatures for importc procs
* workaround for openbsd to unblock ctffi testing
2020-05-06 17:16:54 +02:00
awr1
b8e6ea7547 Added bitslice operations for bitops (#14016)
* added bit operations based on bit slices, clarified documentation, made non-mutating versions of mask ops
* Added since annotations, some runnable examples
* Added mask()/masked() functions, changed internal workings of mask ops to use new bit* funcs
* Changelog updated for new bitops improvements
* Reorganization, added runnable examples
* Documentation adjustments
* Add incltrl for since annotation
* Fix masked() impl
* Fix mask() return type
* Don't call toUnsigned on already unsigned types
* Remove improper `var T` for flipMasked()
* Fix return types for flipMasked()
* Slight syntactic cleanup for *masked ops
* Added tests for bitslice operations, new mask() operation, non-mutating mask ops
* Fix setmasked() var T issue
* More comprehensive tests
* Fix runnable example for bitsliced()
* Fix runnable example for mask()
2020-05-06 12:21:49 +02:00
Oscar Nihlgård
48e7775ad1 Make the fields of times.DateTime private (#14197)
* Make the fields of `times.DateTime` private

* PR fixes
2020-05-06 12:20:34 +02:00
Timothee Cour
c28a057a6b fix js stacktraces, unify all file,line,col formatting into a single function (#14230)
* fix https://github.com/timotheecour/Nim/issues/135 ; unify all file,line,col formatting into a single function
2020-05-05 14:56:15 +02:00
hlaaftana
6b7b5fb4fa Clarify JS cstring len (#14184) 2020-05-05 10:34:37 +02:00
cooldome
eefada8a88 fix #14217 (#14218)
* fix #14217

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-05 07:26:32 +02:00
Andreas Rumpf
64e839d5fd fixes #14209 [backport:1.2] (#14213)
* fixes #14209 [backport:1.2]
* improve stability
2020-05-05 00:48:13 +02:00
cooldome
e86a6d24d5 vcc fix (#14222)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-05-04 19:42:29 +02:00
wltsmrz
c817e85f4c Linux updates (#14170)
* Add posix_memalign()

* Add linux-specific open() flags

O_TMPFILE: since Linux 3.11
O_PATH: since Linux 2.6.39
O_NOATIME: since Linux 2.6.8
O_DIRECT: since Linux 2.4.10

* Fix Stat type

* Fix POSIX AF_INET* const generation
2020-05-04 19:23:49 +02:00
PMunch
44f377ff5e Add procedures to read RSA keys from BIO format (#14223) 2020-05-04 19:23:11 +02:00
Timothee Cour
a23302ef56 fix https://github.com/timotheecour/Nim/issues/152: avoid writing spurious ^[[0m to stderr when callStyledWriteLineStderr not called (#14214)
* fix https://github.com/timotheecour/Nim/issues/152 `^[[0m` is inserted in stderr for `echo code | nim c -`

* resetAttributes not even needed, already handled in styledWriteLine

* simplify tests in tests/trunner.nim thanks to this fix
2020-05-04 15:07:32 +02:00
Tristram Oaten
927737975c Re-enabling INim (#14215) 2020-05-04 15:07:04 +02:00
rockcavera
603010f8c9 Fixes net.recvFrom to work correctly with IPv6 (#14131)
* added high level sendTo and recvFrom to std/asyncnet; tests were also added.
* add .since annotation, a changelog entry and fixed to standard library style guide.
* fixes net.recvFrom to work correctly with IPv6
* raise if domain is not AF_INET or AF_INET6
* renamed template to adaptRecvFromToDomain()
2020-05-04 11:54:08 +02:00
Timothee Cour
f115e40e6a echo cmd | nim r - -arg1 -arg2 now works (#14210) 2020-05-04 11:27:59 +02:00
Andreas Rumpf
a73d403901 sequtils refactoring: prefer typeof over type (#14212) 2020-05-04 11:18:29 +02:00
Andreas Rumpf
b6fb609e0d destructors: don't produce stupid code for 'cast' (#14208) [backport:1.2]
* destructors: don't produce stupid code for 'cast'

* fixes #14207
2020-05-04 07:43:22 +02:00
hlaaftana
3e060cfb0a => supports pragmas & names (+ changed behavior) (#14200)
* => supports pragmas & names (+ changed behavior)

(x, y: int) is now parsed as (x: int, y: int) instead of
(x: auto, y: int) inside => and ->.

* fix pragma check

* fixes, use since & LHS of -> supports pragmas
2020-05-03 10:22:49 +02:00
slangmgh
b56432bd8a fix #14203 (#14204) 2020-05-03 09:50:08 +02:00
slangmgh
d5c014e59b Fix #14151 (#14205) [backport] 2020-05-03 09:47:21 +02:00
slangmgh
b447ff7860 Fix #14201 (#14202) 2020-05-03 09:46:42 +02:00
Andreas Rumpf
49b28f1997 fixes #14136 (#14198) 2020-05-03 00:12:52 +02:00
hlaaftana
fbc97e712a move since from inclrtl to std/private/since (#14188)
* move since from inclrtl to std/private/since
* move since import in system below for HCR
2020-05-02 23:51:59 +02:00
Dien Tran
3be669be32 Move generated tex file to doc to correct location (#14191) 2020-05-02 23:49:08 +02:00
Araq
ff1c0bae4c update tests that tested for the 'discard' error messages 2020-05-02 22:31:19 +02:00
Araq
7f1d2489ad improve the 'has to be discarded' error message 2020-05-02 22:31:19 +02:00
Araq
87ac28d19a fixes #14159 [backport:1.2] 2020-05-02 22:31:19 +02:00
Araq
4301a7bdf0 fixes #14177 2020-05-02 22:31:19 +02:00
Araq
7bac6f5f9a don't close #14142 2020-05-02 22:31:19 +02:00
Araq
8e04ef3c0f closes #14142 2020-05-02 22:31:19 +02:00
Araq
15f54728ef fixes a bug encountered when running 'nim check posix_haiku.nim' 2020-05-02 22:31:19 +02:00
hlaaftana
f50377986a exp. features now in correct manual, closes #11932 (#14195) 2020-05-02 22:30:08 +02:00
Kaushal Modi
0880f118d3 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
2020-05-02 17:50:27 +02:00
Clyybber
83547ec769 Make unreachable else in case statements a warning instead of an error (#14190)
* Fix #14019 by making trailing else a warning

* Rename to UnreachableElse
2020-05-02 16:09:02 +02:00
Clyybber
1f1e4de3bc Make ./koch temp --gc:arc work (#14186) 2020-05-01 20:25:18 +02:00
Miran
9c33bcac5c change 'iff' to 'if' to stop "corrections" once and for all (#14182) 2020-05-01 15:54:03 +02:00
hlaaftana
9b01c6cf48 discardable async procs are now an error (#14176)
* add discard warning in manual
2020-05-01 09:49:13 +02:00
Andreas Rumpf
d5fc35c968 arc: do not unload globals when building a library [backport:1.2] (#14180) 2020-05-01 09:15:46 +02:00
rockcavera
33e9ac7cd3 fix sendTo and recvFrom in asyncnet (#14154)
* added high level sendTo and recvFrom to std/asyncnet; tests were also added.

* add .since annotation, a changelog entry and fixed to standard library style guide.

* Improved asserts msgs and added notes for use with UDP sockets

* pointers removed in parameters and fixes

* added .since annotation

* minor fixes
2020-04-30 22:50:37 +02:00
Araq
6b39b47abc hotfix: make tcompilerapi green again 2020-04-30 22:48:10 +02:00
Andreas Rumpf
89be5be03e fixes #13698 [backport:1.2] (#14175) 2020-04-30 22:45:02 +02:00
Araq
3d2459bdc0 fixes the regression #12860 caused; hotfix 2020-04-30 20:23:53 +02:00
Andreas Rumpf
cf3e0008b9 fixes #13986 [backport:1.2] (#14173) 2020-04-30 19:32:03 +02:00
hlaaftana
0aefebb728 JS unittest stacktrace fix, cleanup js repr and inclrtl includes (#14168) 2020-04-30 17:04:53 +01:00
narimiran
4d799f8820 test even more packages 2020-04-30 13:03:48 +02:00
narimiran
d844d10e8e [ci skip] clean-up CI badges 2020-04-30 10:19:18 +02:00
narimiran
f1068c01a8 [ci skip] prevent fail-fast on packages CI 2020-04-30 10:11:18 +02:00
Andreas Rumpf
cc60caedb3 fixes #14054 [backport:1.2] (#14061)
* fixes #14054

* make tests green again

* more tests are green

* maybe now
2020-04-30 06:48:57 +02:00
Clyybber
d6e1b5c070 Fix #14160 (#14161)
* Fix #14160

* Add testcase
2020-04-30 02:01:07 +02:00
Araq
bd57f0cd32 fixes another silly arc/orc bug [backport:1.2] 2020-04-29 22:14:01 +02:00
Andreas Rumpf
d9e907c0e2 fixes #14079 [backport:1.2] (#14163) 2020-04-29 21:58:59 +02:00
hlaaftana
707367e1ca many bugfixes for js (#14158)
* many bugfixes for js

fixes #12672, fixes #14153, closes #14123, closes #11331, fixes #11783, fixes #13966, fixes #14087, fixes #14117, closes #12256.

mostly fixes the fact that it was allowed to assign to newly created temp variables. additionally attempts to get rid of null initialized seqs/strings (though they might pop up here and there); this simplifies a lot of things and makes code size smaller. even if null seqs/strings pop up here and there it's still better than all those bugs existing.

* formatting fixes

* CI fixes

* more CI fixes
2020-04-29 20:55:09 +02:00
Tristram Oaten
a297c016fa Remove travis ci badge (#14062) 2020-04-29 17:06:14 +02:00
hlaaftana
800ce5b950 Fix negative indexed arrays for JS, refs #13966 (#14152)
* Fix negative arrays for JS, refs #13966

* small extra fix: no need to .slice() cstring in JS
2020-04-29 08:59:08 +02:00
cooldome
3b5a504692 parseEnum_regression (#14150)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-28 19:56:50 +02:00
Jacek Sieka
7d6cbf290a Error -> Defect for defects (#13908)
* Error -> Defect for defects

The distinction between Error and Defect is subjective,
context-dependent and somewhat arbitrary, so when looking at an
exception, it's hard to guess what it is - this happens often when
looking at a `raises` list _without_ opening the corresponding
definition and digging through layers of inheritance.

With the help of a little consistency in naming, it's at least possible
to start disentangling the two error types and the standard lib can set
a good example here.
2020-04-28 19:56:01 +02:00
hlaaftana
cd9af6b804 StringStream & more stdlib modules support for JS/NimScript (#14095)
* StringStream & more stdlib modules support for JS/NimScript

* change back pegs test in line with #14134
2020-04-28 19:44:52 +02:00
narimiran
d5ed4fba3e test packages with Github workflows 2020-04-28 18:14:34 +02:00
cooldome
289d48e5fe bug fix (#14149) [backport:1.2]
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-28 18:02:14 +02:00
narimiran
e63fc95bd4 fix tdistros test which was failing on Nightlies 2020-04-28 15:59:32 +02:00
hlaaftana
82fc66b607 Update grammar.txt with func and as (#14147) [backport] 2020-04-28 10:57:35 +02:00
Miran
e1dab59d46 add 14 more packages to 'important_packages' (#14141) 2020-04-28 07:28:48 +02:00
Andreas Rumpf
065a6af2de fixes a critical =trace generation bug (see test case) (#14140) 2020-04-27 22:20:14 +02:00
PMunch
2f1aad0264 Add RSA key reading and encrypt/decrypt to openssl (#14137)
This adds the procedures to read RSA keys and encrypt/decrypt messages
with both public and private keys.
2020-04-27 21:01:56 +02:00
Neelesh Chandola
d38853c504 Undefine paramCount & paramStr in nimscript.nim for *.nims (#12860)
* Remove `paramStr` and `paramCount` from implicitly imported nimscript.nim
* Update changelog.md
* Update stable nimble commit hash

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-04-27 19:16:40 +02:00
Timothee Cour
a3a317b76d $ now works for unsigned intergers with nim js (#14122)
* $(unsigned) now works for js
* move NimMajor+friends closer to NimVersion according as per reviewer feedback
2020-04-27 19:15:17 +02:00
PMunch
0e6eb96a5f Fix #14066 issue with stringifying incomplete types (#14135) 2020-04-27 18:43:02 +02:00
Timothee Cour
bb982c644b $(a: float) now works consistently in nim js, avoiding printing floats as ints (#14134)
* fix https://github.com/timotheecour/Nim/issues/133; $(a: float) works in nim js like in other backends

* fix tests

* fix test for windows that prints 1.1e17 differently than other OS
2020-04-27 17:33:03 +02:00
Oscar Nihlgård
664cb2c0be Remove some deprecated procs from std/times (#14129) 2020-04-27 14:42:29 +02:00
Timothee Cour
b8d7a98265 fix #14132 dsymutil should not be called on static libraries (#14133) [backport:1.2] 2020-04-27 12:39:27 +02:00
Andreas Rumpf
dedb04fa9e new implementations for --gc:orc (#14121)
* cycle collector: new implementation
* cycle collector: make self-adaptive based on its previous effectiveness
* cycle collector: added Lins's jump stack to improve traversal from 3*N to 2*N
* cycle collector: make tests green
* API extensions and bugfixes
* code cleanup and use --gc:orc for tasyncawait
2020-04-27 11:57:26 +02:00
cooldome
eaedd0cb94 add FileReader Web API to js dom (#14105)
* add FileReader to js dom
* minor improvement
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-27 00:08:11 +02:00
Timothee Cour
9384f7ad35 since now takes an optional patch, eg: since: (1, 3, 1) (#14124)
add tests for tinclrtl
2020-04-26 14:55:25 +02:00
rockcavera
d23446c6ba added high level sendTo and recvFrom to std/asyncnet (UDP functionality) (#14109)
* added high level sendTo and recvFrom to std/asyncnet; tests were also added.

* add .since annotation, a changelog entry and fixed to standard library style guide.

* Improved asserts msgs and added notes for use with UDP sockets
2020-04-26 10:16:10 +02:00
hlaaftana
76ffa4fa25 fixes #14112, tests for #12892, #12671, #11697 (#14125) 2020-04-26 10:12:16 +02:00
hlaaftana
31ba27590c small docs fix in typetraits (#14108) 2020-04-25 20:35:20 +02:00
Alexander Ivanov
56584414f3 Make await a template (#12085)
* Make await a template
* Generate await inside async/multisync
2020-04-25 20:27:03 +02:00
Christopher Dunn
caf30e7cb5 Faster readStr() (#14099)
* Faster readStr()

* https://github.com/nim-lang/Nim/issues/13857

* Add .since annotation and add to changelog

* Private, un-sinced proc for csource bootstrapping
2020-04-25 20:19:11 +02:00
Viktor Kirilov
018e297d66 HCR: properly handling complex const objects in the codegen - fixes #13915 (#14115) 2020-04-25 20:17:33 +02:00
Jae Yang
362c8964bf Fixes #14110 (#14111)
Fixes jsffi usage example in doc
2020-04-25 20:00:24 +02:00
cooldome
13fa338ada implement (#14114)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-25 19:59:56 +02:00
Euan
f3eeb3f921 Fix #14088 and #14089 on NetBSD (#14104)
* Set path to libSDL for NetBSD.

* Disable SFML test on NetBSD
2020-04-24 14:30:41 +02:00
Timothee Cour
706de1a566 add CI badges for CI github actions ssl+docs 2020-04-24 11:10:14 +01:00
Timothee Cour
d5b7e9902c fix nim CI; fix local testament (#14102) 2020-04-24 10:24:30 +02:00
Phil Krylov
d5d3594457 Add critbits.commonPrefixLen (#14072)
* Add critbits.commonPrefixLen

* add inline and since annotations, as well as a changelog entry

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-04-24 09:31:30 +02:00
hlaaftana
b2141fc2a1 changed type() to typeof() in docs and error messages (#14084) 2020-04-24 09:22:12 +02:00
alaviss
dd5ccc3e5a testament: don't try to test nimgrep if it's not there [backport:1.2] (#14085)
One more compiler source-specific tackled
2020-04-24 09:20:33 +02:00
hlaaftana
dff007f66d Make JS not mangle to snake_case (#14086) 2020-04-24 09:19:54 +02:00
Euan
123f9fb77a Fix #14091 and #14093 - test failures on NetBSD (#14096) 2020-04-24 09:18:44 +02:00
Timothee Cour
f07f07eef9 [ci skip] changelog conflicts are a thing of the past (#14098) 2020-04-24 09:16:20 +02:00
Timothee Cour
b18b1b0302 add CI badges for azure-pipelines for devel, 1.0, 1.2 branches (#14101) 2020-04-24 09:08:27 +02:00
Clyybber
eca8f1d79f Add tests for #8481, #6490 and #4061 (#14083) 2020-04-23 19:52:33 +02:00
Timothee Cour
66db9de714 CT sizeof(+friends) for {.importc, completeStruct.} types, enable ABI static checks (#13926)
* -d:checkabi obsolete (ABI check now enforced); add `addTypeHeader` helper
* cleanups
* import sizeof at CT for {.completeType.}
* address comments; revert default enabling of -d:checkAbi for now
* mimportc_size_check.nim => msizeof5.nim; merge mabi_check.nim into msizeof5.nim; refactor
* all pragmas in errmsgs should be written: '.importc' (un-ambiguous and less verbose than {.importc.})
2020-04-23 11:24:09 +02:00
Timothee Cour
5c534b2943 new cmd: nim r main [args...] to compile & run, saving binary under $nimcache/main (#13382)
* implement `nim r main` to compile and run, saving binary to $nimcache
* remove outFileAbs for now
2020-04-23 10:02:18 +02:00
alaviss
4b43d42b98 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.
2020-04-23 09:26:06 +02:00
Euan
0b4a475f2e Ref #14075 - enable two tests which seem to now be passing locally on FreeBSD. (#14076) 2020-04-22 23:35:22 +01:00
Keithcat1
d27bc03b21 Add LTO support for most compilers and do some VCC fixes (#14013)
* Added LTO in nim.cfg, added /link in extccomp.nim and other fixes

* Fix line endings

* Fix line endings, for real this time. Almost certainly. Like, 95% certain.

* Removed /MD from extccom.nim VCC comiler
2020-04-22 23:56:43 +02:00
Hiroki Noda
6cfe2e0c3d Set O_NONBLOCK flag atomically (#13934)
These flags were added in Linux 2.6.27, I'm not sure Nim's minimal
support Linux version.
2020-04-22 20:24:45 +02:00
Bung
e1cc0219de fix #14064 xmltree should allow create text node with raw text(non-es… (#14070)
* fix #14064 xmltree should allow create text node with raw text(non-escaped) eg. html style element's text

* change xnRawText to VerbatimText,newRawText to newVerbatimText ,add since anotation

* change changelog_1_2_0.md latest date

* move change log

Co-authored-by: bung87 <crc32@qq.com>
2020-04-22 19:46:55 +02:00
Chris Heller
6c0c882509 Make debugSend/debugRecv procs public. Fixes #12189 (#12190)
* Make debugSend/debugRecv procs public. Fixes #12189

* Make checkReply proc public. Part of #12189

* Add doc comments for debugSend,debugRecv and checkReply
2020-04-22 17:45:31 +02:00
wonderix
5571d48c32 Add the ability to pass title case headers to an HTTP server (#13968)
* Add the ability to pass title case headers to an HTTP server

* Remove unnecessary type spec of titleCase

* Replace convert member proc by isTitleCase

Co-authored-by: wonderix <wonderix@googlemail.com>
2020-04-22 17:43:39 +02:00
Andreas Rumpf
269a458d74 cycle collector (#14071)
* figured out the wrong cycle trace proc problem
* cycle collector/break refactorings and minor improvements
2020-04-22 17:34:35 +02:00
hlaaftana
01523b2b58 change some Exceptions to CatchableError or Defect, fixes #10288 (#14069) 2020-04-22 16:49:41 +02:00
Miran
5c26a83a4a use newer nodejs on Azure Pipelines (#14065) 2020-04-22 11:38:33 +02:00
Vindaar
d42c5a575d base parseEnum on a case statement, fixes #14030 (#14046)
* base `parseEnum` on a case statement, fixes #14030

* apply simplifactions / clean up, remove `norm` node, use strVal

* export `normalize` in json.nim

* cmp using nimIdentNormalize, error at CT if ambiguous enum found

`nimIdentNormalize` provided by @cooldome.

We track all names of the branches we have created so far and error if
a duplicate is found.

Dummy change to make github react...

* fix docstring of `nimIdentNormalize`

* make `typ` arg `typedesc`, add lineinfo, call norm. only once
2020-04-22 09:41:56 +01:00
Hessam Mehr
c3f4b93060 Treat zig like clang/gcc wrt integer arithmetic. (#13957) 2020-04-22 08:31:24 +02:00
alaviss
22418ce8fb 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.
2020-04-22 07:51:18 +02:00
Timothee Cour
eb6f523733 fix globalOptions (#14059) 2020-04-22 07:50:38 +02:00
Arnaud Moura
dc40fb805f Fix OS detection in a docker container (#13172)
* Support detection in docker container.
* Get only ID information in os-release.
* Add test to distros module.
* Fix Linux OS detection in Windows.
* Fix OS detection for FreeBSD and OpenBSD.
2020-04-22 07:49:42 +02:00
Andy Davidoff
9604a5a97a fix typo (#14063) 2020-04-21 23:23:15 -04:00
Timothee Cour
7ce0358351 fix #13222: make relativePath more robust and flexible (#13451)
* * relativePath(foo) now works
* relativePath(rel, abs) and relativePath(abs, rel) now work (fixes #13222)
* relativePath, absolutePath, getCurrentDir now available in more targets (eg: vm, nodejs etc)
* fix bug: isAbsolutePath now works with -d:js; add tests
* workaround https://github.com/nim-lang/Nim/issues/13469
* remove `relativePath(path)` overload for now
* add back changelog after rebase
2020-04-21 23:53:55 +02:00
Araq
dd24004fab cleanup PR #14048 2020-04-21 23:27:19 +02:00
Andreas Rumpf
1b6c4ed2ba fixes #14052 [backport:1.2] (#14055) 2020-04-21 23:19:34 +02:00
hlaaftana
5608a4e57b Add deques.peekFirst/Last(var Deque[T]) -> var T (#13542)
* Add deques.peekFirst/Last(var Deque[T]) -> var T
* Add changelog entry for deques.peekFirst/Last var T overloads
* Add since annotation to peekFirst/peekLast

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2020-04-21 22:09:19 +02:00
Arnaud Moura
cb2b9bd797 Add package install command for FreeBSD and OpenBSD. (#14051) 2020-04-21 22:07:19 +02:00
cooldome
5db0bb744c Replace enum fields idents with syms (#14048)
* replace enum fields idents with syms
* Trigger build

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-21 20:12:32 +02:00
Oscar Nihlgård
218cbf0e09 Times refactorings (#13949) 2020-04-21 17:07:37 +02:00
Euan
7828199827 #12103 - CI for OpenBSD (#12105)
* Working on OpenBSD CI
* Condense steps into 2 steps to make output easier to follow.
* Move up one directory after csources build.
* Remove FreeBSD build manifest and add OpenBSD test ignores for coroutines and hot code reloading.
* If runCI fails, run the test results script.
* Add email trigger for build failure
* Remove .git from repository URL
* Disable SFML test on OpenBSD
* Disable tgetaddrinfo on OpenBSD as only UDP and TCP protocols are supported.
* Remove getFilePermissions as it causes CI test failures with NimScript.
* Set clang as cc in nim.cfg and use gmake to build csources.
* Add getCurrentDir to nimscript.
* Remove duplicate getCurrentDir and check for not weirdTarget.
* Add CI badge for OpenBSD.
* Disable tests which allocate lots of memory for OpenBSD.
* Use `CORO_BACKEND_SETJMP` on OpenBSD rather than ucontext.
* Simplify building of koch
* Disable t8657 on OpenBSD. See issue #13760.
* Fix #12142 - tarray_of_channels fails on OpenBSD
* Disable thhtpclient_ssl and tosprocterminate on OpenBSD. These tests can be enabled at a later date after fixing them.
* Install libffi.
* Set path to libc for openbsd.
* Disable tevalffi for now.
* Remove tevalffi.nim.
* Use ncpuonline sysctl rather than ncpu.
* Disable tacceptcloserace and tasynchttpserver on OpenBSD.
* Enable tacceptcloserace and tasynchttpserver.
* Fix #13775 as suggested by @alaviss - use /bin/cat on OpenBSD rather than /bin/sh.
* Enable test on OpenBSD.
* Disable tflowvar on OpenBSD.
2020-04-21 15:05:21 +02:00
treeform
89e6a7ab48 Fix the getSelection method. (#13632) 2020-04-21 14:57:19 +02:00
Rory O’Kane
b8b0e9b21d docs: move not nil to the experimental page (#14027)
When I heard that this feature existed, and found the 2018 changelog entry that said `not nil` was made experimental (https://github.com/nim-lang/Nim/blob/devel/changelogs/changelog_0_19_0.md#changes-affecting-backwards-compatibility), I looked for `not nil` documentation in https://nim-lang.org/docs/manual_experimental.html. When I didn’t find it there, I initially assumed the feature had no documentation. This change moves the documentation to where readers will expect it.

As well as moving the text to another file, I added instructions for enabling the experimental feature and tweaked some wording.
2020-04-21 14:54:43 +02:00
Judd
04c326569b fix mapIt issues #12625 & #12639 (#14041)
* fix mapIt issues #12625 & #12639:

1. fallback to call `map` when the result of `op` is a closure;
2. use `items(s)` in the for loop.

* fix test errors.

* add comments and InType is moved.

* fix ident.
2020-04-21 14:50:16 +02:00
Tristram Oaten
1a44b7e3ce New runnableExample for newAsyncHttpClient() (#14045) 2020-04-21 14:47:06 +02:00
alaviss
7beed44fc9 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.
2020-04-21 11:21:36 +02:00
hlaaftana
3fe3db3c0d clarify tuples and objects in manual, fixes #12486 (#14044) 2020-04-21 11:21:12 +02:00
Tristram Oaten
42a64245f8 Fix broken async httpclient example
As the async httpclient is almost certainly the first async example beginners will want to try, we OWE it to them to give them a real example.

Example repeated here for clarity:

```nim
import asyncdispatch, httpclient

proc asyncProc(): Future[string] {.async.} =
  var client = newAsyncHttpClient()
  return await client.getContent("http://example.com")

echo waitFor asyncProc()
```

This is my first Nim contribution, please let me know if the code is right. (it runs on my machine, but may not be the best example)
2020-04-21 00:00:30 +01:00
Andreas Rumpf
67d71bb76d fixes #14038 2020-04-20 23:44:29 +02:00
alaviss
1bdc30bdb1 Make file descriptors from stdlib non-inheritable by default (#13201)
* io: make file descriptors non-inheritable by default

This prevents file descriptors/handles leakage to child processes
that might cause issues like running out of file descriptors, or potential
security issues like leaking a file descriptor to a restricted file.

While this breaks backward compatibility, I'm rather certain that not
many programs (if any) actually make use of this implementation detail.
A new API `setInheritable` is provided for the few that actually want to
use this functionality.

* io: disable inheritance at file creation time for supported platforms

Some platforms provide extension to fopen-family of functions to allow
for disabling descriptor inheritance atomically during File creation.
This guards against possible leaks when a child process is spawned
before we managed to disable the file descriptor inheritance
(ie. in a multi-threaded program).

* net, nativesockets: make sockets non inheritable by default

With this commit, sockets will no longer leak to child processes when
you don't want it to. Should solves a lot of "address in use" that might
occur when your server has just restarted.

All APIs that create sockets in these modules now expose a `inheritable`
flag that allow users to toggle inheritance for the resulting sockets.
An implementation of `setInheritance()` is also provided for SocketHandle.

While atomically disabling inheritance at creation time is supported on
Windows, it's only implemented by native winsock2, which is too much for
now. This support can be implemented in a future patch.

* posix: add F_DUPFD_CLOEXEC

This command duplicates file descriptor with close-on-exec flag set.

Defined in POSIX.1-2008.

* ioselectors_kqueue: don't leak file descriptors

File descriptors internally used by ioselectors on BSD/OSX are now
shielded from leakage.

* posix: add O_CLOEXEC

This flag allows file descriptors to be open() with close-on-exec flag
set atomically.

This flag is specified in POSIX.1-2008

* tfdleak: test for selectors leakage

Also simplified the test by using handle-type agnostic APIs to test for
validity.

* ioselectors_epoll: mark all fd created close-on-exec

File descriptors from ioselectors should no longer leaks on Linux.

* tfdleak: don't check for selector leakage on Windows

The getFd proc for ioselectors_select returns a hardcoded -1

* io: add NoInheritFlag at compile time

* io: add support for ioctl-based close-on-exec

This allows for the flag to be set/unset in one syscall. While the
performance gains might be negliable, we have one less failure point
to deal with.

* tfdleak: add a test for setInheritable

* stdlib: add nimInheritHandles to restore old behaviors

* memfiles: make file handle not inheritable by default for posix

* io: setInheritable now operates on OS file handle

On Windows, the native handle is the only thing that's inheritable, thus
we can assume that users of this function will already have the handle
available to them. This also allows users to pass down file descriptors
from memfiles on Windows with ease, should that be desired.

With this, nativesockets.setInheritable can be made much simpler.

* changelog: clarify

* nativesockets: document setInheritable return value

* posix_utils: atomically disable fd inheritance for mkstemp
2020-04-20 17:09:59 +02:00
Clyybber
6bd279c978 Fix #13972 (#14034) 2020-04-20 17:06:44 +02:00
cooldome
65c5367dc1 Fixes #14014 (#14029)
* add test

* improve test

* progress

* fix #14014

* fix bug

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-20 15:57:36 +02:00
Jasper Jenkins
ba0af0f827 allow generic typedesc field access (#12220)
Co-authored-by: Clyybber <darkmine956@gmail.com>
2020-04-20 15:36:57 +02:00
Lưu Danh, Hiếu
4476d8a2e0 Update code example to match new sdl2.nim syntax (#13924)
* Update code example to match new sdl2.nim syntax

Signed-off-by: Hieu Luu Danh <hieu@vivu.asia>

* Modify on recommendation of @alaviss

- Removed trailing whitespaces
- Detailed how to compile libnimhcr and libnimrtl
- Fixed some logic in example code

* Modify following recommendations of @alaviss

- Rewording so that it conforms to Windows/Linux/MacOS

Signed-off-by: Hieu Luu Danh <hieu@vivu.asia>
2020-04-20 14:49:05 +02:00
awr1
59aeaa1c98 Make bitand, bitor, bitxor varargs-friendly (#13985)
* made bitand, bitor, bitxor varargs friendly
* changed new bitops to macros
* changed macro signature for consistency (this technically doesn't matter)
* added tests
* removed redundant assert
* fix literal
2020-04-20 14:48:37 +02:00
Araq
59f1462b95 remove the nilChecks switch; refs #11570 2020-04-20 14:44:54 +02:00
Araq
4d1149cffd fix for asm statement; refs #12650 2020-04-20 14:44:54 +02:00
Araq
17f222613a refactor system.$ for objects a little; refs #13398 2020-04-20 14:44:54 +02:00
Timothee Cour
b2720317fa add --experimental:vmopsDanger; add generic conversion for vmops (#13813)
* add --experimental:vmopsDanger; vmops cleanups
2020-04-20 12:00:00 +02:00
alaviss
77834f0fda compiler/suggest: highlight squashed operators (#11796)
The operator fetching proc is greedy, so operators such as `%*` in
expression `%*{}` can't be highlighted.

This commit fixes that.
2020-04-20 11:54:53 +02:00
Araq
e6cf11351d unicode: minor documention improvement 2020-04-20 08:42:08 +02:00
Andreas Rumpf
242d39d27f fixes #12834 (#14017) 2020-04-19 14:42:45 +02:00
Andreas Rumpf
73eff1f457 fixes #12741 (#14005)
* fixes #12741
* updated tests
2020-04-19 11:59:01 +02:00
Andreas Rumpf
9874981e75 fixes #14001 (#14004) 2020-04-19 10:01:04 +02:00
Arne Döring
4005f0d0e4 forward type alignment information to seqs (#12430) 2020-04-19 07:52:01 +02:00
Andreas Rumpf
a8f030fea2 drnim: phi nodes for 'if' statements (#13990) 2020-04-19 02:41:16 +02:00
jiro
f1ee817627 Add runnableExamples to critbits module (#13994)
* doc: critbit: add runnableExamples

* doc: critbit: change to upper
2020-04-18 20:06:20 +02:00
hlaaftana
f46803b225 Fix unused warning for $ for empty tuple/objects (#13991) 2020-04-18 17:41:03 +02:00
Timothee Cour
e3919b658f 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
2020-04-18 16:22:03 +02:00
cooldome
d839eb9352 fix #14007 (#14012) [backport]
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-18 16:15:17 +02:00
cooldome
f10689d3d4 fixes #14003 (#14006) [backport:1.2]
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-17 13:23:04 +02:00
cooldome
d3b0132061 Step2: fixes #13781, fixes #13805 (#13897)
* Fix sym owner in wrapper proc
* threadpool changes
* revert lowerings
* add newFastMoveStmt
* try fixing test by switching to cpp

Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-16 23:27:08 +02:00
cooldome
9295251e68 Implements RFCs #209 (#13995)
* add test
* add changelod entry
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-16 21:04:05 +02:00
awr1
b6f99409a9 added extended msg for failed library loads w/ incorrect DLL formats (#13950)
* added extended msg for failed library loads w/ incorrect DLL formats

* missing colon

* fix GetLastError()

* make GetLastError() available for windows console apps

* remove premature nullchar if outputting extra message

* if-protect nullchar detection

* better fix for message box code
2020-04-16 20:23:54 +02:00
Miran
06e0c75ba9 make fuzzy search a bit less fuzzy (#13996) [backport:1.2] 2020-04-16 20:22:32 +02:00
Timothee Cour
6914de0d8d fix newDomParser (#13981) 2020-04-16 08:59:54 +02:00
Adam Weber
d72808520b Grammar correction in backends.rst (#13989)
I hate to be the guy that submits a couple grammatical/spelling corrections.
2020-04-16 00:39:44 -04:00
Andreas Rumpf
60ec5c89c5 added a .since annotation to hashIdentity 2020-04-15 23:35:10 +02:00
c-blake
a0b33f9408 Add hashWangYi1 (#13823)
* Unwind just the "pseudorandom probing" (whole hash-code-keyed variable
stride double hashing) part of recent sets & tables changes (which has
still been causing bugs over a month later (e.g., two days ago
https://github.com/nim-lang/Nim/issues/13794) as well as still having
several "figure this out" implementation question comments in them (see
just diffs of this PR).

This topic has been discussed in many places:
  https://github.com/nim-lang/Nim/issues/13393
  https://github.com/nim-lang/Nim/pull/13418
  https://github.com/nim-lang/Nim/pull/13440
  https://github.com/nim-lang/Nim/issues/13794

Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in
identity hashes) are a better solution that is more general (no illusion
of one hard-coded sequence solving all problems) while retaining the
virtues of linear probing such as cache obliviousness and age-less tables
under delete-heavy workloads (still untested after a month of this change).

The only real solution for truly adversarial keys is a hash keyed off of
data unobservable to attackers.  That all fits better with a few families
of user-pluggable/define-switchable hashes which can be provided in a
separate PR more about `hashes.nim`.

This PR carefully preserves the better (but still hard coded!) probing
of the  `intsets` and other recent fixes like `move` annotations, hash
order invariant tests, `intsets.missingOrExcl` fixing, and the move of
`rightSize` into `hashcommon.nim`.

* Fix `data.len` -> `dataLen` problem.

* This is an alternate resolution to https://github.com/nim-lang/Nim/issues/13393
(which arguably could be resolved outside the stdlib).

Add version1 of Wang Yi's hash specialized to 8 byte integers.  This gives
simple help to users having trouble with overly colliding hash(key)s.  I.e.,
  A) `import hashes; proc hash(x: myInt): Hash = hashWangYi1(int(x))`
      in the instantiation context of a `HashSet` or `Table`
or
  B) more globally, compile with `nim c -d:hashWangYi1`.

No hash can be all things to all use cases, but this one is A) vetted to
scramble well by the SMHasher test suite (a necessarily limited but far
more thorough test than prior proposals here), B) only a few ALU ops on
many common CPUs, and C) possesses an easy via "grade school multi-digit
multiplication" fall back for weaker deployment contexts.

Some people might want to stampede ahead unbridled, but my view is that a
good plan is to
  A) include this in the stdlib for a release or three to let people try it
     on various key sets nim-core could realistically never access/test
     (maybe mentioning it in the changelog so people actually try it out),
  B) have them report problems (if any),
  C) if all seems good, make the stdlib more novice friendly by adding
     `hashIdentity(x)=x` and changing the default `hash() = hashWangYi1`
     with some `when defined` rearranging so users can `-d:hashIdentity`
     if they want the old behavior back.
This plan is compatible with any number of competing integer hashes if
people want to add them.  I would strongly recommend they all *at least*
pass the SMHasher suite since the idea here is to become more friendly to
novices who do not generally understand hashing failure modes.

* Re-organize to work around `when nimvm` limitations; Add some tests; Add
a changelog.md entry.

* Add less than 64-bit CPU when fork.

* Fix decl instead of call typo.

* First attempt at fixing range error on 32-bit platforms; Still do the
arithmetic in doubled up 64-bit, but truncate the hash to the lower
32-bits, but then still return `uint64` to be the same.  So, type
correct but truncated hash value.  Update `thashes.nim` as well.

* A second try at making 32-bit mode CI work.

* Use a more systematic identifier convention than Wang Yi's code.

* Fix test that was wrong for as long as `toHashSet` used `rightSize` (a
very long time, I think).  `$a`/`$b` depend on iteration order which
varies with table range reduced hash order which varies with range for
some `hash()`.  With 3 elements, 3!=6 is small and we've just gotten
lucky with past experimental `hash()` changes.  An alternate fix here
would be to not stringify but use the HashSet operators, but it is not
clear that doesn't alter the "spirit" of the test.

* Fix another stringified test depending upon hash order.

* Oops - revert the string-keyed test.

* Fix another stringify test depending on hash order.

* Add a better than always zero `defined(js)` branch.

* It turns out to be easy to just work all in `BigInt` inside JS and thus
guarantee the same low order bits of output hashes (for `isSafeInteger`
input numbers).  Since `hashWangYi1` output bits are equally random in
all their bits, this means that tables will be safely scrambled for table
sizes up to 2**32 or 4 gigaentries which is probably fine, as long as the
integer keys are all < 2**53 (also likely fine).  (I'm unsure why the
infidelity with C/C++ back ends cut off is 32, not 53 bits.)

Since HashSet & Table only use the low order bits, a quick corollary of
this is that `$` on most int-keyed sets/tables will be the same in all
the various back ends which seems a nice-to-have trait.

* These string hash tests fail for me locally.  Maybe this is what causes
the CI hang for testament pcat collections?

* Oops. That failure was from me manually patching string hash in hashes.  Revert.

* Import more test improvements from https://github.com/nim-lang/Nim/pull/13410

* Fix bug where I swapped order when reverting the test.  Ack.

* Oh, just accept either order like more and more hash tests.

* Iterate in the same order.

* `return` inside `emit` made us skip `popFrame` causing weird troubles.

* Oops - do Windows branch also.

* `nimV1hash` -> multiply-mnemonic, type-scoped `nimIntHash1` (mnemonic
resolutions are "1 == identity", 1 for Nim Version 1, 1 for
first/simplest/fastest in a series of possibilities.  Should be very
easy to remember.)

* Re-organize `when nimvm` logic to be a strict `when`-`else`.

* Merge other changes.

* Lift constants to a common area.

* Fall back to identity hash when `BigInt` is unavailable.

* Increase timeout slightly (probably just real-time perturbation of CI
system performance).
2020-04-15 20:11:18 +02:00
Andreas Rumpf
3a2697dd73 drnim: tiny progress (#13882)
* drnim: tiny progress
* refactoring complete
* drnim: prove .ensures annotations
* Moved code around to avoid code duplication
* drnim: first implementation of the 'old' property
* drnim: be precise about the assignment statement
* first implementation of --assumeUnique
* progress on forall/exists handling
2020-04-15 20:03:25 +02:00
Miran
04b6e9cf3e add timezones package to important_packages (#13987) 2020-04-15 17:33:16 +02:00
Timothee Cour
4764220cfb Fix https://github.com/inim-repl/INim/issues/66 (#13984) 2020-04-15 13:07:18 +02:00
Timothee Cour
2c93d1684e enable important_pkg on OSX (#13954)
* enable important_pkg on OSX

* disable some important_packages on OSX

* fixup

* enable nigui by installing dependency
2020-04-14 15:00:35 +02:00
Timothee Cour
10eabec6d4 fix #12864 static params were mutating arg types during sigmatch; fix #12713 ; refs #13529 (#13976)
* fix #12864 static params were mutating arg types during sigmatch

* fix test

* fix StaticParam

* also fixes #12713; added test case
2020-04-14 15:00:02 +02:00
Juan Carlos
c269964860 Add Data URI Base64, implements RFC-2397 (#13759)
* Add Data URI Base64, implements RFC-2397

* Add Data URI Base64, implements RFC-2397

* Add Data URI Base64, implements RFC-2397

* https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420

* https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420

* ReSync changelog

* https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420

Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>
2020-04-13 14:15:45 +01:00
Juan Carlos
0a84219b3e Add jsdomparser (#13920)
* Add jsdomparser

* Add jsdomparser

* Add jsdomparser

* https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142

* https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142

* https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142

* https://github.com/nim-lang/Nim/pull/13920#discussion_r405932909

* https://github.com/nim-lang/Nim/pull/13920#discussion_r406502592
2020-04-13 14:07:52 +01:00
Oscar Nihlgård
255698deee Fix semfold handling of {.str/int/bool-define.} (#13964) 2020-04-13 14:22:33 +02:00
jiro
40b64ccd7b Add runnableExamples to bitops module (#13951)
* doc: bitops: add runnableExamples

* doc: bitops: add notes to documentation comments of macros

* doc: bitops: add periods to documentation comments

* doc: bitops: add static

* Revert "doc: bitops: add static"

This reverts commit 595ee134ab.

* doc: bitops: add `var` to arguments of macros

* doc: bitops: remove examples of testBit
2020-04-13 14:21:45 +02:00
cooldome
8ba915e449 error msg for #13864 (#13962)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-13 14:17:22 +02:00
Timothee Cour
814f150184 fix #13848: make var result work with nim cpp (#13959)
* fix #13848

* add exhaustive tests for var result
2020-04-13 14:16:06 +02:00
narimiran
2ef39081e1 minor fixes in 1.2 changelog [ci skip] 2020-04-13 08:12:27 +02:00
genotrance
35b046373a Improve #12920 fix (#13958) 2020-04-12 21:08:16 +02:00
Juan Carlos
7238b968f3 Make unused code into actual test, replace echo with doassert (#13952) 2020-04-11 22:16:26 +02:00
alaviss
5f6962337d osproc: added a better version of waitForExit for Haiku (#13938)
Also modified tosprocterminate to verify waitForExit implementations.
2020-04-10 09:34:52 +02:00
alaviss
cc3f5d21b2 posix: add full Haiku support (#13931)
* posix: add full Haiku support

This commit provides a posix_haiku derived from posix_other, with types
following Haiku's definition. This fixes cases where the compiler
generates type check for the wrong types (ie. checks where generated for
an int-derived type but it's actually implemented as an uint instead).

* tools/kochdocs: welcome posix_haiku to the blacklist
2020-04-09 15:56:08 +02:00
cooldome
7b582fd6a6 fixes #13863 (#13929)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-08 19:51:23 +02:00
Hessam Mehr
bff742cd8b Add support for zig cc as C compiler. (#13757) 2020-04-08 15:24:14 +02:00
Dominik Picheta
350ee0308a 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`.
2020-04-08 14:37:00 +02:00
Miran
3dc8068075 Test packages on Linux (#13921)
* test important packages on Linux

* enable chronos
2020-04-08 14:34:08 +02:00
cooldome
b4e9f8e814 fix ICE in isUnresolvedSym (#13925)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-08 13:16:25 +01:00
cooldome
f86fc5316a fix #13909 (#13914) [backport:1.2]
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-08 11:28:09 +02:00
Timothee Cour
95fd8ae93c 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>
2020-04-08 09:56:16 +02:00
narimiran
3036ec9c44 fix #13894, httpclient hang on Http204 2020-04-07 22:21:39 +01:00
cooldome
c835c8c4e7 fix #13910 (#13917)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-07 19:40:14 +02:00
Timothee Cour
ab5e26c53c fix some codegen bugs: NIM_BOOL, NIM_STATIC_ASSERT, --passc:-std=... (etc) (#13798)
* fix cgen bool D20200328T203812
* --passc:std=c++17 (etc) now works instead of silently ignored
* document caveats for NIM_NIL
2020-04-07 15:17:30 +02:00
Nicolai Søborg
b41931bf67 json doc: Note about Option and reserved keywords (#13895) 2020-04-07 15:14:25 +02:00
Arne Döring
37692baf49 fix #13739 (#13742) 2020-04-07 14:42:59 +02:00
Clyybber
92c4aad205 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>
2020-04-06 16:25:24 +02:00
Clyybber
1e25e16c88 Fix #13872 (#13898) 2020-04-06 14:35:27 +01:00
Timothee Cour
e6d870896b openDefaultBrowser now works on OSX (#13892) [backport] 2020-04-06 08:26:12 +02:00
Timothee Cour
f1fd3ef7f4 fix https://github.com/timotheecour/Nim/issues/88 (#13865) [backport:1.2] 2020-04-06 00:24:35 +02:00
supakeen
87847150bf Add barebones asynchttpserver tests (#13883)
* Add isNil check to custom Content-Length.

Related to #13866.

* Setup barebones asynchttpserver tests.
2020-04-05 21:16:13 +02:00
Hiroki Noda
b6814be653 doc: fix comment for repr*(x: char): string (#13873)
replace `$` with `repr`.
2020-04-05 16:44:55 +02:00
Timothee Cour
29734b73ff add nimPath to nim dump (#13876)
* add nimPath to nim dump

* rename
2020-04-05 16:44:34 +02:00
cooldome
6d4f07f2ea Fix sym owner in wrapper proc (#13878)
Co-authored-by: cooldome <ariabushenko@bk.ru>
2020-04-05 16:44:15 +02:00
supakeen
09ca19208f Add isNil check to custom Content-Length. (#13867) [backport:1.2]
Related to #13866.
2020-04-05 09:02:30 +02:00
alaviss
813ed358bf asyncdispatch: get rid of erroneous set constructions (#13877)
Ref #13764
2020-04-05 08:39:43 +02:00
Andreas Rumpf
a890aa75aa finally de-deprecate the .define and .undef pragmas 2020-04-04 23:12:24 +02:00
Andreas Rumpf
9c46927fad new feature: ability to turn specific warnings to errors 2020-04-04 22:56:03 +02:00
narimiran
ed44e524b0 bump devel version to 1.3.1 2020-04-03 21:28:11 +02:00
Alexander Ivanov
cec320b569 Remove my wrongly written mangled-related code, not needed anymore (#13858) 2020-04-03 20:22:03 +02:00
865 changed files with 38036 additions and 13299 deletions

34
.builds/openbsd_0.yml Normal file
View File

@@ -0,0 +1,34 @@
## 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.git
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>

34
.builds/openbsd_1.yml Normal file
View File

@@ -0,0 +1,34 @@
## 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.git
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>

34
.builds/openbsd_2.yml Normal file
View File

@@ -0,0 +1,34 @@
## 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.git
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>

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
# Avoids changelog conflicts by assuming additions-only, which is by far the common case.
# In the rare case where branch b1 rebases against branch b2 and both branches
# modified the same changelog entry, you'll end up with that changelog entry
# duplicated, which is easily identifiable and fixable.
/changelog.md merge=union

View File

@@ -12,9 +12,14 @@ 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!
```
@@ -29,12 +34,18 @@ 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 Normal file
View File

@@ -0,0 +1,69 @@
# 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,22 +1,37 @@
name: Nim Docs CI
on:
push:
# Run only on changes on these files
paths:
- 'lib/**.nim'
- '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'
- '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:
@@ -111,17 +126,14 @@ 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' &&

85
.github/workflows/ci_packages.yml vendored Normal file
View File

@@ -0,0 +1,85 @@
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-18.04, macos-10.15]
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 "::add-path::${{ github.workspace }}/dist/mingw64/bin"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "::add-path::${{ github.workspace }}/bin"
- 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,6 +12,8 @@ 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,6 +66,7 @@ testament.db
/tests/**/*.js
/csources
/dist/
/lib/fusion
# Private directories and files (IDEs)
.*/
@@ -82,6 +83,8 @@ megatest.nim
/outputExpected.txt
/outputGotten.txt
/t15148.txt
/tests/vm/tfile_rw.txt
/lib/pure/*.js
@@ -92,7 +95,8 @@ 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

@@ -27,13 +27,19 @@ jobs:
vmImage: 'macOS-10.15'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64:
Windows_amd64_batch0_3:
vmImage: 'windows-2019'
CPU: amd64
Windows_amd64_pkg:
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
CPU: amd64
NIM_TEST_PACKAGES: true
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
pool:
vmImage: $(vmImage)
@@ -47,14 +53,15 @@ jobs:
condition: eq(variables['Agent.OS'], 'Windows_NT')
- checkout: self
fetchDepth: 1
- bash: git clone --depth 1 https://github.com/nim-lang/csources.git
displayName: 'Checkout csources'
- bash: git clone --depth 1 https://github.com/nim-lang/csources
displayName: 'Checkout Nim csources'
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install node.js 8.x'
versionSpec: '12.x'
displayName: 'Install node.js 12.x'
- bash: |
sudo apt-fast update -qq
@@ -67,19 +74,12 @@ jobs:
- bash: |
sudo dpkg --add-architecture i386
# Downgrade llvm, libgcc and libstdc++:
# Downgrade llvm:
# - llvm has to be downgraded to have 32bit version installed for sfml.
# - libgcc and libstdc++ have to be downgraded as an optimization to
# prevent the use of the toolchain ppa, which has a terrible download
# speed.
cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel
Package: libllvm6.0 libgcc1 libstdc++6
Package: libllvm6.0
Pin: origin "azure.archive.ubuntu.com"
Pin-Priority: 1001
Package: *
Pin: release o=LP-PPA-ubuntu-toolchain-r-test
Pin-Priority: 100
EOF
sudo apt-fast update -qq
@@ -135,8 +135,18 @@ jobs:
make -v
displayName: 'System information'
- bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)"
displayName: 'Get csources version'
- task: Cache@2
inputs:
key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)'
path: csources/bin
displayName: 'Restore built csources'
- bash: |
ncpu=
ext=
case '$(Agent.OS)' in
'Linux')
ncpu=$(nproc)
@@ -146,19 +156,25 @@ jobs:
;;
'Windows_NT')
ncpu=$NUMBER_OF_PROCESSORS
ext=.exe
;;
esac
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
make -C csources -j $ncpu CC=gcc ucpu=$(CPU)
displayName: 'Build csources'
if [[ -x csources/bin/nim$ext ]]; then
echo "Found cached compiler, skipping build"
else
make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no
fi
cp csources/bin/nim$ext bin
displayName: 'Build 1-stage compiler from csources'
- bash: nim c koch
displayName: 'Build koch'
# set result to omit the "bash exited with error code '1'" message
- bash: |
./koch runCI || echo '##vso[task.complete result=Failed]'
- bash: ./koch runCI || echo '##vso[task.complete result=Failed]'
displayName: 'Run CI'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

View File

@@ -5,17 +5,15 @@ 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" ]]; then
which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from homebrew."; exit 1)
READLINK=greadlink
if [[ "$(uname -s)" == "Darwin" || "(uname -s)" == *"BSD" ]]; then
NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim))))
else
which readlink > /dev/null || (echo "readlink not in PATH."; exit 1)
READLINK=readlink
NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim))))
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

0
build_all.sh Normal file → Executable file
View File

View File

@@ -1,15 +1,18 @@
# v1.4.0 - yyyy-mm-dd
# v1.6.x - yyyy-mm-dd
## Standard library additions and changes
## Language changes
## Compiler changes
## Tool changes

View File

@@ -2,7 +2,6 @@
## 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`,
@@ -33,7 +32,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.
@@ -53,6 +52,8 @@
was designed for it. For example:
```nim
import std/with
type
Foo = object
col, pos: string
@@ -113,8 +114,6 @@ 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),
@@ -128,8 +127,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.
@@ -138,25 +137,33 @@ 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++.
- `=sink` type bound operator is now optional. Compiler can now use combination
of `=destroy` and `copyMem` to move objects efficiently.
- The `=sink` type bound operator is now optional. The compiler can now use a
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.
- New syntax for lvalue references: `var b {.byaddr.} = expr` enabled by
- There is a 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
- Generated JS code uses spaces, instead of mixed spaces and tabs.
- The generated JS code uses spaces, instead of mixing 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
@@ -192,10 +199,6 @@ echo f
with `-d:nimEmulateOverflowChecks`.
## Tool changes
- Nimpretty doesn't accept negative indentation argument anymore, because it was
breaking files.
## Bugfixes

View File

@@ -0,0 +1,886 @@
# 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 `Joptions` parameter to `jsonutils.fromJson` procedure 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 accept primary key column name.
- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text.
- `uri` adds Data URI Base64, 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` 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.
- `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`.
- Removed `sugar.distinctBase`, deprecated since `0.19`.
- Export `asyncdispatch.PDispatcher.handles` so that an external library can register them.
- `std/with`, `sugar.dup` now support object field assignment expression:
```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` module for `startProcess` convenience.
- Added the below `to` 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 readability `=copy` without loss of compatibility.
- 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)
```
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. 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. 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 `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop.
- Removed `strutils.isNilOrWhitespace`, was deprecated.
- Removed `sharedtables.initSharedTable`, was deprecated and produces undefined behavior.
- Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`.
- Removed `dom.releaseEvents` and `dom.captureEvents`, was deprecated.
- 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](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 a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased
performance this keyword can enable.
- `items` no longer compiles with enum 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 a `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 output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to
avoid recompiling when sources don't change. This is now the preferred way to
run tests, avoiding the usual pain of clobbering your repo with binaries or
using tricky gitignore rules on posix. Example:
```nim
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`.
- 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.
- new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change backend; can be
used with any command (eg nim r, doc, check etc); safe to re-assign.
- 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.
- new flag `--usenimcache` to output to nimcache (whatever it resolves to after
all commands are processed)
and avoids polluting both $pwd and $projectdir. It can be used with any command.
- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override
how an example is compiled and run, for example to change backend or compile only.
- `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` will now return both the forward declaration and the
implementation location upon a `def` query. Previously the behavior was
just to return the forward declaration.
## 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))
Was unsure about: " add testcase for #4668 (#14946)"
- 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,21 +17,21 @@ export int128
type
TCallingConvention* = enum
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
ccNimCall # nimcall, also the default
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)
ccThisCall # thiscall (parameters are pushed right-to-left)
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"]
const CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall",
"closure", "noconv"]
type
TNodeKind* = enum # order is extremely important, because ranges are used
@@ -218,7 +218,7 @@ type
nkEnumFieldDef, # `ident = expr` in an enumeration
nkArgList, # argument list
nkPattern, # a special pattern; used for matching
nkHiddenTryStmt, # token used for interpretation
nkHiddenTryStmt, # a hidden try statement
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)
@@ -229,7 +229,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 42 flags!
TSymFlag* = enum # 46 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
@@ -290,8 +290,11 @@ 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 OverflowError
sfNeverRaises # proc can never raise an exception, not even OverflowDefect
# 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]
@@ -310,10 +313,6 @@ 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
@@ -432,8 +431,9 @@ type
# instantiation and prior to this it has the potential to
# be any type.
tyOpt
# Builtin optional type
tyOptDeprecated
# 'out' parameter. Comparable to a 'var' parameter but every
# path must assign a value to it before it can be read from.
tyVoid
# now different from tyEmpty, hurray!
@@ -553,6 +553,10 @@ 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 +613,7 @@ var
type
TMagic* = enum # symbols that require compiler magic:
mNone,
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mDefined, mDeclared, mDeclaredInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait,
mIs, mOf, mAddr, mType, mTypeOf,
mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic,
@@ -652,8 +656,8 @@ type
mSwap, mIsNil, mArrToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy,
mDefault, mUnown, mAccessEnv, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
mDefault, mUnown, mIsolate, mAccessEnv, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal,
mInt, mInt8, mInt16, mInt32, mInt64,
@@ -677,7 +681,7 @@ type
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo,
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
mSymIsInstantiationOf, mNodeId
@@ -1026,6 +1030,7 @@ const
nkFloatLiterals* = {nkFloatLit..nkFloat128Lit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef}
procDefs* = nkLambdaKinds + declarativeDefs
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
@@ -1113,12 +1118,49 @@ 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
@@ -1219,43 +1261,6 @@ 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
@@ -1288,7 +1293,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
@@ -1326,7 +1331,7 @@ const
MaxLockLevel* = 1000'i16
UnknownLockLevel* = TLockLevel(1001'i16)
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=destroy", "=", "=sink", "=trace", "=dispose", "=deepcopy"]
"=destroy", "=copy", "=sink", "=trace", "=dispose", "=deepcopy"]
proc `$`*(x: TLockLevel): string =
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
@@ -1352,9 +1357,9 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
writeStackTrace()
proc mergeLoc(a: var TLoc, b: TLoc) =
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.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.lode == nil: a.lode = b.lode
if a.r == nil: a.r = b.r
@@ -1379,7 +1384,7 @@ proc assignType*(dest, src: PType) =
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:
dest.sym.flags = dest.sym.flags + (src.sym.flags-{sfExported})
dest.sym.flags.incl src.sym.flags-{sfExported}
if dest.sym.annex == nil: dest.sym.annex = src.sym.annex
mergeLoc(dest.sym.loc, src.sym.loc)
else:
@@ -1398,9 +1403,6 @@ 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
@@ -1486,8 +1488,7 @@ proc isGCedMem*(t: PType): bool {.inline.} =
t.kind == tyProc and t.callConv == ccClosure
proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) =
const HaveTheirOwnEmpty = {tySequence, tyOpt, tySet, tyPtr, tyRef, tyProc}
owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime})
owner.flags.incl elem.flags * {tfHasMeta, tfTriggersCompileTime}
if tfNotNil in elem.flags:
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
owner.flags.incl tfNotNil
@@ -1499,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, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}:
tySequence, tySet, tyDistinct, tyOpenArray, tyVarargs}:
o2.flags.incl mask
owner.flags.incl mask
@@ -1749,7 +1750,7 @@ proc isRoutine*(s: PSym): bool {.inline.} =
proc isCompileTimeProc*(s: PSym): bool {.inline.} =
result = s.kind == skMacro or
s.kind == skProc and sfCompileTime in s.flags
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
proc isRunnableExamples*(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
@@ -1796,12 +1797,12 @@ proc skipStmtList*(n: PNode): PNode =
else:
result = n
proc toVar*(typ: PType): PType =
proc toVar*(typ: PType; kind: TTypeKind): 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 != tyVar:
result = newType(tyVar, typ.owner)
if typ.kind != kind:
result = newType(kind, typ.owner)
rawAddSon(result, typ)
proc toRef*(typ: PType): PType =
@@ -1833,8 +1834,14 @@ 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 =
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
# n.typ == nil: see issue #14802
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
return n
for son in n:
@@ -1851,6 +1858,10 @@ 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}
@@ -1928,3 +1939,6 @@ 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

@@ -591,10 +591,17 @@ proc value(this: var DebugPrinter; value: PNode) =
if this.conf != nil:
this.key "info"
this.value $lineInfoToStr(this.conf, value.info)
if card(value.flags) > 0:
if value.flags != {}:
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"
@@ -1048,3 +1055,7 @@ proc listSymbolNames*(symbols: openArray[PSym]): string =
result.add ", "
result.add sym.name.s
proc isDiscriminantField*(n: PNode): bool =
if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags
elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags
else: false

View File

@@ -79,6 +79,9 @@ 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):
@@ -132,8 +135,7 @@ proc `$`[Key, Val](b: BTree[Key, Val]): string =
result = ""
toString(b.root, "", result)
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool =
result = index < b.entries
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = index < b.entries
proc countSubTree[Key, Val](it: Node[Key, Val]): int =
if it.isInternal:

View File

@@ -21,11 +21,39 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
# we have to be *very* conservative:
result = canRaiseConservative(n)
proc leftAppearsOnRightSide(le, ri: PNode): bool =
proc preventNrvo(p: BProc; le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
var n = le
while true:
# do NOT follow nkHiddenDeref here!
case n.kind
of nkSym:
# we don't own the location so it escapes:
if n.sym.owner != p.prc:
return true
elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags:
# it is also an observable store if the location is used
# in 'except' or 'finally'
return true
return false
of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
nkCheckedFieldExpr:
n = n[0]
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
n = n[1]
else:
# cannot analyse the location; assume the worst
return true
if le != nil:
for i in 1..<ri.len:
let r = ri[i]
if isPartOf(le, r) != arNo: return true
# we use the weaker 'canRaise' here in order to prevent too many
# annoying warnings, see #14514
if canRaise(ri[0]) and
locationEscapes(p, le, p.nestedTryStmts.len > 0):
message(p.config, le.info, warnObservableStores, $le)
proc hasNoInit(call: PNode): bool {.inline.} =
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
@@ -51,7 +79,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
if isInvalidReturnType(p.config, typ[0]):
if params != nil: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
# Great, we can use 'd':
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
@@ -113,9 +141,61 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
proc openArrayLoc(p: BProc, n: PNode): Rope =
var a: 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 q = skipConv(n)
var skipped = false
while q.kind == nkStmtListExpr and q.len > 0:
@@ -129,41 +209,26 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
for i in 0..<q.len-1:
genStmts(p, q[i])
q = q.lastSon
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 = "($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:
if skipTypes(n.typ, abstractInst).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))
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result = x & ", " & y
else:
initLocExpr(p, n, a)
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar).kind
of tyOpenArray, tyVarargs:
result = "$1, $1Len_0" % [rdLoc(a)]
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)]
else:
result = "$1, $1Len_0" % [rdLoc(a)]
of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar and
not compileToCpp(p.module):
let ntyp = skipTypes(n.typ, abstractInst)
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.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):
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
@@ -183,22 +248,31 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
if needsTmp and a.lode.typ != nil:
var tmp: TLoc
getTemp(p, a.lode.typ, tmp, needsInit=false)
genAssignment(p, tmp, a, {})
tmp
else:
a
proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} =
var a: TLoc
initLocExpr(p, n[0], a)
result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc])
ropecg(p.module, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n)
result = genArgStringToCString(p, n, needsTmp)
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
result = openArrayLoc(p, n)
result = openArrayLoc(p, param.typ, n)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
initLocExpr(p, n, a)
result = addrLoc(p.config, a)
elif p.module.compileToCpp and param.typ.kind == tyVar and
result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp))
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a)
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
@@ -212,26 +286,85 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
result = rdLoc(a)
else:
initLocExprSingleUse(p, n, a)
result = rdLoc(a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp))
proc genArgNoParam(p: BProc, n: PNode): Rope =
proc genArgNoParam(p: BProc, n: PNode, needsTmp = false): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n)
result = genArgStringToCString(p, n, needsTmp)
else:
initLocExprSingleUse(p, n, a)
result = rdLoc(a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp))
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))
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)
else:
if params != nil: params.add(~", ")
params.add(genArgNoParam(p, ri[i]))
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]))
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
@@ -242,13 +375,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)
for i in 1..<ri.len:
genParamLoop(params)
var params = genParams(p, ri, typ)
var callee = rdLoc(op)
if p.hcrOn and ri[0].kind == nkSym:
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
@@ -256,23 +389,21 @@ 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 =
result = if r == nil: r else: r & ~", "
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
var typ = skipTypes(ri[0].typ, abstractInst)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
for i in 1..<ri.len:
assert(typ.len == typ.n.len)
genParamLoop(pl)
assert(typ.len == typ.n.len)
var pl = genParams(p, ri, typ)
template genCallPattern {.dirty.} =
if tfIterator in typ.flags:
@@ -280,13 +411,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
else:
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
let rawProc = getRawProcType(p, typ)
let rawProc = getClosureType(p.module, typ, clHalf)
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
if typ[0] != nil:
if isInvalidReturnType(p.config, typ[0]):
if ri.len > 1: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
# Great, we can use 'd':
if d.k == locNone:
getTemp(p, typ[0], d, needsInit=true)
@@ -338,7 +469,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 == tyVar and ri[i].kind == nkHiddenAddr:
elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr:
result = genArgNoParam(p, ri[i][0])
else:
result = genArgNoParam(p, ri[i]) #, typ.n[i].sym)
@@ -415,7 +546,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 == tyVar:
if t.kind in {tyVar}:
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.typ.kind == tyPtr:
result = genArgNoParam(p, x)
@@ -610,18 +741,33 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
pl.add(~"];$n")
line(p, cpsStmts, pl)
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 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 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:
@@ -631,3 +777,5 @@ 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

@@ -126,9 +126,8 @@ 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))
toBitSet(p.config, n, cs)
let cs = toBitSet(p.config, n)
if size > 8:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
@@ -141,6 +140,7 @@ 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
@@ -266,10 +266,38 @@ 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), genTypeInfo(p.module, dest.t, dest.lode.info)])
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(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), genTypeInfo(p.module, dest.t, dest.lode.info)])
[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)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating
@@ -290,7 +318,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),
genTypeInfo(p.module, dest.t, dest.lode.info)])
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tyString:
if optSeqDestructors in p.config.globalOptions:
genGenericAsgn(p, dest, src, flags)
@@ -349,11 +377,13 @@ 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 containsGarbageCollectedRef(dest.t):
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src)
elif 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),
genTypeInfo(p.module, dest.t, dest.lode.info)])
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
else:
linefmt(p, cpsStmts,
# bug #4799, keep the nimCopyMem for a while
@@ -361,7 +391,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
"$1 = $2;$n",
[rdLoc(dest), rdLoc(src)])
of tySet:
if mapType(p.config, ty) == ctArray:
if mapSetType(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:
@@ -395,18 +425,23 @@ 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),
genTypeInfo(p.module, dest.t, dest.lode.info)])
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tySequence, tyString:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)])
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)])
of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info)])
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tySet:
if mapType(p.config, ty) == ctArray:
if mapSetType(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:
@@ -675,11 +710,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 == tyVar and
skipTypes(typ, abstractInstOwned).kind in {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)
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
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?
@@ -692,7 +727,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 == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
initLocExprSingleUse(p, e[0][0], d)
return
else:
@@ -715,7 +750,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 == tyVar and tfVarIsPtr notin typ.flags and
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and
e.kind == nkHiddenDeref:
putIntoDest(p, d, e, rdLoc(a), a.storage)
return
@@ -729,6 +764,17 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
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}:
@@ -736,7 +782,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) == ctArray or isCppRef(p, e.typ):
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ):
expr(p, e[0], d)
else:
var a: TLoc
@@ -821,7 +867,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 = genFieldError(field, disc.sym)
let msg = genFieldDefect(field, disc.sym)
let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg))
if op.magic == mNot:
linefmt(p, cpsStmts,
@@ -894,10 +940,16 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
case ty.kind
of tyOpenArray, tyVarargs:
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)])
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)])
of tyArray:
let first = intLiteral(firstOrd(p.config, ty))
linefmt(p, cpsStmts,
@@ -914,13 +966,22 @@ 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) # 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)
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)
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
@@ -930,7 +991,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) or optLaxStrings in p.options):
if ty.kind == tyString and not defined(nimNoZeroTerminator):
linefmt(p, cpsStmts,
"if ((NU)($1) > (NU)$2){ #raiseIndexError2($1,$2); $3}$n",
[rdLoc(b), lenExpr(p, a), raiseInstr(p)])
@@ -1173,12 +1234,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),
genTypeInfo(p.module, seqType, e.info)])
genTypeInfoV1(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),
genTypeInfo(p.module, seqType, e.info)])
genTypeInfoV1(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)
@@ -1194,9 +1255,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
proc genReset(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
specializeReset(p, a)
when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfoV1(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)
@@ -1222,12 +1285,12 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
[getTypeDesc(p.module, typ), sizeExpr])
genAssignment(p, a, b, {})
else:
let ti = genTypeInfo(p.module, typ, a.lode.info)
let ti = genTypeInfoV1(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 != ccDefault:
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccNimCall:
localError(p.module.config, a.lode.info,
"the destructor that is turned into a finalizer needs " &
"to have the 'nimcall' calling convention")
@@ -1281,18 +1344,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),
genTypeInfo(p.module, seqtype, dest.lode.info), length])
genTypeInfoV1(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),
genTypeInfo(p.module, seqtype, dest.lode.info), length])
genTypeInfoV1(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),
genTypeInfo(p.module, seqtype, dest.lode.info), length])
genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
genAssignment(p, dest, call, {})
proc genNewSeq(p: BProc, e: PNode) =
@@ -1301,9 +1364,10 @@ 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));$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), NIM_ALIGNOF($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
@@ -1316,14 +1380,15 @@ 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));$n",
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($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),
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc]))
gcUsage(p.config, e)
proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
@@ -1335,7 +1400,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)])
[getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true, t)])
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@@ -1345,7 +1410,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:
@@ -1425,7 +1490,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));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
@@ -1456,7 +1521,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));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
@@ -1493,7 +1558,10 @@ proc genNewFinalize(p: BProc, e: PNode) =
initLocExpr(p, e[1], a)
initLocExpr(p, e[2], f)
initLoc(b, locExpr, a.lode, OnHeap)
ti = genTypeInfo(p.module, refType, e.info)
if optTinyRtti in p.config.globalOptions:
ti = genTypeInfoV2(p.module, refType, e.info)
else:
ti = genTypeInfoV1(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),
@@ -1508,9 +1576,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 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
# have to call it here first:
let ti = genTypeInfo(p.module, dest, info)
let ti = genTypeInfoV1(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]
@@ -1523,7 +1591,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, genTypeInfo(p.module, dest, info)])
[a, genTypeInfoV1(p.module, dest, info)])
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc
@@ -1573,12 +1641,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), genTypeInfo(p.module, t, e.info)]), a.storage)
rdLoc(a), genTypeInfoV1(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), genTypeInfo(p.module, t, e.info)]), a.storage)
addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs:
var b: TLoc
case skipTypes(a.t, abstractVarRange).kind
@@ -1593,20 +1661,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),
genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
genTypeInfoV1(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), genTypeInfo(p.module, t, e.info)]), a.storage)
rdLoc(a), genTypeInfoV1(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), genTypeInfo(p.module, t, e.info)]),
[addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]),
a.storage)
gcUsage(p.config, e)
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope =
result = rdLoc(a)
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
@@ -1620,13 +1688,20 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): 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, genTypeInfo(p.module, t, e.info))
putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info))
else:
var a: TLoc
initLocExpr(p, e[1], a)
@@ -1638,7 +1713,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 = a.flags - {lfIndirect} # this flag should not be propagated here (not just for HCR)
a.flags.excl 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)
@@ -1660,8 +1735,12 @@ 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 op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
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")
of tyCString:
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
@@ -1715,13 +1794,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),
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
genTypeInfoV1(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),
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
genAssignment(p, a, call, {})
gcUsage(p.config, e)
@@ -1746,6 +1825,8 @@ 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
@@ -1779,9 +1860,9 @@ template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(p.config, skipTypes(e[1].typ, abstractVar)))
of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)")
of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)")
of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)")
of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)")
of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)")
of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)")
of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)")
else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)")
@@ -1979,25 +2060,30 @@ 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:
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])
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])
putIntoDest(p, d, n, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
@@ -2062,10 +2148,14 @@ proc skipAddr(n: PNode): PNode =
proc genWasMoved(p: BProc; n: PNode) =
var a: TLoc
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)])
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)])
proc genMove(p: BProc; n: PNode; d: var TLoc) =
var a: TLoc
@@ -2074,7 +2164,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.len && $1.p != $2.p) {", [rdLoc(a), rdLoc(src)])
linefmt(p, cpsStmts, "if ($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:
@@ -2092,14 +2182,14 @@ proc genDestroy(p: BProc; n: PNode) =
initLocExpr(p, arg, 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",
"}$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" &
" #deallocShared($1.p);$n" &
" $1.p = NIM_NIL; $1.len = 0; }$n",
"}$n",
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
else: discard "nothing to do"
else:
@@ -2125,6 +2215,14 @@ proc genDispose(p: BProc; n: PNode) =
# 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})
@@ -2151,12 +2249,13 @@ 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] = ["+=", "-="]
const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"]
const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"]
let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange})
let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct})
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
binaryStmt(p, e, d, opr[op])
else:
@@ -2201,7 +2300,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
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 mStrToStr, mUnown, mIsolate: expr(p, e[1], d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
@@ -2224,18 +2323,15 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
of mAlignOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
if not p.module.compileToCpp:
p.module.includeHeader("<stdalign.h>")
putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)])
of mOffsetOf:
var dotExpr: PNode
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")
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)
let member =
@@ -2298,6 +2394,10 @@ 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)
@@ -2308,9 +2408,7 @@ 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:
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
"'toOpenArray' is only valid within a call expression")
of mSlice: genSlice(p, e, d)
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
@@ -2387,7 +2485,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)])
[getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true, n.typ)])
putIntoDest(p, d, n, tmp, OnStatic)
else:
var tmp, a, b: TLoc
@@ -2450,6 +2548,8 @@ 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)
@@ -2460,7 +2560,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, dest)
else:
genTypeInfo(p.module, dest, n.info)
genTypeInfoV1(p.module, dest, n.info)
if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n",
[nilCheck, r, checkFor, raiseInstr(p)])
@@ -2468,7 +2568,11 @@ 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:
putIntoDest(p, d, n,
if n.isLValue:
putIntoDest(p, d, n,
"(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else:
putIntoDest(p, d, n,
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else:
putIntoDest(p, d, n, "(*($1*) ($2))" %
@@ -2520,7 +2624,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), tmp, genBracedInit(p, n, isConst = true)])
[getTypeDesc(p.module, t, skConst), tmp, genBracedInit(p, n, isConst = true, t)])
if d.k == locNone:
fillLoc(d, locData, n, tmp, OnStatic)
@@ -2585,10 +2689,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else:
putLocIntoDest(p, d, sym.loc)
of skTemp:
if sym.loc.r == nil:
# we now support undeclared 'skTemp' variables for easier
# transformations in other parts of the compiler:
assignLocalVar(p, n)
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 or sym.loc.t == nil:
#echo "FAILED FOR PRCO ", p.prc.name.s
#echo renderTree(p.prc.ast, {renderIds})
@@ -2663,9 +2769,7 @@ 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: genRangeChck(p, n, d)
of nkChckRange64: genRangeChck(p, n, d)
of nkChckRange: genRangeChck(p, n, d)
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
of nkStringToCString: convStrToCStr(p, n, d)
of nkCStringToString: convCStrToStr(p, n, d)
of nkLambdaKinds:
@@ -2685,9 +2789,11 @@ 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.
@@ -2741,8 +2847,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)
else: result = genBracedInit(p, n, isConst)
if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst, n[0].typ)
else: result = genBracedInit(p, n, isConst, n.typ)
proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc})
@@ -2781,12 +2887,29 @@ 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 mapType(p.config, t) == ctArray: result = rope"{}"
if mapSetType(p.config, t) == ctArray: result = rope"{}"
else: result = rope"0"
else:
globalError(p.config, info, "cannot create null element for: " & $t.kind)
proc caseObjDefaultBranch(obj: PNode; branch: Int128): int =
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
return i
elif getOrdValue(obj[i][j]) == branch:
return i
if obj[i].len == 1:
# else branch
return i
assert(false, "unreachable")
proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
result: var Rope; count: var int;
isConst: bool, info: TLineInfo) =
@@ -2809,31 +2932,14 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
branch = getOrdValue(constOrNil[i])
break
var selectedBranch = -1
block branchSelection:
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
selectedBranch = i
break branchSelection
elif getOrdValue(obj[i][j]) == branch:
selectedBranch = i
break branchSelection
if obj[i].len == 1:
# else branch
selectedBranch = i
assert(selectedBranch >= 1)
let selectedBranch = caseObjDefaultBranch(obj, branch)
result.add "{"
var countB = 0
let b = lastSon(obj[selectedBranch])
# designated initilization is the only way to init non first element of unions
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
if b.kind == nkRecList and b.len > 0:
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
if b.kind == nkRecList and b.len > 0:
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
result.add "}"
elif b.kind == nkSym:
@@ -2849,10 +2955,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)
result.add genBracedInit(p, constOrNil[i][1], isConst, field.typ)
return
elif i == field.position:
result.add genBracedInit(p, constOrNil[i], isConst)
result.add genBracedInit(p, constOrNil[i], isConst, field.typ)
return
# not found, produce default value:
result.add getDefaultValue(p, field.typ, info)
@@ -2871,7 +2977,10 @@ 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):
result.add genTypeInfo(p.module, orig, obj.info)
if optTinyRtti in p.config.globalOptions:
result.add genTypeInfoV2(p.module, orig, obj.info)
else:
result.add genTypeInfoV1(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:
@@ -2890,25 +2999,35 @@ 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 - 1:
result.addf("$1,$n", [genNamedConstExpr(p, n[i], isConst)])
if n.len > 0:
result.add(genNamedConstExpr(p, n[^1], isConst))
result.addf("}$n", [])
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")
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)
data.add genBracedInit(p, n[i], isConst, base)
data.add("}")
data.add("}")
result = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData,
"static $5 struct {$n" &
@@ -2921,14 +3040,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)
data.add genBracedInit(p, n[i], isConst, base)
data.add("}")
let payload = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData,
"static $5 struct {$n" &
@@ -2938,31 +3057,32 @@ 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): Rope =
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope =
case n.kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genBracedInit(p, n[1], isConst)
result = genBracedInit(p, n[1], isConst, n.typ)
else:
var ty = tyNone
if n.typ == nil:
var typ: PType = nil
if optionalType == nil:
if n.kind in nkStrKinds:
ty = tyString
else:
internalError(p.config, n.info, "node has no type")
else:
ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind
typ = skipTypes(optionalType, abstractInstOwned + {tyStatic})
ty = typ.kind
case ty
of tySet:
var cs: TBitSet
toBitSet(p.config, n, cs)
let cs = toBitSet(p.config, n)
result = genRawSetData(cs, int(getSize(p.config, n.typ)))
of tySequence:
if optSeqDestructors in p.config.globalOptions:
result = genConstSeqV2(p, n, n.typ, isConst)
result = genConstSeqV2(p, n, typ, isConst)
else:
result = genConstSeq(p, n, n.typ, isConst)
result = genConstSeq(p, n, typ, isConst)
of tyProc:
if n.typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit:
if 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
@@ -2975,13 +3095,30 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
else:
var d: TLoc
initLocExpr(p, n[0], d)
result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, n.typ, clHalfWithEnv), rdLoc(d)]
result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)]
else:
var d: TLoc
initLocExpr(p, n, d)
result = rdLoc(d)
of tyArray, tyTuple, tyOpenArray, tyVarargs:
of tyArray, 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,6 +48,10 @@ 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")
@@ -278,7 +282,7 @@ proc mergeRequired*(m: BModule): bool =
if m.s[i] != nil:
#echo "not empty: ", i, " ", m.s[i]
return true
for i in low(TCProcSection)..high(TCProcSection):
for i in TCProcSection:
if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", m.initProc.s[i]
return true
@@ -288,7 +292,7 @@ proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
var old: TMergeSections
readMergeSections(cfilename, old)
# do the merge; old section before new section:
for i in low(TCFileSection)..high(TCFileSection):
for i in TCFileSection:
m.s[i] = old.f[i] & m.s[i]
for i in low(TCProcSection)..high(TCProcSection):
for i in TCProcSection:
m.initProc.s(i) = old.p[i] & m.initProc.s(i)

94
compiler/ccgreset.nim Normal file
View File

@@ -0,0 +1,94 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# included from cgen.nim
## Code specialization instead of the old, incredibly slow 'genericReset'
## implementation.
proc specializeResetT(p: BProc, accessor: Rope, typ: PType)
proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
typ: PType) =
if n == nil: return
case n.kind
of nkRecList:
for i in 0..<n.len:
specializeResetN(p, accessor, n[i], typ)
of nkRecCase:
if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN")
let disc = n[0].sym
if disc.loc.r == nil: fillObjectFields(p.module, typ)
if disc.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
specializeResetN(p, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
specializeResetT(p, "$1.$2" % [accessor, disc.loc.r], disc.loc.t)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.r == nil: fillObjectFields(p.module, typ)
if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(p.config, n.info, "specializeResetN()")
proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
if typ == nil: return
case typ.kind
of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
tySink, tyOwned:
specializeResetT(p, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ[0])
var i: TLoc
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
lineF(p, cpsStmts, "}$n", [])
of tyObject:
for i in 0..<typ.len:
var x = typ[i]
if x != nil: x = x.skipTypes(skipPtrs)
specializeResetT(p, accessor.parentObj(p.module), x)
if typ.n != nil: specializeResetN(p, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i in 0..<typ.len:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), typ[i])
of tyString, tyRef, tySequence:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])
of tyProc:
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor])
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCString, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
else:
discard
proc specializeReset(p: BProc, a: TLoc) =
specializeResetT(p, rdLoc(a), a.t)

View File

@@ -200,6 +200,7 @@ 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:
@@ -217,6 +218,8 @@ 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])
@@ -269,7 +272,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): Rope
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope
proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope =
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
@@ -277,7 +280,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)
result = genBracedInit(p, value, isConst = false, v.typ)
else:
result = nil
@@ -688,14 +691,15 @@ proc genBreakStmt(p: BProc, t: PNode) =
proc raiseExit(p: BProc) =
assert p.config.exc == excGoto
p.flags.incl nimErrorFlagAccessed
if p.nestedTryStmts.len == 0:
p.flags.incl beforeRetNeeded
# easy case, simply goto 'ret':
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", [])
else:
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
[p.nestedTryStmts[^1].label])
if nimErrorFlagDisabled notin p.flags:
p.flags.incl nimErrorFlagAccessed
if p.nestedTryStmts.len == 0:
p.flags.incl beforeRetNeeded
# easy case, simply goto 'ret':
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", [])
else:
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
[p.nestedTryStmts[^1].label])
proc finallyActions(p: BProc) =
if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
@@ -727,6 +731,7 @@ 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:
@@ -859,10 +864,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 i in 0..<b.len-1:
for it in b:
# last son is block
if (b[i].kind == nkRange) and
b[i][1].intVal - b[i][0].intVal > RangeExpandLimit:
if (it.kind == nkRange) and
it[1].intVal - it[0].intVal > RangeExpandLimit:
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
@@ -981,14 +986,19 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
inc(p.labels, 2)
let etmp = p.labels
lineCg(p, cpsStmts, "std::exception_ptr T$1_ = nullptr;", [etmp])
p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp]))
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural))
startBlock(p, "try {$n")
expr(p, t[0], d)
endBlock(p)
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)
# First pass: handle Nim based exceptions:
lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1])
@@ -1030,7 +1040,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, typeNode.typ)
else:
genTypeInfo(p.module, typeNode.typ, typeNode.info)
genTypeInfoV1(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])
@@ -1208,6 +1218,10 @@ 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:
@@ -1241,7 +1255,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:
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
genTypeInfoV1(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])
@@ -1278,7 +1292,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)
if p.prc != nil: raiseExit(p)
raiseExit(p)
if hasExcept: inc p.withinTryWithExcept
proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
@@ -1333,13 +1347,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])
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
lineCg(p, cpsStmts, "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", [])
endBlock(p)
lineCg(p, cpsStmts, "}$n", [])
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
genRestoreFrameAfterException(p)
@@ -1369,7 +1383,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:
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
genTypeInfoV1(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])
@@ -1440,7 +1454,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
else:
# ignore empty lines
result.add("\"")
result.add(x)
result.add(x.replace("\"", "\\\""))
result.add("\\n\"\n")
else:
res.add("\L")
@@ -1484,26 +1498,17 @@ proc genPragma(p: BProc, n: PNode) =
of wEmit: genEmit(p, it)
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
p.options.excl {optLineTrace, optStackTrace}
genStmts(p, it[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn[0]
if le.kind == nkCheckedFieldExpr:
var field = le[0][1].sym
result = sfDiscriminant in field.flags
elif le.kind == nkDotExpr:
var field = le[1].sym
result = sfDiscriminant in field.flags
proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfo(p.module, t, a.lode.info)
discard genTypeInfoV1(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)])
@@ -1534,28 +1539,24 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
expr(p, e[1], tmp)
let field = dotExpr[1].sym
if optTinyRtti in p.config.globalOptions:
let t = dotExpr[0].typ.skipTypes(abstractInst)
var oldVal, newVal: TLoc
genCaseObjDiscMapping(p, e[0], t, field, oldVal)
genCaseObjDiscMapping(p, e[1], t, field, newVal)
lineCg(p, cpsStmts,
"if ($1 != $2) { #raiseObjectCaseTransition(); $3}$n",
[rdLoc(oldVal), rdLoc(newVal), raiseInstr(p)])
else:
if optTinyRtti notin p.config.globalOptions:
let field = dotExpr[1].sym
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
message(p.config, e.info, warnCaseTransition)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
if e[0].kind == nkSym and sfGoto in e[0].sym.flags:
genLineDir(p, e)
genGotoVar(p, e[1])
elif not fieldDiscriminantCheckNeeded(p, e):
elif optFieldCheck in p.options and isDiscriminantField(e[0]):
genLineDir(p, e)
asgnFieldDiscriminant(p, e)
else:
let le = e[0]
let ri = e[1]
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs))
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
@@ -1565,10 +1566,6 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
assert(a.t != nil)
genLineDir(p, ri)
loadInto(p, le, ri, a)
else:
genLineDir(p, e)
asgnFieldDiscriminant(p, e)
message(p.config, e.info, warnCaseTransition)
proc genStmts(p: BProc, t: PNode) =
var a: TLoc

View File

@@ -42,11 +42,12 @@ 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.cmd == cmdCompileToCpp or
let externc = if m.config.backend == backendCpp 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 genTypeInfo(m, s.loc.t, info)
discard genTypeInfoV1(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): TCTypeKind =
proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
## Maps a Nim type to a C type
case typ.kind
of tyNone, tyTyped: result = ctVoid
@@ -157,14 +157,17 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
of tyChar: result = ctChar
of tyNil: result = ctPtr
of tySet: result = mapSetType(conf, typ)
of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray
of tyOpenArray, tyVarargs:
if kind == skParam: result = ctArray
else: result = ctStruct
of tyArray, tyUncheckedArray: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses:
doAssert typ.isResolvedUserTypeClass
return mapType(conf, typ.lastSon)
return mapType(conf, typ.lastSon, kind)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
result = mapType(conf, lastSon(typ))
result = mapType(conf, lastSon(typ), kind)
of tyEnum:
if firstOrd(conf, typ) < 0:
result = ctInt32
@@ -175,7 +178,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctInt32
of tyRange: result = mapType(conf, typ[0])
of tyRange: result = mapType(conf, typ[0], kind)
of tyPtr, tyVar, tyLent, tyRef:
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
@@ -192,14 +195,14 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(conf, lastSon typ)
if typ.n != nil: result = mapType(conf, lastSon typ, kind)
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)
result = mapType(conf, typ, skResult)
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
@@ -209,7 +212,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): Rope
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
@@ -222,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
# is necessary for proper code generation of assignments.
if rettype == nil: result = true
else:
case mapType(conf, rettype)
case mapType(conf, rettype, skResult)
of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyLent, tyRef, tyPtr})
@@ -238,7 +241,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_CLOSURE", "N_NOCONV"]
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV"]
proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
# returns nil if we need to declare this type
@@ -247,8 +250,13 @@ 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):
m.s[cfsTypeInfo].addf("NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)])
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
proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
@@ -263,19 +271,18 @@ 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:
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
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 = pt.kind != tyVar
proc fillResult(conf: ConfigRef; param: PNode) =
fillLoc(param.sym.loc, locParam, param, ~"Result",
@@ -328,7 +335,6 @@ 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):
@@ -343,8 +349,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 {.global.} = rope("union")
let cachedStruct {.global.} = rope("struct")
let cachedUnion = rope("union")
let cachedStruct = rope("struct")
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: cachedUnion
else: cachedStruct
@@ -364,7 +370,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 + {tyOpt})
let concrete = typ.skipTypes(abstractInst)
case concrete.kind
of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ, sig)
@@ -376,7 +382,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): Rope =
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): 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:
@@ -384,7 +390,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and t.kind == tyGenericInst:
result = getTypeDescAux(m, t, check)
result = getTypeDescAux(m, t, check, kind)
else:
result = getTypeForward(m, t, hashType(t))
pushType(m, t)
@@ -414,18 +420,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
result = getTypeForward(m, t, sig) & seqStar(m)
pushType(m, t)
else:
result = getTypeDescAux(m, t, check)
result = getTypeDescAux(m, t, check, kind)
proc getSeqPayloadType(m: BModule; t: PType): Rope =
var check = initIntSet()
result = getTypeDescWeak(m, t, check) & "_Content"
result = getTypeDescWeak(m, t, check, skParam) & "_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)
discard getTypeDescAux(m, t, check, skVar)
else:
# little hack for now to prevent multiple definitions of the same
# Seq_Content:
@@ -434,7 +440,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), result, rope"#"])
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"])
proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
@@ -450,7 +456,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)
rettype = getTypeDescAux(m, t[0], check, skResult)
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
@@ -459,15 +465,17 @@ 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))
params.add(getTypeDescWeak(m, param.typ, check, skParam))
params.add(~"*")
incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown
elif weakDep:
params.add(getTypeDescWeak(m, param.typ, check))
params.add(getTypeDescWeak(m, param.typ, check, skParam))
else:
params.add(getTypeDescAux(m, param.typ, check))
params.add(getTypeDescAux(m, param.typ, check, skParam))
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
@@ -484,10 +492,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))
params.add(getTypeDescWeak(m, arr, check, skResult))
params.add("*")
else:
params.add(getTypeDescAux(m, arr, check))
params.add(getTypeDescAux(m, arr, check, skResult))
params.addf(" Result", [])
if t.callConv == ccClosure and declareEnvironment:
if params != nil: params.add(", ")
@@ -556,19 +564,21 @@ 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), sname])
[getTypeDescAux(m, fieldType.elemType, check, skField), sname])
elif fieldType.kind == tySequence:
# we need to use a weak dependency here for trecursive_table.
result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
result.addf("$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias])
elif field.bitsize != 0:
result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
result.addf("$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias])
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias])
else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
@@ -603,11 +613,14 @@ 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:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
else:
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)])
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
@@ -620,7 +633,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)])
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
hasField = true
else:
result.addf(" {$n", [name])
@@ -640,7 +653,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), rope(i)])
[getTypeDescAux(m, typ[i], check, skField), rope(i)])
if desc == nil: result.add("char dummy;\L")
else: result.add(desc)
result.add("};\L")
@@ -674,8 +687,22 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
result = if result.kind == tyGenericInst: result[1]
else: result.elemType
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
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 =
# returns only the type's name
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
if containsOrIncl(check, t.id):
if not (isImportedCppType(origTyp) or isImportedCppType(t)):
@@ -686,17 +713,22 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
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:
if result != nil and t.kind != tyOpenArray:
excl(check, t.id)
return
case t.kind
of tyRef, tyPtr, tyVar, tyLent:
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
var star = if t.kind in {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) == ctPtrToArray:
if mapType(m.config, t, kind) == ctPtrToArray and (etB.kind != tyOpenArray or kind == skParam):
if etB.kind == tySet:
et = getSysType(m.g.graph, unknownLineInfo, tyUInt8)
else:
@@ -706,7 +738,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst:
result = getTypeDescAux(m, et, check) & star
result = getTypeDescAux(m, et, check, kind) & star
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType et)
@@ -714,7 +746,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
m.typeCache[sig] = result
of tySequence:
if optSeqDestructors in m.config.globalOptions:
result = getTypeDescWeak(m, et, check) & star
result = getTypeDescWeak(m, et, check, kind) & star
m.typeCache[sig] = result
else:
# no restriction! We have a forward declaration for structs
@@ -724,11 +756,10 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
pushType(m, et)
else:
# else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star
result = getTypeDescAux(m, et, check, kind) & star
m.typeCache[sig] = result
of tyOpenArray, tyVarargs:
result = getTypeDescWeak(m, t[0], check) & "*"
m.typeCache[sig] = result
result = getOpenArrayDesc(m, t, check, kind)
of tyEnum:
result = cacheGetType(m.typeCache, sig)
if result == nil:
@@ -774,7 +805,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
[result, rettype, desc])
of tySequence:
if optSeqDestructors in m.config.globalOptions:
result = getTypeDescWeak(m, t, check)
result = getTypeDescWeak(m, t, check, kind)
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:
@@ -795,11 +826,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
if m.compileToCpp:
appcg(m, m.s[cfsSeqTypes],
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t[0], check), result])
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
else:
appcg(m, m.s[cfsSeqTypes],
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t[0], check), result])
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
else:
result = rope("TGenericSeq")
result.add(seqStar(m))
@@ -807,7 +838,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t[0], check)
let foo = getTypeDescAux(m, t[0], check, kind)
m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
of tyArray:
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
@@ -815,10 +846,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t[1], check)
let foo = getTypeDescAux(m, t[1], check, kind)
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)
@@ -832,7 +862,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
internalAssert m.config, ty.n != nil
result.add ty.n.renderTree
else:
result.add getTypeDescAux(m, ty, check)
result.add getTypeDescAux(m, ty, check, kind)
while i < cppName.data.len:
if cppName.data[i] == '\'':
@@ -879,7 +909,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
m.s[cfsTypes].add(recdesc)
elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
elif tfIncompleteStruct notin t.flags:
discard # addAbiCheck(m, t, result) # already handled elsewhere
of tySet:
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType
@@ -892,16 +923,16 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
[result, rope(getSize(m.config, t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
result = getTypeDescAux(m, lastSon(t), check)
result = getTypeDescAux(m, lastSon(t), check, kind)
else:
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
result = nil
# fixes bug #145:
excl(check, t.id)
proc getTypeDesc(m: BModule, typ: PType): Rope =
proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope =
var check = initIntSet()
result = getTypeDescAux(m, typ, check)
result = getTypeDescAux(m, typ, check, kind)
type
TClosureTypeKind = enum ## In C closures are mapped to 3 different things.
@@ -933,8 +964,9 @@ 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)
discard getTypeDescAux(m, t, check, skParam)
inc(i)
m.typeStack.setLen 0
template cgDeclFrmt*(s: PSym): string =
s.constraint.strVal
@@ -979,7 +1011,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
# ------------------ type info generation -------------------------------------
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope
proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope
proc getNimNode(m: BModule): Rope =
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes)
@@ -999,11 +1031,14 @@ 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)
if tfIncompleteStruct in typ.flags:
size = rope"void*"
else:
size = getTypeDesc(m, origType, skVar)
m.s[cfsTypeInit3].addf(
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
[nameHcr, size, rope(nimtypeKind), base])
"$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($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
@@ -1039,7 +1074,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 = genTypeInfo(m, x, info)
base = genTypeInfoV1(m, x, info)
else:
base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base, info)
@@ -1097,8 +1132,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), field.loc.r,
genTypeInfo(m, field.typ, info),
"$1.len = $7;$n", [expr, getTypeDesc(m, origType, skVar), field.loc.r,
genTypeInfoV1(m, field.typ, info),
makeCString(field.name.s),
tmp, rope(L)])
m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)])
@@ -1134,8 +1169,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),
field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
"$1.name = $5;$n", [expr, getTypeDesc(m, origType, skVar),
field.loc.r, genTypeInfoV1(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) =
@@ -1170,7 +1205,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), rope(i), genTypeInfo(m, a, info)])
[tmp2, getTypeDesc(m, origType, skVar), rope(i), genTypeInfoV1(m, a, info)])
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(typ.len), tmp])
else:
@@ -1227,7 +1262,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, genTypeInfo(m, typ[1], info), info)
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info)
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1245,13 +1280,14 @@ 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, str: Rope, ownerModule: PSym) =
proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) =
let nr = rope(name)
if m.hcrOn:
m.s[cfsData].addf("static TNimType* $1;$n", [str])
m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
[str, getModuleDllPath(m, ownerModule)])
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])
else:
m.s[cfsData].addf("extern TNimType $1;$n", [str])
m.s[cfsData].addf("extern $2 $1;$n", [str, nr])
proc genTypeInfo2Name(m: BModule; t: PType): Rope =
var res = "|"
@@ -1284,21 +1320,22 @@ 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 != ccDefault:
if theProc.typ == nil or theProc.typ.callConv != ccNimCall:
localError(m.config, info,
theProc.name.s & " needs to have the 'nimcall' calling convention")
genProc(m, theProc)
result = theProc.loc.r
else:
if op == attachedTrace and m.config.selectedGC == gcOrc and
containsGarbageCollectedRef(t):
when false:
# re-enable this check
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'.
internalError(m.config, info, "no attached trace proc found")
result = rope("NIM_NIL")
proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
var typeName: Rope
if t.kind == tyObject:
if incompleteType(t):
@@ -1308,19 +1345,65 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
else:
typeName = rope("NIM_NIL")
m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name])
discard cgsym(m, "TNimTypeV2")
m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
let destroyImpl = genHook(m, t, info, attachedDestructor)
let traceImpl = genHook(m, t, info, attachedTrace)
let disposeImpl = genHook(m, t, info, attachedDispose)
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", [
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;", [
name, destroyImpl, getTypeDesc(m, t), typeName,
traceImpl, disposeImpl])
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
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 =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
@@ -1335,7 +1418,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
if marker.str != nil:
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
declareNimType(m, marker.str, marker.owner)
declareNimType(m, "TNimType", marker.str, marker.owner)
# also store in local type section:
m.typeInfoMarker[sig] = marker.str
return prefixTI.rope & marker.str & ")".rope
@@ -1347,63 +1430,68 @@ proc genTypeInfo(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 genTypeInfo(m.g.modules[owner.position], origType, info)
discard genTypeInfoV1(m.g.modules[owner.position], origType, info)
# reference the type info as extern here
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
declareNimType(m, result, owner)
declareNimType(m, "TNimType", result, owner)
return prefixTI.rope & result & ")".rope
m.g.typeInfoMarker[sig] = (str: result, owner: owner)
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:
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:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
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 & ')')
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 & ')')
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.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
m.config.backend == backendCpp or sfCompileToCpp in m.module.flags
proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels)
@@ -310,14 +310,19 @@ 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) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
result = "(&" & result & ")"
proc byRefLoc(p: BProc; a: TLoc): Rope =
result = a.r
if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
p.module.compileToCpp:
result = "(&" & result & ")"
@@ -355,7 +360,10 @@ 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)
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
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)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc
@@ -364,14 +372,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)])
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
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, genTypeInfo(p.module, t, a.lode.info)])
linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
if isException(t):
var r = rdLoc(a)
@@ -387,9 +395,11 @@ 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} or
result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or
(t.kind == tyProc and t.callConv == ccClosure)
include ccgreset
proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t)
let typ = skipTypes(loc.t, abstractVarRange)
@@ -406,11 +416,11 @@ 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:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
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)])
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
@@ -418,7 +428,8 @@ 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)])
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
# 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)
@@ -429,14 +440,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ)])
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
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)])
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@@ -454,7 +465,7 @@ 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), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -464,7 +475,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
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), result.r, value])
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -486,12 +497,13 @@ 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)
result.add getTypeDesc(p.module, s.typ, skVar)
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:
@@ -539,7 +551,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)
var td = getTypeDesc(p.module, s.loc.t, skVar)
if s.constraint.isNil:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
@@ -552,6 +564,7 @@ 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:
@@ -679,12 +692,13 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
[loadlib, genStringLiteral(m, lib.path)])
else:
var p = newProc(nil, m)
p.options = p.options - {optStackTrace}
p.options.excl 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), rdLoc(dest)])
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
@@ -724,7 +738,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), params, makeCString($extname)]
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last[1]
internalAssert(m.config, last.kind == nkStrLit)
@@ -738,8 +752,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), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
[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)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -751,9 +765,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), lib.name, makeCString($extname)])
[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)])
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
@@ -973,6 +987,9 @@ proc genProcBody(p: BProc; procBody: PNode) =
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
sfNoReturn in s.flags and m.config.exc != excGoto
proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = genProcHeader(m, prc)
@@ -1027,7 +1044,7 @@ proc genProcAux(m: BModule, prc: PSym) =
var generatedProc: Rope
generatedProc.genCLineDir prc.info, m.config
if sfNoReturn in prc.flags:
if isNoReturn(p.module, prc):
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
@@ -1068,11 +1085,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.cmd != cmdCompileToCpp) or (
m.config.backend != backendCpp) or (
sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and
sym.flags * {sfImportc, sfExportc} != {} and
sym.magic == mNone and
m.config.cmd == cmdCompileToCpp)
m.config.backend == backendCpp)
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
@@ -1090,13 +1107,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
let asPtr = isReloadable(m, sym)
var header = genProcHeader(m, sym, asPtr)
if not asPtr:
if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
header = "__declspec(noreturn) " & header
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
header = "extern \"C\" " & header
if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
header.add(" __attribute__((naked))")
if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props:
header.add(" __attribute__((noreturn))")
m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header]))
@@ -1168,21 +1185,44 @@ 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), sym.loc.r, genBracedInit(q.initProc, sym.ast, isConst = true)])
[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)]))
# declare header:
if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
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)
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)
proc isActivated(prc: PSym): bool = prc.typ != nil
@@ -1219,15 +1259,16 @@ 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))
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
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), getModuleDllPath(m, sym)])
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
@@ -1533,7 +1574,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 != gcNone:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
@@ -1585,10 +1626,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)])
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
result = "\t$1 = ($2) $3($4, $5);$n" %
[tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
proc genInitCode(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
@@ -1638,6 +1679,10 @@ proc genInitCode(m: BModule) =
writeSection(preInitProc, cpsInit, m.hcrOn)
writeSection(preInitProc, cpsStmts)
prc.addf("}$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
@@ -1749,11 +1794,6 @@ 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
@@ -1774,7 +1814,9 @@ 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 = newPreInitProc(result)
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
initNodeTable(result.dataCache)
result.typeStack = @[]
result.typeNodesName = getTempName(result)
@@ -1804,7 +1846,10 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
injectG()
result = newModule(g, module, graph.config)
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
@@ -1844,7 +1889,7 @@ proc writeHeader(m: BModule) =
proc getCFile(m: BModule): AbsoluteFile =
let ext =
if m.compileToCpp: ".nim.cpp"
elif m.config.cmd == cmdCompileToOC or sfCompileToObjc in m.module.flags: ".nim.m"
elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m"
else: ".nim.c"
result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
@@ -1999,8 +2044,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil:
discard cgsym(m, "nimTestErrorFlag")
for i in countdown(high(graph.globalDestructors), 0):
n.add graph.globalDestructors[i]
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
if moduleHasChanged(graph, m.module):
# if the module is cached, we don't regenerate the main proc
@@ -2039,7 +2085,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
let disp = generateMethodDispatchers(graph)
for x in disp: genProcAux(m, x.sym)
m.g.modulesClosed.add m
let mm = m
m.g.modulesClosed.add mm
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
tables, ndi, lineinfos, pathutils, modulegraphs, sets
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
cfsTypeInfo, # section for type information (ag ABI checks)
cfsProcHeaders, # section for C procs prototypes
cfsData, # section for C constant data
cfsVars, # section for C variable declarations
@@ -70,7 +70,8 @@ type
hasCurFramePointer,
noSafePoints,
nimErrorFlagAccessed,
nimErrorFlagDeclared
nimErrorFlagDeclared,
nimErrorFlagDisabled
TCProc = object # represents C proc that is currently generated
prc*: PSym # the Nim proc that this C proc belongs to
@@ -96,6 +97,7 @@ 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]
@@ -120,6 +122,7 @@ 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
@@ -144,11 +147,16 @@ 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
@@ -184,8 +192,8 @@ proc newProc*(prc: PSym, module: BModule): BProc =
new(result)
result.prc = prc
result.module = module
if prc != nil: result.options = prc.options
else: result.options = module.config.options
result.options = if prc != nil: prc.options
else: 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 = ccDefault
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil

View File

@@ -130,7 +130,8 @@
import
ast, msgs, idents,
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
tables, options
type
Ctx = object
@@ -388,6 +389,10 @@ 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:
@@ -481,7 +486,6 @@ 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)
@@ -686,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 0..<n.len:
for i in ord(n.kind == nkCast)..<n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns)
if ns:
@@ -738,8 +742,6 @@ 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
@@ -1102,7 +1104,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
result = ctx.states[stateIdx][0].intVal.int
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
result = n
case n.kind
of nkSkip:
@@ -1282,6 +1284,101 @@ proc deleteEmptyStates(ctx: var Ctx) =
else:
inc i
type
PreprocessContext = object
finallys: seq[PNode]
config: ConfigRef
blocks: seq[(PNode, int)]
FreshVarsContext = object
tab: Table[int, PSym]
config: ConfigRef
info: TLineInfo
proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
case n.kind
of nkSym:
let x = c.tab.getOrDefault(n.sym.id)
if x == nil:
result = n
else:
result = newSymNode(x, n.info)
of nkSkip - {nkSym}:
result = n
of nkLetSection, nkVarSection:
result = copyNode(n)
for it in n:
if it.kind in {nkIdentDefs, nkVarTuple}:
let idefs = copyNode(it)
for v in 0..it.len-3:
if it[v].kind == nkSym:
let x = copySym(it[v].sym)
c.tab[it[v].sym.id] = x
idefs.add newSymNode(x)
else:
idefs.add it[v]
for rest in it.len-2 ..< it.len: idefs.add it[rest]
result.add idefs
else:
result.add it
of nkRaiseStmt:
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n
for i in 0..<n.safeLen:
result[i] = freshVars(n[i], c)
proc preprocess(c: var PreprocessContext; n: PNode): PNode =
# in order to fix bug #15243 without risking regressions, we preprocess
# the AST so that 'break' statements inside a 'try finally' also have the
# finally section. We need to duplicate local variables here and also
# detect: 'finally: raises X' which is currently not supported. We produce
# an error for this case for now. All this will be done properly with Yuriy's
# patch.
result = n
case n.kind
of nkTryStmt:
let f = n.lastSon
if f.kind == nkFinally:
c.finallys.add f.lastSon
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
if f.kind == nkFinally:
discard c.finallys.pop()
of nkWhileStmt, nkBlockStmt:
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
discard c.blocks.pop()
of nkBreakStmt:
if c.blocks.len == 0:
discard
else:
var fin = -1
if n[0].kind == nkEmpty:
fin = c.blocks[^1][1]
elif n[0].kind == nkSym:
for i in countdown(c.blocks.high, 0):
if c.blocks[i][0].kind == nkBlockStmt and c.blocks[i][0][0].kind == nkSym and
c.blocks[i][0][0].sym == n[0].sym:
fin = c.blocks[i][1]
break
if fin >= 0:
result = newNodeI(nkStmtList, n.info)
for i in countdown(c.finallys.high, fin):
var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info)
result.add freshVars(preprocess(c, c.finallys[i]), vars)
result.add n
of nkSkip: discard
else:
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
var ctx: Ctx
ctx.g = g
@@ -1294,7 +1391,10 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
var n = n.toStmtList
var pc = PreprocessContext(finallys: @[], config: g.config)
var n = preprocess(pc, n.toStmtList)
#echo "transformed into ", n
#var n = n.toStmtList
discard ctx.newState(n, nil)
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))

View File

@@ -11,16 +11,29 @@
import
options, idents, nimconf, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, os, pathutils
lineinfos, modulegraphs, condsyms, os, pathutils, parseopt
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)
@@ -42,37 +55,28 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
else:
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir())
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef;
graph: ModuleGraph): bool =
if self.suggestMode:
conf.command = "nimsuggest"
loadConfigs(DefaultConfig, cache, conf) # load all config files
block:
if not self.suggestMode:
let scriptFile = conf.projectFull.changeFileExt("nims")
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
# '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,15 +53,14 @@ const
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} =
var x = ""
for f in low(T)..high(T):
if x.len > 0: x.add "|"
x.add $f
x
result = ""
for f in T:
if result.len > 0: result.add "|"
result.add $f
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,
@@ -98,7 +97,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
CPU[conf.target.hostCPU].name, CompileDate]),
{msgStdout})
const gitHash = gorge("git log -n 1 --format=%H").strip
const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip
when gitHash.len == 40:
msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
@@ -146,24 +145,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 = conf.options + op
of "off": conf.options = conf.options - op
of "","on": conf.options.incl op
of "off": conf.options.excl 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 = conf.options + op
of "off": conf.options = conf.options - op
of "on": conf.options.incl op
of "off": conf.options.excl 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 = conf.globalOptions + op
of "off": conf.globalOptions = conf.globalOptions - op
of "", "on": conf.globalOptions.incl op
of "off": conf.globalOptions.excl op
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
@@ -176,7 +175,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:val or [key]:val; with val=on|off
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var i = 0
var n = hintMin
var isBracket = false
@@ -190,7 +189,8 @@ 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 and (arg[i] in {':', '='}): inc(i)
if i == arg.len: discard
elif i < arg.len and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(conf, pass, orig, info)
if state == wHint:
let x = findStr(lineinfos.HintsToStr, id)
@@ -201,7 +201,8 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: localError(conf, info, "unknown warning: " & id)
let val = substr(arg, i).normalize
var val = substr(arg, i).normalize
if val == "": val = "on"
if val notin ["on", "off"]:
localError(conf, info, errOnOrOffExpectedButXFound % arg)
elif n notin conf.cmdlineNotes or pass == passCmd1:
@@ -209,12 +210,18 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
incl(conf.modifiedyNotes, n)
case val
of "on":
incl(conf.notes, n)
incl(conf.mainPackageNotes, n)
if state == wWarningAsError:
incl(conf.warningAsErrors, n)
else:
incl(conf.notes, n)
incl(conf.mainPackageNotes, n)
of "off":
excl(conf.notes, n)
excl(conf.mainPackageNotes, n)
excl(conf.foreignPackageNotes, n)
if state == wWarningAsError:
excl(conf.warningAsErrors, n)
else:
excl(conf.notes, n)
excl(conf.mainPackageNotes, n)
excl(conf.foreignPackageNotes, n)
proc processCompile(conf: ConfigRef; filename: string) =
var found = findFile(conf, filename)
@@ -222,7 +229,7 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', 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"
@@ -291,7 +298,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 = contains(conf.options, optNilCheck)
of "nilchecks": result = false # not a thing
of "objchecks": result = contains(conf.options, optObjCheck)
of "fieldchecks": result = contains(conf.options, optFieldCheck)
of "rangechecks": result = contains(conf.options, optRangeCheck)
@@ -312,7 +319,6 @@ 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,
@@ -426,11 +432,18 @@ 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: "@default" else: arg
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
of "mainmodule", "m":
discard "allow for backwards compatibility, but don't do anything"
of "define", "d":
@@ -470,14 +483,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "forcebuild", "f":
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
of "project":
processOnOffSwitchG(conf, {optWholeProject}, arg, pass, info)
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
of "gc":
if conf.backend == backendJs:
return
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
case arg.normalize
of "boehm":
conf.selectedGC = gcBoehm
defineSymbol(conf.symbols, "boehmgc")
incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS
of "refc":
conf.selectedGC = gcRefc
of "v2":
@@ -487,8 +503,6 @@ 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
@@ -498,8 +512,6 @@ 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
@@ -528,6 +540,7 @@ 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)
@@ -569,25 +582,13 @@ 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": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
of "nilchecks": discard "no such thing anymore"
of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
@@ -866,8 +867,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "expandmacro":
expectArg(conf, switch, arg, pass, info)
conf.macrosToExpand[arg] = "T"
of "oldgensym":
processOnOffSwitchG(conf, {optNimV019}, arg, pass, info)
of "expandarc":
expectArg(conf, switch, arg, pass, info)
conf.arcToExpand[arg] = "T"
of "useversion":
expectArg(conf, switch, arg, pass, info)
case arg
@@ -878,14 +880,26 @@ 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:
@@ -893,15 +907,14 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "sourcemap":
conf.globalOptions.incl optSourcemap
conf.options.incl optLineDir
# processOnOffSwitchG(conf, {optSourcemap, opt}, arg, pass, info)
of "deepcopy":
processOnOffSwitchG(conf, {optEnableDeepCopy}, 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

@@ -86,7 +86,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimMacrosSizealignof")
defineSymbol("nimNoZeroExtendMagic")
defineSymbol("nimMacrosGetNodeId")
for f in low(Feature)..high(Feature):
for f in Feature:
defineSymbol("nimHas" & $f)
for s in WarningsToStr:
@@ -102,6 +102,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimnomagic64")
defineSymbol("nimNewShiftOps")
defineSymbol("nimHasCursor")
defineSymbol("nimAlignPragma")
defineSymbol("nimHasExceptionsQuery")
defineSymbol("nimHasIsNamedTuple")
defineSymbol("nimHashOrdinalFixed")
@@ -116,3 +117,9 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewIntegerOps")
defineSymbol("nimHasInvariant")
defineSymbol("nimHasStacktraceMsgs")
defineSymbol("nimDoesntTrackDefects")
defineSymbol("nimHasLentIterators")
defineSymbol("nimHasDeclaredMagic")
defineSymbol("nimHasStacktracesModule")
defineSymbol("nimHasEffectTraitsModule")
defineSymbol("nimHasCastPragmaBlocks")

View File

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

View File

@@ -29,44 +29,45 @@
## "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
import ast, types, intsets, lineinfos, renderer, asciitables
from patterns import sameTrees
type
InstrKind* = enum
goto, fork, join, def, use
goto, fork, def, use
Instr* = object
n*: PNode # contains the def/use location.
case kind*: InstrKind
of goto, fork, join: dest*: int
of goto, fork: dest*: int
else: discard
ControlFlowGraph* = seq[Instr]
TPosition = distinct int
TBlock = object
label: PSym
fixups: seq[TPosition]
case isTryBlock: bool
of false:
label: PSym
breakFixups: seq[(TPosition, seq[PNode])] #Contains the gotos for the breaks along with their pending finales
of true:
finale: PNode
raiseFixups: seq[TPosition] #Contains the gotos for the raises
Con = object
code: ControlFlowGraph
inCall, inTryStmt: int
inTryStmt: int
blocks: seq[TBlock]
tryStmtFixups: seq[TPosition]
forks: seq[TPosition]
owner: PSym
proc debugInfo(info: TLineInfo): string =
result = $info.line #info.toFilename & ":" & $info.line
proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
# for debugging purposes
# first iteration: compute all necessary labels:
var jumpTargets = initIntSet()
let last = if last < 0: c.len-1 else: min(last, c.len-1)
for i in start..last:
if c[i].kind in {goto, fork, join}:
if c[i].kind in {goto, fork}:
jumpTargets.incl(i+c[i].dest)
var i = start
while i <= last:
@@ -77,26 +78,22 @@ proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
case c[i].kind
of def, use:
result.add renderTree(c[i].n)
of goto, fork, join:
of goto, fork:
result.add "L"
result.addInt c[i].dest+i
result.add("\t#")
result.add(debugInfo(c[i].n.info))
result.add($c[i].n.info.line)
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.
var buf = ""
codeListing(c, buf, start, last)
echo buf
echo codeListing(c, start, last).alignTable
proc forkI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)
c.code.add Instr(n: n, kind: fork, dest: 0)
c.forks.add result
proc gotoI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)
@@ -104,6 +101,24 @@ proc gotoI(c: var Con; n: PNode): TPosition =
#[
Join is no more
===============
Instead of generating join instructions we adapt our traversal of the CFG.
When encountering a fork we split into two paths, we follow the path
starting at "pc + 1" until it encounters the joinpoint: "pc + forkInstr.dest".
If we encounter gotos that would jump further than the current joinpoint,
as can happen with gotos generated by unstructured controlflow such as break, raise or return,
we simply suspend following the current path, and follow the other path until the new joinpoint
which is simply the instruction pointer returned to us by the now suspended path.
If the path we are following now, also encounters a goto that exceeds the joinpoint
we repeat the process; suspending the current path and evaluating the other one with a new joinpoint.
If we eventually reach a common joinpoint we join the two paths.
This new "ping-pong" approach has the obvious advantage of not requiring join instructions, as such
cutting down on the CFG size but is also mandatory for correctly handling complicated cases
of unstructured controlflow.
Design of join
==============
@@ -252,33 +267,36 @@ duplicate the 'join' instructions on breaks and return exits!
]#
proc joinI(c: var Con; fromFork: TPosition; n: PNode) =
let dist = fromFork.int - c.code.len
c.code.add Instr(n: n, kind: join, dest: dist)
proc genLabel(c: Con): TPosition = TPosition(c.code.len)
proc genLabel(c: Con): TPosition =
result = TPosition(c.code.len)
template checkedDistance(dist): int =
doAssert low(int) div 2 + 1 < dist and dist < high(int) div 2
dist
proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
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)
c.code.add Instr(n: n, kind: goto, dest: checkedDistance(p.int - c.code.len))
proc patch(c: var Con, p: TPosition) =
# patch with current index
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
c.code[p.int].dest = checkedDistance(c.code.len - p.int)
proc gen(c: var Con; n: PNode)
proc popBlock(c: var Con; oldLen: int) =
for f in c.blocks[oldLen].fixups:
c.patch(f)
var exits: seq[TPosition]
exits.add c.gotoI(newNode(nkEmpty))
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
for finale in f[1]:
c.gen(finale)
exits.add c.gotoI(newNode(nkEmpty))
for e in exits:
c.patch e
c.blocks.setLen(oldLen)
template withBlock(labl: PSym; body: untyped) {.dirty.} =
var oldLen {.gensym.} = c.blocks.len
c.blocks.add TBlock(label: labl, fixups: @[])
template withBlock(labl: PSym; body: untyped) =
let oldLen = c.blocks.len
c.blocks.add TBlock(isTryBlock: false, label: labl)
body
popBlock(c, oldLen)
@@ -286,8 +304,6 @@ proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
proc gen(c: var Con; n: PNode) # {.noSideEffect.}
when true:
proc genWhile(c: var Con; n: PNode) =
# We unroll every loop 3 times. We emulate 0, 1, 2 iterations
@@ -299,12 +315,13 @@ when true:
Becomes:
if cond:
body
block:
if cond:
body
if cond:
body
if cond:
body
We still need to ensure 'break' resolves properly, so an AST to AST
translation is impossible.
@@ -330,25 +347,20 @@ when true:
if isTrue(n[0]):
# 'while true' is an idiom in Nim and so we produce
# better code for it:
for i in 0..2:
withBlock(nil):
withBlock(nil):
for i in 0..2:
c.gen(n[1])
else:
let oldForksLen = c.forks.len
var endings: array[3, TPosition]
for i in 0..2:
withBlock(nil):
withBlock(nil):
var endings: array[3, TPosition]
for i in 0..2:
c.gen(n[0])
endings[i] = c.forkI(n)
c.gen(n[1])
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
doAssert(c.forks.len == oldForksLen)
for i in countdown(endings.high, 0):
c.patch(endings[i])
else:
proc genWhile(c: var Con; n: PNode) =
# lab1:
# cond, tmp
@@ -356,7 +368,6 @@ else:
# body
# jmp lab1
# lab2:
let oldForksLen = c.forks.len
let lab1 = c.genLabel
withBlock(nil):
if isTrue(n[0]):
@@ -364,39 +375,14 @@ else:
c.jmpBack(n, lab1)
else:
c.gen(n[0])
let lab2 = c.forkI(n)
c.gen(n[1])
c.jmpBack(n, lab1)
c.patch(lab2)
setLen(c.forks, oldForksLen)
proc genBlock(c: var Con; n: PNode) =
withBlock(n[0].sym):
c.gen(n[1])
proc genJoins(c: var Con; n: PNode) =
for i in countdown(c.forks.high, 0): joinI(c, c.forks[i], n)
proc genBreak(c: var Con; n: PNode) =
genJoins(c, n)
let lab1 = c.gotoI(n)
if n[0].kind == nkSym:
#echo cast[int](n[0].sym)
for i in countdown(c.blocks.len-1, 0):
if c.blocks[i].label == n[0].sym:
c.blocks[i].fixups.add lab1
return
#globalError(n.info, "VM problem: cannot find 'break' target")
else:
c.blocks[c.blocks.high].fixups.add lab1
forkT(n):
c.gen(n[1])
c.jmpBack(n, lab1)
template forkT(n, body) =
let oldLen = c.forks.len
let lab1 = c.forkI(n)
body
c.patch(lab1)
c.joinI(lab1, n)
setLen(c.forks, oldLen)
proc genIf(c: var Con, n: PNode) =
#[
@@ -435,21 +421,16 @@ proc genIf(c: var Con, n: PNode) =
join F1
]#
let oldLen = c.forks.len
var endings: seq[TPosition] = @[]
for i in 0..<n.len:
var it = n[i]
let it = n[i]
c.gen(it[0])
if it.len == 2:
let elsePos = forkI(c, it[1])
c.gen(it[1])
endings.add(c.gotoI(it[1]))
c.patch(elsePos)
forkT(it[1]):
c.gen(it[1])
endings.add c.gotoI(it[1])
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
doAssert(c.forks.len == oldLen)
c.patch(endings[i])
proc genAndOr(c: var Con; n: PNode) =
# asgn dest, a
@@ -476,75 +457,90 @@ proc genCase(c: var Con; n: PNode) =
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
var endings: seq[TPosition] = @[]
let oldLen = c.forks.len
c.gen(n[0])
for i in 1..<n.len:
let it = n[i]
if it.len == 1:
c.gen(it[0])
elif i == n.len-1 and isExhaustive:
if it.len == 1 or (i == n.len-1 and isExhaustive):
# treat the last branch as 'else' if this is an exhaustive case statement.
c.gen(it.lastSon)
else:
let elsePos = c.forkI(it.lastSon)
c.gen(it.lastSon)
endings.add(c.gotoI(it.lastSon))
c.patch(elsePos)
forkT(it.lastSon):
c.gen(it.lastSon)
endings.add c.gotoI(it.lastSon)
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
doAssert(c.forks.len == oldLen)
proc genBlock(c: var Con; n: PNode) =
withBlock(n[0].sym):
c.gen(n[1])
proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
let lab1 = c.gotoI(n)
if c.blocks[i].isTryBlock:
c.blocks[i].raiseFixups.add lab1
else:
var trailingFinales: seq[PNode]
if c.inTryStmt > 0: #Ok, we are in a try, lets see which (if any) try's we break out from:
for b in countdown(c.blocks.high, i):
if c.blocks[b].isTryBlock:
trailingFinales.add c.blocks[b].finale
c.blocks[i].breakFixups.add (lab1, trailingFinales)
proc genBreak(c: var Con; n: PNode) =
if n[0].kind == nkSym:
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)
return
#globalError(n.info, "VM problem: cannot find 'break' target")
else:
for i in countdown(c.blocks.high, 0):
if not c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
return
proc genTry(c: var Con; n: PNode) =
let oldLen = c.forks.len
var endings: seq[TPosition] = @[]
inc c.inTryStmt
let oldFixups = c.tryStmtFixups.len
#let elsePos = c.forkI(n)
let oldLen = c.blocks.len
c.blocks.add TBlock(isTryBlock: true, finale: if n[^1].kind == nkFinally: n[^1] else: newNode(nkEmpty))
inc c.inTryStmt
c.gen(n[0])
dec c.inTryStmt
for i in oldFixups..c.tryStmtFixups.high:
let f = c.tryStmtFixups[i]
for f in c.blocks[oldLen].raiseFixups:
c.patch(f)
# we also need to produce join instructions
# for the 'fork' that might precede the goto instruction
if f.int-1 >= 0 and c.code[f.int-1].kind == fork:
c.joinI(TPosition(f.int-1), n)
setLen(c.tryStmtFixups, oldFixups)
c.blocks.setLen oldLen
#c.patch(elsePos)
for i in 1..<n.len:
let it = n[i]
if it.kind != nkFinally:
let endExcept = c.forkI(it)
c.gen(it.lastSon)
endings.add(c.gotoI(it))
c.patch(endExcept)
forkT(it):
c.gen(it.lastSon)
endings.add c.gotoI(it)
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
# join the 'elsePos' forkI instruction:
#c.joinI(c.forks.pop(), n)
c.patch(endings[i])
let fin = lastSon(n)
if fin.kind == nkFinally:
c.gen(fin[0])
doAssert(c.forks.len == oldLen)
template genNoReturn(c: var Con; n: PNode) =
# leave the graph
c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
proc genRaise(c: var Con; n: PNode) =
genJoins(c, n)
gen(c, n[0])
if c.inTryStmt > 0:
c.tryStmtFixups.add c.gotoI(n)
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
return
assert false #Unreachable
else:
genNoReturn(c, n)
@@ -553,12 +549,11 @@ proc genImplicitReturn(c: var Con) =
gen(c, c.owner.ast[resultPos])
proc genReturn(c: var Con; n: PNode) =
genJoins(c, n)
if n[0].kind != nkEmpty:
gen(c, n[0])
else:
genImplicitReturn(c)
genNoReturn(c, n)
genBreakOrRaiseAux(c, 0, n)
const
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
@@ -578,58 +573,43 @@ proc skipConvDfa*(n: PNode): PNode =
result = result[1]
else: break
proc genUse(c: var Con; orig: PNode) =
var n = orig
proc aliases*(obj, field: PNode): bool =
var n = field
var obj = obj
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 - {nkBracketExpr}:
n = n[0]
of nkBracketExpr:
gen(c, n[1])
of PathKinds0:
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)
proc aliases*(obj, field: PNode): bool =
var n = field
var obj = obj
while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}:
obj = obj[0]
while true:
if sameTrees(obj, n): return true
case n.kind
of PathKinds0, PathKinds1:
n = n[0]
else:
break
type InstrTargetKind* = enum
None, Full, Partial
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 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 isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
var n = orig
while true:
case n.kind
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr:
of PathKinds0 - {nkBracketExpr, nkHiddenDeref, nkDerefExpr}:
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}:
@@ -639,15 +619,16 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
of nkHiddenDeref, nkDerefExpr:
# We "own" sinkparam[].loc but not ourVar[].location as it is a nasty
# pointer indirection.
# 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 (isSinkParam(n.sym) or
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
owner.kind != skModule and
{sfGlobal, sfThread, sfCursor} * n.sym.flags == {} 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
@@ -660,43 +641,42 @@ 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 genDef(c: var Con; n: PNode) =
var m = n
# XXX do something about this duplicated logic here.
proc skipTrivials(c: var Con, n: PNode): PNode =
result = n
while true:
case m.kind
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr:
m = m[0]
case result.kind
of PathKinds0 - {nkBracketExpr}:
result = result[0]
of nkBracketExpr:
gen(c, m[1])
m = m[0]
of nkHiddenDeref, nkDerefExpr:
m = m[0]
else:
break
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)
if n.kind == nkSym and n.sym.kind in InterestingSyms:
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:
c.code.add Instr(n: orig, kind: use)
elif n.kind in nkCallKinds:
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 == 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.
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.
genDef(c, n[i])
# every call can potentially raise:
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
@@ -705,11 +685,11 @@ proc genCall(c: var Con; n: PNode) =
# goto exceptionHandler (except or finally)
# lab1:
# join F1
let endGoto = c.forkI(n)
c.tryStmtFixups.add c.gotoI(n)
c.patch(endGoto)
c.joinI(c.forks.pop(), n)
dec c.inCall
forkT(n):
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
break
proc genMagic(c: var Con; n: PNode; m: TMagic) =
case m
@@ -753,7 +733,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 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}:
of PathKinds0 - {nkObjDownConv, nkObjUpConv}:
genUse(c, n)
of nkIfStmt, nkIfExpr: genIf(c, n)
of nkWhenStmt:
@@ -770,18 +750,21 @@ 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: gen(c, n[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv:
of nkDiscardStmt, nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
gen(c, n[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
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 =
## constructs a control flow graph for ``body``.
var c = Con(code: @[], blocks: @[], owner: s)
gen(c, body)
genImplicitReturn(c)
shallowCopy(result, c.code)
withBlock(s):
gen(c, body)
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc):
result = c.code # will move
else:
shallowCopy(result, c.code)

View File

@@ -17,19 +17,28 @@ import
packages/docutils/rst, packages/docutils/rstgen,
json, xmltree, cgi, trees, types,
typesrenderer, astalgo, lineinfos, intsets,
pathutils, trees
pathutils, trees, tables, nimpaths, renderverbatim, osproc
from std/private/globs import nativeToUnixPath
const
exportSection = skField
htmldocsDir = RelativeDir"htmldocs"
docCmdSkip = "skip"
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, eg --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, section: TSections
toc, toc2, section: TSections
tocTable: array[TSymKind, Table[string, Rope]]
indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
@@ -41,22 +50,12 @@ type
exampleCounter: int
emitted: IntSet # we need to track which symbols have been emitted
# already. See bug #3655
destFile*: AbsoluteFile
thisDir*: AbsoluteDir
examples: string
wroteCss*: bool
exampleGroups: OrderedTable[string, ExampleGroup]
wroteSupportFiles*: 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
@@ -65,7 +64,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re
proc nimbleDir(): AbsoluteDir =
getNimbleFile(conf, file2).parentDir.AbsoluteDir
case conf.docRoot:
of "@default": # using `@` instead of `$` to avoid shell quoting complications
of docRootDefault:
result = getRelativePathFromConfigPath(conf, file)
let dir = nimbleDir()
if not dir.isEmpty:
@@ -81,16 +80,22 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re
result = getRelativePathFromConfigPath(conf, file)
if result.isEmpty: bail()
elif conf.docRoot.len > 0:
doAssert conf.docRoot.isAbsolute, conf.docRoot # or globalError
doAssert conf.docRoot.existsDir, conf.docRoot
result = relativeTo(file, conf.docRoot.AbsoluteDir)
# 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
else:
bail()
if isAbsolute(result.string):
result = file.string.splitPath()[1].RelativeFile
if isTitle:
result = result.string.nativeToUnix.RelativeFile
result = result.string.nativeToUnixPath.RelativeFile
else:
result = result.string.replace("..", "@@").RelativeFile ## refs #13223
result = result.string.replace("..", dotdotMangle).RelativeFile
doAssert not result.isEmpty
doAssert not isAbsolute(result.string)
proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
@@ -136,7 +141,7 @@ template declareClosures =
result = options.findFile(conf, s).string
if result.len == 0:
result = getCurrentDir() / s
if not existsFile(result): result = ""
if not fileExists(result): result = ""
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
@@ -147,13 +152,9 @@ proc parseRst(text, filename: string,
docgenFindFile, compilerMsgHandler)
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
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
ext: string, guessTarget: bool): AbsoluteFile =
if optWholeProject in conf.globalOptions or guessTarget:
let d = conf.outDir
createDir(d)
result = d / changeFileExt(filename, ext)
elif not conf.outFile.isEmpty:
@@ -167,6 +168,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.module = module
result.conf = conf
result.cache = cache
result.outDir = conf.outDir
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown},
docgenFindFile, compilerMsgHandler)
@@ -193,6 +195,7 @@ 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
@@ -211,15 +214,23 @@ 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)
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)
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])
result.emitted = initIntSet()
result.destFile = getOutFile2(conf, presentationPath(conf, filename),
outExt, htmldocsDir, false)
result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false)
result.thisDir = result.destFile.splitFile.dir
template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
@@ -292,11 +303,13 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
proc genComment(d: PDoc, n: PNode): string =
result = ""
var dummyHasToc: bool
if n.comment.len > 0:
renderRstToOut(d[], parseRst(n.comment, toFullPath(d.conf, n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options, d.conf), result)
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)
proc genRecCommentAux(d: PDoc, n: PNode): Rope =
if n == nil: return nil
@@ -328,11 +341,10 @@ 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.
result = ""
if n == nil: return
if startsWith(n.comment, "##"):
if n == nil: result = ""
elif startsWith(n.comment, "##"):
result = n.comment
if result.len < 1:
else:
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -343,8 +355,7 @@ 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,
htmldocsDir, sfMainModule notin module.flags)
let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, sfMainModule notin module.flags)
result = relativeTo(tmp, d.thisDir, '/').string
else:
result = extractFilename toFullPath(d.conf, FileIndex module.position)
@@ -357,6 +368,7 @@ 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
@@ -365,7 +377,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}",
[rope(esc(d.target, literal))])
[escLit])
of tokKeywordLow..tokKeywordHigh:
if kind in {tkProc, tkMethod, tkIterator, tkMacro, tkTemplate, tkFunc, tkConverter}:
procTokenPos = tokenPos
@@ -373,53 +385,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}",
[rope(esc(d.target, literal))])
[escLit])
of tkStrLit..tkTripleStrLit:
dispA(d.conf, result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [rope(esc(d.target, literal))])
"\\spanStringLit{$1}", [escLit])
of tkCharLit:
dispA(d.conf, result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[rope(esc(d.target, literal))])
[escLit])
of tkIntLit..tkUInt64Lit:
dispA(d.conf, result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
"\\spanDecNumber{$1}", [escLit])
of tkFloatLit..tkFloat128Lit:
dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
"\\spanFloatNumber{$1}", [escLit])
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}", [rope(esc(d.target, literal)), procLink])
"\\spanIdentifier{$1}", [escLit, 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,
rope(esc(d.target, literal))]
escLit]
else:
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
"\\spanIdentifier{$1}", [escLit])
of tkSpaces, tkInvalid:
result.add(literal)
of tkCurlyDotLe:
dispA(d.conf, result, "<span>" & # This span is required for the JS to work properly
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
"""<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>
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
<span class="pragma">""".replace("\n", "") # Must remove newlines because wrapped in a <pre>
of tkCurlyDotRi:
dispA(d.conf, result, """
template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
if renderRunnableExamples in renderFlags: fun "$1"
else: fun """
</span>
<span class="Other">$1</span>
</span>""".replace("\n", ""),
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
</span>""".replace("\n", "")
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
@@ -427,51 +439,73 @@ 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}",
[rope(esc(d.target, literal))])
[escLit])
proc testExample(d: PDoc; ex: PNode) =
proc exampleOutputDir(d: PDoc): AbsoluteDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) =
if d.conf.errorCounter > 0: return
let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
let outputDir = d.exampleOutputDir
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)
d.examples.add "import r\"" & outp.string & "\"\n"
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
proc runAllExamples(d: PDoc) =
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))
# This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however
# using `-d:js` (etc) cannot work properly, eg 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
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 from " & loc
docComment.comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd]
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
testExample(d, runnableExamples)
# we could also use `ret` instead here, to keep sources verbatim
writeExample(d, runnableExamples, rdoccmd)
result = (rdoccmd, ret)
when false:
proc extractImports(n: PNode; result: PNode) =
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
@@ -485,36 +519,99 @@ proc prepareExamples(d: PDoc; n: PNode) =
for imp in imports: runnableExamples.add imp
runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
if n.info.fileIndex != orig.info.fileIndex: return
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
]##
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:
prepareExamples(d, n)
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
dispA(d.conf, dest, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\\textbf{$1}\n", [rope"Examples:"])
"\n\\textbf{$1}\n", [msg.rope])
inc d.listingCounter
let id = $d.listingCounter
dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"])
# 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)
var dest2 = ""
renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex)
dest.add dest2
dest.add(d.config.getOrDefault"doc.listing_end" % id)
return rsRunnable
else: discard
for i in 0..<n.safeLen:
getAllRunnableExamplesRec(d, n[i], orig, dest)
return rsDone
# change this to `rsStart` if you want to keep generating doc comments
# and runnableExamples that occur after some code in routine
proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
getAllRunnableExamplesRec(d, n, n, 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]
if result.kind == nkAsgn and n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym:
doAssert result[0].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 isVisible(d: PDoc; n: PNode): bool =
result = false
@@ -689,8 +786,12 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
var result: Rope = nil
var literal, plainName = ""
var kind = tkEof
var comm = genRecComment(d, n) # call this here for the side-effect!
getAllRunnableExamples(d, n, comm)
var comm: Rope = nil
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
@@ -771,6 +872,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope, attype]))
d.tocTable[k].mgetOrPut(cleanPlainSymbol, nil).add(ropeFormatNamedVars(
d.conf, getConfigVar(d.conf, "doc.item.tocTable"),
["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
# use the plain one for callable elements, and the complex for the rest.
@@ -846,7 +955,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, changeFileExt(external, "")),
"$1", [rope esc(d.target, external.prettyLink),
rope changeFileExt(external, "html")])
proc exportSym(d: PDoc; s: PSym) =
@@ -856,7 +965,7 @@ 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, changeFileExt(external, "")),
"$1", [rope esc(d.target, external.prettyLink),
rope changeFileExt(external, "html")])
elif s.kind != skModule and s.owner != nil:
let module = originatingModule(s)
@@ -892,8 +1001,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 = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects])
result = newTreeI(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
@@ -905,8 +1014,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
effects.add params[i]
if effects.len > 0:
result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(cache, pragmaName), n.info), effects])
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1067,7 +1176,7 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
generateTags(d, lastSon(n[0]), r)
else: discard
proc genSection(d: PDoc, kind: TSymKind) =
proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
const sectionNames: array[skModule..skField, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs",
"Methods", "Iterators", "Converters", "Macros", "Templates", "Exports"
@@ -1077,17 +1186,23 @@ proc genSection(d: PDoc, kind: TSymKind) =
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), d.toc[kind]])
ord(kind).rope, title, rope(ord(kind) + 50), tocSource[kind]])
const nimdocOutCss = "nimdoc.out.css"
# `out` to make it easier to use with gitignore in user's repos
proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): Rope =
rope($relativeTo(outDir / linkto, destFile.splitFile().dir, '/'))
proc cssHref(outDir: AbsoluteDir, destFile: AbsoluteFile): Rope =
rope($relativeTo(outDir / nimdocOutCss.RelativeFile, destFile.splitFile().dir, '/'))
proc genOutFile(d: PDoc): Rope =
proc genOutFile(d: PDoc, groupedToc = false): Rope =
var
code, content: Rope
title = ""
@@ -1095,36 +1210,42 @@ proc genOutFile(d: PDoc): Rope =
var tmp = ""
renderTocEntries(d[], j, 1, tmp)
var toc = tmp.rope
for i in low(TSymKind)..high(TSymKind):
genSection(d, i)
for i in TSymKind:
var shouldSort = i in {skProc, skFunc} and groupedToc
genSection(d, i, shouldSort)
toc.add(d.toc[i])
if toc != nil:
toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
for i in low(TSymKind)..high(TSymKind): code.add(d.section[i])
for i in 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.nativeToUnix
let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnixPath
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("")
let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
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"
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"],
"tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"],
[title.rope, toc, d.modDesc, rope(getDateStr()),
rope(getClockStr()), code, d.modDeprecationMsg])
rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile), groupsection.rope])
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", "title", "tableofcontents", "moduledesc", "date", "time",
"nimdoccss", "dochackjs", "title", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics", "deprecationMsg"],
[cssHref(d.conf.outDir, d.destFile), title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()),
[relLink(d.conf.outDir, d.destFile, nimdocOutCss.RelativeFile),
relLink(d.conf.outDir, d.destFile, docHackJsFname.RelativeFile),
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
@@ -1132,35 +1253,39 @@ proc genOutFile(d: PDoc): Rope =
proc generateIndex*(d: PDoc) =
if optGenIndex in d.conf.globalOptions:
let dir = d.conf.docOutDir(htmldocsDir)
let dir = d.conf.outDir
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 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 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) =
proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
runAllExamples(d)
var content = genOutFile(d)
var content = genOutFile(d, groupedToc)
if optStdout in d.conf.globalOptions:
writeRope(stdout, content)
else:
template outfile: untyped = d.destFile
#let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, htmldocsDir)
#let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt)
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.wroteCss:
let cssSource = $d.conf.getPrefixDir() / "doc" / "nimdoc.css"
let cssDest = $dir / nimdocOutCss
copyFile(cssSource, cssDest)
d.wroteCss = true
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
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
@@ -1187,6 +1312,8 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
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) =
@@ -1261,18 +1388,20 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
if not writeRope(content, filename):
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
var content = mergeIndexes(conf.projectFull.string).rope
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
var content = mergeIndexes(dir).rope
var outFile = RelativeFile"theindex"
if conf.outFile != RelativeFile"":
outFile = conf.outFile
var outFile = outFile
if outFile.isEmpty: outFile = theindexFname.RelativeFile.changeFileExt("")
let filename = getOutFile(conf, outFile, HtmlExt)
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), [
"nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time",
"nimdoccss", "dochackjs",
"title", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
[cssHref(conf.outDir, filename), rope"Index", nil, nil, rope(getDateStr()),
[relLink(conf.outDir, filename, nimdocOutCss.RelativeFile),
relLink(conf.outDir, filename, docHackJsFname.RelativeFile),
rope"Index", nil, nil, rope(getDateStr()),
rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available

View File

@@ -29,6 +29,7 @@ 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:
@@ -38,7 +39,7 @@ template closeImpl(body: untyped) {.dirty.} =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutput(g.doc, useWarning)
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:

View File

@@ -17,6 +17,8 @@ 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):
@@ -102,7 +104,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI =
case cc
of ccDefault: result = DEFAULT_ABI
of ccNimCall: 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,6 +21,7 @@ type
# new symbol
config: ConfigRef
ic: IdentCache
instID: int
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
@@ -53,8 +54,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 and optNimV019 notin c.config.globalOptions:
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
if sfGenSym in s.flags:
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
if c.instLines: actual.info else: templ.info)
else:
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
@@ -166,7 +167,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef;
ic: IdentCache;
ic: IdentCache; instID: ref int;
fromHlo=false): PNode =
inc(conf.evalTemplateCounter)
if conf.evalTemplateCounter > evalTemplateLimit:
@@ -181,6 +182,7 @@ 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})
@@ -203,3 +205,5 @@ 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 /G7 ",
optSize: " /O1 /G7 ",
optSpeed: " /Ogityb2 ",
optSize: " /O1 ",
compilerExe: "cl",
cppCompiler: "cl",
compileTmpl: "/c$vccplatform $options $include /Fo$objfile $file",
buildGui: " /link /SUBSYSTEM:WINDOWS ",
compileTmpl: "/c$vccplatform $options $include /nologo /Fo$objfile $file",
buildGui: " /SUBSYSTEM:WINDOWS user32.lib ",
buildDll: " /LD",
buildLib: "lib /OUT:$libfile $objfiles",
linkerExe: "cl",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui $options",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /nologo $options",
includeCmd: " /I",
linkDirCmd: " /LIBPATH:",
linkLibCmd: " $1.lib",
@@ -170,6 +170,7 @@ 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:
@@ -185,32 +186,6 @@ 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 = (
@@ -238,58 +213,6 @@ 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 = (
@@ -316,43 +239,16 @@ compiler tcc:
cppXsupport: "",
props: {hasSwitchRange, hasComputedGoto, hasGnuAsm})
# Pelles C Compiler
compiler pcc:
# Pelles C
result = (
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:
compiler envcc:
result = (
name: "ucc",
name: "env",
objExt: "o",
optSpeed: " -O3 ",
optSize: " -O1 ",
compilerExe: "cc",
compilerExe: "",
cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file",
compileTmpl: "-c $ccenvflags $options $include -o $objfile $file",
buildGui: "",
buildDll: " -shared ",
buildLib: "", # XXX: not supported yet
@@ -367,7 +263,7 @@ compiler ucc:
structStmtFmt: "$1 $2",
produceAsm: "",
cppXsupport: "",
props: {})
props: {hasGnuAsm})
const
CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
@@ -375,23 +271,16 @@ const
nintendoSwitchGCC(),
llvmGcc(),
clang(),
lcc(),
bcc(),
dmc(),
wcc(),
vcc(),
tcc(),
pcc(),
ucc(),
envcc(),
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.
@@ -414,15 +303,14 @@ 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
let fullSuffix =
if conf.cmd == cmdCompileToCpp:
".cpp" & suffix
elif conf.cmd == cmdCompileToOC:
".objc" & suffix
elif conf.cmd == cmdCompileToJS:
".js" & suffix
else:
suffix
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 ""
if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and
optCompileOnly notin conf.globalOptions:
@@ -443,7 +331,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 i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
for c in CC: undefSymbol(conf.symbols, c.name)
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
proc addOpt(dest: var string, src: string) =
@@ -465,7 +353,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 i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
for c in CC: undefSymbol(conf.symbols, c.name)
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always"))
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
@@ -541,7 +429,6 @@ 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:
@@ -562,6 +449,8 @@ 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__")
@@ -589,21 +478,61 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} =
(conf.target.hostOS == osWindows)
proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool =
conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c")
conf.backend == backendCpp and not cfile.string.endsWith(".c")
proc envFlags(conf: ConfigRef): string =
result = if conf.backend == backendCpp:
getEnv("CXXFLAGS")
else:
getEnv("CFLAGS")
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
result = if useCpp(conf, cfile):
CC[compiler].cppCompiler
else:
CC[compiler].compilerExe
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
if result.len == 0:
rawMessage(conf, errGenerated,
"Compiler '$1' doesn't support the requested target" %
CC[compiler].name)
proc ccHasSaneOverflow*(conf: ConfigRef): bool =
if conf.cCompiler == ccGcc:
result = false # assume an old or crappy GCC
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
let (s, exitCode) = try: execCmdEx(exe & " --version") except: ("", 1)
if exitCode == 0:
var i = 0
var j = 0
# the version is the last part of the first line:
while i < s.len and s[i] != '\n':
if s[i] in {' ', '\t'}: j = i+1
inc i
if j > 0:
var major = 0
while j < s.len and s[j] in {'0'..'9'}:
major = major * 10 + (ord(s[j]) - ord('0'))
inc j
if i < s.len and s[j] == '.': inc j
while j < s.len and s[j] in {'0'..'9'}:
inc j
if j+1 < s.len and s[j] == '.' and s[j+1] in {'0'..'9'}:
# we found a third version number, chances are high
# we really parsed the version:
result = major >= 5
else:
result = conf.cCompiler == ccCLang
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
elif optMixedMode in conf.globalOptions and conf.backend != backendCpp: CC[compiler].cppCompiler
else: getCompilerExe(conf, compiler, AbsoluteFile"")
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
@@ -612,6 +541,11 @@ 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)
@@ -620,8 +554,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
var compilePattern: string
# compute include paths:
@@ -659,7 +594,8 @@ 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])
"lib", conf.libpath.string,
"ccenvflags", envFlags(conf)])
if optProduceAsm in conf.globalOptions:
if CC[conf.cCompiler].produceAsm.len > 0:
@@ -679,7 +615,8 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
"options", options, "include", includeCmd,
"nim", quoteShell(getPrefixDir(conf)),
"lib", quoteShell(conf.libpath),
"vccplatform", vccplatform(conf)])
"vccplatform", vccplatform(conf),
"ccenvflags", envFlags(conf)])
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
result = secureHash(
@@ -690,8 +627,10 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
getCompileCFileCmd(conf, cfile))
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM, cmdNone}:
return false
case conf.backend
of backendInvalid: doAssert false
of backendJs: return false # pre-existing behavior, but not sure it's good
else: discard
var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
var currentHash = footprint(conf, cfile)
@@ -726,14 +665,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) =
proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
objfiles: string, isDllBuild: bool): string =
if optGenStaticLib in conf.globalOptions:
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),
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output),
"objfiles", objfiles]
else:
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
@@ -830,19 +762,16 @@ 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 notin conf.globalOptions: return
# 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
@@ -913,6 +842,7 @@ 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
@@ -983,6 +913,7 @@ 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:
@@ -992,7 +923,8 @@ proc callCCompiler*(conf: ConfigRef) =
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd)
maybeRunDsymutil(conf, mainOutput)
for cmd in extraCmds:
execExternalProgram(conf, cmd, hintExecuting)
else:
linkCmd = ""
if optGenScript in conf.globalOptions:
@@ -1066,10 +998,16 @@ 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 "{\"compile\":[\L"
lit "{\L"
lit "\"outputFile\": "
str $output
lit ",\L\"compile\":[\L"
cfiles(conf, f, buf, conf.toCompile, false)
lit "],\L\"link\":[\L"
var objfiles = ""
@@ -1077,10 +1015,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink)
lit "],\L\"linkcmd\": "
str getLinkCmd(conf, conf.absOutFile, objfiles)
str getLinkCmd(conf, output, objfiles)
lit ",\L\"extraCmds\": "
lit $(%* conf.extraCmds)
lit $(%* getExtraCmds(conf, conf.absOutFile))
lit ",\L\"stdinInput\": "
lit $(%* conf.projectIsStdin)
@@ -1137,6 +1075,17 @@ 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*(stdin: PLLStream, filename: AbsoluteFile,
call: PNode; conf: ConfigRef): PLLStream =
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
@@ -214,9 +214,9 @@ proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile,
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
p.info.line = p.info.line + 1'u16
inc p.info.line
while llStreamReadLine(p.inp, p.x):
p.info.line = p.info.line + 1'u16
inc p.info.line
parseLine(p)
newLine(p)
result = p.outp

View File

@@ -1,89 +0,0 @@
#
#
# 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 != tyVar:
abstractInst).kind notin {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*(m: var TModel, n: PNode) =
proc invalidateFacts*(s: var seq[PNode], 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,8 +482,11 @@ proc invalidateFacts*(m: var TModel, 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(m.s):
if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil
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)
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:

View File

@@ -187,10 +187,9 @@ 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
importAllSymbolsExcept(c, m, emptySet)
importAllSymbols(c, m)
#importForwarded(c, m.ast, emptySet, m)
proc evalImport*(c: PContext, n: PNode): PNode =

18
compiler/index.nim Normal file
View File

@@ -0,0 +1,18 @@
##[
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

@@ -9,9 +9,9 @@ Platforms: """
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc
netbsd: i386;amd64
openbsd: i386;amd64
openbsd: i386;amd64;arm;arm64
dragonfly: i386;amd64
haiku: i386;amd64
android: i386;arm;arm64
@@ -35,9 +35,8 @@ App: Console
License: "copying.txt"
[Config]
Files: "config/nim.cfg"
Files: "config/nimdoc.cfg"
Files: "config/nimdoc.tex.cfg"
Files: "config/*.cfg"
Files: "config/config.nims"
[Documentation]
; Files: "doc/*.html"
@@ -77,6 +76,7 @@ Files: "lib"
[Other]
Files: "examples"
Files: "dist/nimble"
Files: "dist/fusion"
Files: "tests"
@@ -89,6 +89,7 @@ Files: "bin/vccexe.exe"
Files: "bin/nimgrab.exe"
Files: "bin/nimpretty.exe"
Files: "bin/testament.exe"
Files: "bin/nim-gdb.bat"
Files: "koch.exe"
Files: "finish.exe"
@@ -117,6 +118,8 @@ Files: "bin/nim"
[Unix]
InstallScript: "yes"
UninstallScript: "yes"
Files: "bin/nim-gdb"
Files: "bin/nim-gdb.bash"
[InnoSetup]

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 = result + toInt128(a32 * b00) shl 32
result = result + toInt128(a00 * b32) shl 32
result += toInt128(a32 * b00) shl 32
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 = dividend - denominator
dividend -= denominator
quotient = bitor(quotient, One)
denominator = denominator shr 1

View File

@@ -0,0 +1,117 @@
#
#
# 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 canAlias*(arg, ret: PType): bool =
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

@@ -86,6 +86,7 @@ type
generatedSyms: IntSet
typeInfoGenerated: IntSet
unique: int # for temp identifier generation
inSystem: bool
PProc = ref TProc
TProc = object
@@ -159,6 +160,14 @@ 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])
@@ -184,7 +193,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, tyOpt: result = etySeq
of tyString, tySequence: result = etySeq
of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs, tyUncheckedArray:
result = etyObject
of tyNil: result = etyNull
@@ -201,12 +210,11 @@ 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
@@ -240,11 +248,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
while i < s.name.s.len:
let c = s.name.s[i]
case c
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':
of 'A'..'Z', 'a'..'z', '_', '0'..'9':
x.add c
else:
x.add("HEX" & toHex(ord(c), 2))
@@ -261,11 +265,6 @@ 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,7 +465,48 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
else:
(a: a, tmp: b)
template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
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) =
# $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
@@ -478,8 +518,11 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
var
a, tmp = x.rdLoc
b, tmp2 = y.rdLoc
when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y)
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)
r.res = frmt % [a, b, tmp, tmp2]
r.kind = resExpr
@@ -496,13 +539,13 @@ template unsignedTrimmer(size: BiggestInt): Rope =
size.unsignedTrimmerJS
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
reassign = false) =
reassign: static[bool] = false) =
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
if reassign:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
when reassign:
let (a, tmp) = maybeMakeTempAssignable(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]
@@ -541,11 +584,10 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
gen(p, n[1], r)
xLoc = r.rdLoc
template applyFormat(frmtA, frmtB: string) =
if i == 0:
r.res = frmtA % [xLoc, yLoc]
else:
r.res = frmtB % [xLoc, yLoc]
template applyFormat(frmt) =
r.res = frmt % [xLoc, yLoc]
template applyFormat(frmtA, frmtB) =
if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
case op:
of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
@@ -560,8 +602,16 @@ 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: applyFormat("($1 << $2)", "($1 << $2)")
of mAshrI: applyFormat("($1 >> $2)", "($1 >> $2)")
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 mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
@@ -607,9 +657,11 @@ 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: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
of mFloatToStr:
useMagic(p, "nimFloatToString")
applyFormat "cstrToNimstr(nimFloatToString($1))"
of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
of mStrToStr, mUnown: applyFormat("$1", "$1")
of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1")
else:
assert false, $op
@@ -998,7 +1050,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
# 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, tyOpt, tyString}:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
xtyp = etySeq
case xtyp
of etySeq:
@@ -1009,7 +1061,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 == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
@@ -1022,8 +1074,15 @@ 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")
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
else:
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
@@ -1040,7 +1099,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, tyOpt, tyString}
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
@@ -1141,7 +1200,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
useMagic(p, "raiseFieldError")
useMagic(p, "makeNimstrLit")
let msg = genFieldError(field, disc)
let msg = genFieldDefect(field, disc)
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n",
setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===",
makeJSString(msg))
@@ -1171,9 +1230,13 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
first = firstOrd(p.config, typ[0])
if optBoundsCheck in p.options:
useMagic(p, "chckIndx")
r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp]
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]
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
@@ -1219,6 +1282,10 @@ 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)
@@ -1240,7 +1307,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")
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
of nkCheckedFieldExpr:
genCheckedFieldOp(p, n[0], n.typ, r)
of nkDotExpr:
@@ -1263,7 +1330,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
gen(p, n[0][0], r)
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")
else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
proc attachProc(p: PProc; content: Rope; s: PSym) =
@@ -1634,14 +1706,16 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
of tyObject:
var initList: Rope
createObjInitList(p, t, initIntSet(), initList)
result = ("{$1}") % [initList]
result = ("({$1})") % [initList]
if indirect: result = "[$1]" % [result]
of tyVar, tyPtr, tyLent, tyRef, tyPointer:
if mapType(p, t) == etyBaseIndex:
result = putToSeq("[null, 0]", indirect)
else:
result = putToSeq("null", indirect)
of tySequence, tyOpt, tyString, tyCString, tyProc:
of tySequence, tyString:
result = putToSeq("[]", indirect)
of tyCString, tyProc:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
@@ -1773,7 +1847,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).kind
case skipTypes(n[1].typ, abstractVar + abstractRange).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")
@@ -1872,7 +1946,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) = maybeMakeTemp(p, n[1], x)
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
lineF(p, "$1 = genericReset($3, $2);$n", [a,
genTypeInfo(p, n[1].typ), tmp])
@@ -1898,37 +1972,33 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mSwap: genSwap(p, n)
of mAppendStrCh:
binaryExpr(p, n, r, "addChar",
"if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }")
"addChar($1, $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:
r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [
a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
r.res = "$1 += $2;" % [lhs.rdLoc, rhs.rdLoc]
else:
r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [
lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, 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 = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
r.res = "$1.push($2);" % [x.rdLoc, c]
elif needsNoCopy(p, n[2]):
r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, y.rdLoc, tmp]
r.res = "$1.push($2);" % [x.rdLoc, y.rdLoc]
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 = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
r.res = "$1.push($2);" % [x.rdLoc, c]
r.kind = resExpr
of mConStrStr:
genConStrStr(p, n, r)
@@ -1960,23 +2030,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:
unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)")
unaryExpr(p, n, r, "", "($1).length")
of mHigh:
unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)")
unaryExpr(p, n, r, "", "(($1).length-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)")
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true)
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)")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
of mSetLengthStr:
binaryExpr(p, n, r, "mnewString", "($1 == null ? $3 = mnewString($2) : $3.length = $2)")
binaryExpr(p, n, r, "mnewString", "($1.length = $2)")
of mSetLengthSeq:
var x, y: TCompRes
gen(p, n[1], x)
@@ -1984,8 +2054,7 @@ 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 === null) $4 = [];
if ($4.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); }
r.res = """if ($1.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)")
@@ -2197,7 +2266,7 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
if hasFrameInfo(p):
result = frameCreate(p,
makeJSString(prc.owner.name.s & '.' & prc.name.s),
makeJSString(toFilename(p.config, prc.info)))
makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace)))
else:
result = nil
if p.beforeRetNeeded:
@@ -2353,7 +2422,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)
@@ -2408,7 +2477,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)
@@ -2492,6 +2561,8 @@ 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 */
@@ -2535,7 +2606,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(toFilename(p.config, p.module.module.info))))
makeJSString(toFilenameOption(p.config, p.module.module.info.fileIndex, foStacktrace))))
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)
@@ -2565,7 +2636,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 = newProc(globals, m, nil, m.module.options)
var p = newInitProc(globals, m)
p.unique = globals.unique
genModule(p, n)
p.g.code.add(p.locals)
@@ -2575,14 +2646,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 = newProc(globals, m, nil, m.module.options)
var p = newInitProc(globals, m)
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 = newProc(globals, m, nil, m.module.options)
var p = newInitProc(globals, m)
attachProc(p, prc)
result = globals.typeInfo & globals.constants & globals.code
@@ -2602,6 +2673,8 @@ 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)
@@ -2609,10 +2682,10 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if optSourcemap in m.config.globalOptions:
var map: SourceMap
(code, map) = genSourceMap($(code), mangled, outFile.string)
(code, map) = genSourceMap($(code), 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,7 +235,7 @@ 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.cmd == cmdCompileToJS and not isCompileTime
result = conf.backend == backendJs and not isCompileTime
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) =
createTypeBoundOps(g, nil, refType.lastSon, info)
@@ -291,8 +291,9 @@ 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") % [s.name.s, typeToString(s.typ), g.config$s.info])
elif owner.typ.callConv notin {ccClosure, ccDefault}:
" 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):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
incl(owner.typ.flags, tfCapturesEnv)
@@ -821,7 +822,8 @@ proc semCaptureSym*(s, owner: PSym) =
var o = owner.skipGenericOwner
while o != nil and o.kind != skModule:
if s.owner == o:
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
if owner.typ.callConv == ccClosure or owner.kind == skIterator or
owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags:
owner.typ.callConv = ccClosure
propagateClosure(owner.skipGenericOwner, s.owner)
else:
@@ -846,14 +848,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 gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# XXX backend == backendJs 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.cmd == cmdCompileToJS and not isCompileTime) or
g.config.backend == backendJs 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: TTokType
lastTok: TokType
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, tkDotDot, tkAnd, tkOr, tkXor}
tkIsnot, tkNot, tkOf, tkAs, tkFrom, 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: TToken; dontIndent: bool) =
proc emitComment(em: var Emitter; tok: Token; 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: TToken; dontIndent: bool) =
inc col
emitMultilineComment(em, lit, col, dontIndent)
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
template wasExportMarker(em): bool =
em.kinds.len > 0 and em.kinds[^1] == ltExportMarker
@@ -452,6 +452,9 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
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

View File

@@ -30,7 +30,7 @@ const
# don't forget to update the 'highlite' module if these charsets should change
type
TTokType* = enum
TokType* = enum
tkInvalid, tkEof, # order is important here!
tkSymbol, # keywords:
tkAddr, tkAnd, tkAs, tkAsm,
@@ -62,9 +62,10 @@ type
tkComma, tkSemiColon,
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon,
tkOpr, tkComment, tkAccent,
# these are fake tokens used by renderer.nim
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TTokTypes* = set[TTokType]
TokTypes* = set[TokType]
const
weakTokens = {tkComma, tkSemiColon, tkColon,
@@ -73,7 +74,7 @@ const
# tokens that should not be considered for previousToken
tokKeywordLow* = succ(tkSymbol)
tokKeywordHigh* = pred(tkIntLit)
TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]",
TokTypeToStr*: array[TokType, string] = ["tkInvalid", "[EOF]",
"tkSymbol",
"addr", "and", "as", "asm",
"bind", "block", "break", "case", "cast",
@@ -104,22 +105,19 @@ const
"tkPrefixOpr", "tkPostfixOpr"]
type
TNumericalBase* = enum
NumericalBase* = enum
base10, # base10 is listed as the first element,
# so that it is the correct default value
base2, base8, base16
CursorPosition* {.pure.} = enum ## XXX remove this again
None, InToken, BeforeToken, AfterToken
TToken* = object # a Nim token
tokType*: TTokType # the type of the token
Token* = object # a Nim token
tokType*: TokType # 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*: TNumericalBase # the numerical base; only valid for int
base*: NumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: int8 # leading spaces of an operator
strongSpaceB*: int8 # trailing spaces of an operator
@@ -127,26 +125,25 @@ 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
TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
TLexer* = object of TBaseLexer
ErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
Lexer* = 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
cursor*: CursorPosition
errorHandler*: TErrorHandler
errorHandler*: ErrorHandler
cache*: IdentCache
when defined(nimsuggest):
previousToken: TLineInfo
config*: ConfigRef
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
result = newLineInfo(L.fileIdx, tok.line, tok.col)
when defined(nimpretty):
result.offsetA = tok.offsetA
@@ -154,8 +151,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
result.commentOffsetA = tok.commentOffsetA
result.commentOffsetB = tok.commentOffsetB
proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isKeyword*(kind: TokType): bool =
(kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
@@ -169,28 +166,27 @@ proc isNimIdentifier*(s: string): bool =
inc(i)
result = true
proc `$`*(tok: TToken): string =
proc `$`*(tok: Token): string =
case 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]
of tkIntLit..tkInt64Lit: $tok.iNumber
of tkFloatLit..tkFloat64Lit: $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: tok.literal
of tkParLe..tkColon, tkEof, tkAccent: TokTypeToStr[tok.tokType]
else:
if tok.ident != nil:
result = tok.ident.s
tok.ident.s
else:
result = ""
""
proc prettyTok*(tok: TToken): string =
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
else: result = $tok
proc prettyTok*(tok: Token): string =
if isKeyword(tok.tokType): "keyword " & tok.ident.s
else: $tok
proc printTok*(conf: ConfigRef; tok: TToken) =
proc printTok*(conf: ConfigRef; tok: Token) =
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" &
TokTypeToStr[tok.tokType] & " " & $tok)
proc initToken*(L: var TToken) =
proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
@@ -203,7 +199,7 @@ proc initToken*(L: var TToken) =
L.commentOffsetA = 0
L.commentOffsetB = 0
proc fillToken(L: var TToken) =
proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
@@ -216,7 +212,7 @@ proc fillToken(L: var TToken) =
L.commentOffsetA = 0
L.commentOffsetB = 0
proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openBaseLexer(lex, inputstream)
lex.fileIdx = fileIdx
@@ -228,36 +224,36 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
lex.previousToken.fileIndex = fileIdx
lex.config = config
proc openLexer*(lex: var TLexer, filename: AbsoluteFile, inputstream: PLLStream;
proc openLexer*(lex: var Lexer, filename: AbsoluteFile, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
proc closeLexer*(lex: var TLexer) =
proc closeLexer*(lex: var Lexer) =
if lex.config != nil:
inc(lex.config.linesCompiled, lex.lineNumber)
closeBaseLexer(lex)
proc getLineInfo(L: TLexer): TLineInfo =
proc getLineInfo(L: Lexer): TLineInfo =
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
proc dispMessage(L: Lexer; 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: TLexer, msg: TMsgKind, arg = "") =
proc lexMessage*(L: Lexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg)
proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
proc lexMessageTok*(L: Lexer, msg: TMsgKind, tok: Token, arg = "") =
var info = newLineInfo(L.fileIdx, tok.line, tok.col)
L.dispMessage(info, msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
proc lexMessagePos(L: var Lexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
L.dispMessage(info, msg, arg)
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
proc matchTwoChars(L: Lexer, 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.} =
@@ -271,7 +267,6 @@ 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):
@@ -296,23 +291,22 @@ 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 TLexer, t: var TToken, replacementChar: char) =
template eatChar(L: var Lexer, t: var Token, replacementChar: char) =
t.literal.add(replacementChar)
inc(L.bufpos)
template eatChar(L: var TLexer, t: var TToken) =
template eatChar(L: var Lexer, t: var Token) =
t.literal.add(L.buf[L.bufpos])
inc(L.bufpos)
proc getNumber(L: var TLexer, result: var TToken) =
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]): Natural =
proc getNumber(L: var Lexer, result: var Token) =
proc matchUnderscoreChars(L: var Lexer, tok: var Token, chars: set[char]): Natural =
var pos = L.bufpos # use registers for pos, buf
result = 0
while true:
@@ -332,19 +326,19 @@ proc getNumber(L: var TLexer, result: var TToken) =
inc(pos)
L.bufpos = pos
proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
proc matchChars(L: var Lexer, tok: var Token, 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 TLexer, msg: string, startpos: int, msgKind = errGenerated) =
proc lexMessageLitNum(L: var Lexer, 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: TToken
var t: Token
t.literal = ""
L.bufpos = startpos # Use L.bufpos as pos because of matchChars
matchChars(L, t, literalishChars)
@@ -571,7 +565,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
raise newException(OverflowError, "number out of range: " & $result.literal)
raise newException(OverflowDefect, "number out of range: " & $result.literal)
if len != result.literal.len:
raise newException(ValueError, "invalid integer: " & $result.literal)
result.iNumber = cast[int64](iNumber)
@@ -581,7 +575,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
raise newException(OverflowError, "number out of range: " & $result.literal)
raise newException(OverflowDefect, "number out of range: " & $result.literal)
if len != result.literal.len:
raise newException(ValueError, "invalid integer: " & $result.literal)
result.iNumber = iNumber
@@ -607,12 +601,12 @@ proc getNumber(L: var TLexer, result: var TToken) =
except ValueError:
lexMessageLitNum(L, "invalid number: '$1'", startpos)
except OverflowError, RangeError:
except OverflowDefect, RangeDefect:
lexMessageLitNum(L, "number out of range: '$1'", startpos)
tokenEnd(result, postPos-1)
L.bufpos = postPos
proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) =
proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) =
template invalid() =
lexMessage(L, errGenerated,
"expected a hex digit, but found: " & L.buf[L.bufpos] &
@@ -637,7 +631,7 @@ proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) =
# Need to progress for `nim check`
inc(L.bufpos)
proc handleDecChars(L: var TLexer, xi: var int) =
proc handleDecChars(L: var Lexer, xi: var int) =
while L.buf[L.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
@@ -680,16 +674,11 @@ 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 TLexer, tok: var TToken) =
proc getEscapedChar(L: var Lexer, tok: var Token) =
inc(L.bufpos) # skip '\'
case L.buf[L.bufpos]
of 'n', 'N':
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')
tok.literal.add('\L')
inc(L.bufpos)
of 'p', 'P':
if tok.tokType == tkCharLit:
@@ -765,18 +754,13 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
else: lexMessage(L, errGenerated, "invalid character constant")
else: lexMessage(L, errGenerated, "invalid character constant")
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 =
proc handleCRLF(L: var Lexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
when not defined(nimpretty):
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
case L.buf[pos]
of CR:
@@ -793,7 +777,7 @@ type
raw,
generalized
proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
proc getString(L: var Lexer, tok: var Token, mode: StringMode) =
var pos = L.bufpos
var line = L.lineNumber # save linenumber for better error message
tokenBegin(tok, pos - ord(mode == raw))
@@ -859,7 +843,7 @@ proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
inc(pos)
L.bufpos = pos
proc getCharacter(L: var TLexer, tok: var TToken) =
proc getCharacter(L: var Lexer, tok: var Token) =
tokenBegin(tok, L.bufpos)
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
@@ -876,7 +860,7 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
tokenEndIgnore(tok, L.bufpos)
inc(L.bufpos) # skip '
proc getSymbol(L: var TLexer, tok: var TToken) =
proc getSymbol(L: var Lexer, tok: var Token) =
var h: Hash = 0
var pos = L.bufpos
tokenBegin(tok, pos)
@@ -906,21 +890,21 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
(tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
tok.tokType = tkSymbol
else:
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
tok.tokType = TokType(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 TLexer, tok: var TToken, pos: int,
proc endOperator(L: var Lexer, tok: var Token, 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 = TTokType(tok.ident.id - oprLow + ord(tkColon))
else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon))
L.bufpos = pos
proc getOperator(L: var TLexer, tok: var TToken) =
proc getOperator(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tokenBegin(tok, pos)
var h: Hash = 0
@@ -940,18 +924,15 @@ proc getOperator(L: var TLexer, tok: var TToken) =
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
proc getPrecedence*(tok: Token): 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 considerStrongSpaces(1)
tok.ident.s[^2] in {'-', '~', '='}: return 1
template considerAsgn(value: untyped) =
result = if tok.ident.s[^1] == '=': 1 else: value
@@ -967,15 +948,13 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): 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: TLexer): bool =
proc newlineFollows*(L: Lexer): bool =
var pos = L.bufpos
while true:
case L.buf[pos]
@@ -991,7 +970,7 @@ proc newlineFollows*(L: TLexer): bool =
else:
break
proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
isDoc: bool) =
var pos = start
var toStrip = 0
@@ -1056,7 +1035,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc scanComment(L: var TLexer, tok: var TToken) =
proc scanComment(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
@@ -1106,7 +1085,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc skip(L: var TLexer, tok: var TToken) =
proc skip(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tokenBegin(tok, pos)
tok.strongSpaceA = 0
@@ -1178,7 +1157,7 @@ proc skip(L: var TLexer, tok: var TToken) =
tok.tokType = tkComment
tok.indent = commentIndent
proc rawGetTok*(L: var TLexer, tok: var TToken) =
proc rawGetTok*(L: var Lexer, tok: var Token) =
template atTokenEnd() {.dirty.} =
when defined(nimsuggest):
# we attach the cursor to the last *strong* token
@@ -1186,8 +1165,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
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
@@ -1258,7 +1235,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
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()
@@ -1331,8 +1307,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
var lex: TLexer
var tok: TToken
var lex: Lexer
var tok: Token
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof
@@ -1346,11 +1322,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
proc getPrecedence*(ident: PIdent): int =
## assumes ident is binary operator already
var tok: TToken
var tok: Token
initToken(tok)
tok.ident = ident
tok.tokType =
if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TTokType(tok.ident.id + ord(tkSymbol))
TokType(tok.ident.id + ord(tkSymbol))
else: tkOpr
getPrecedence(tok, false)
getPrecedence(tok)

View File

@@ -10,9 +10,6 @@
## 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
@@ -26,6 +23,9 @@ 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
c: PContext # c can be nil, then we are called from lambdalifting!
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
@@ -60,9 +60,18 @@ 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:
@@ -72,14 +81,58 @@ proc genAddr(g: ModuleGraph; x: PNode): PNode =
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
result.add x
proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ[0])
result.add(newSymNode(op))
result.add genAddr(g, x)
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c.g, mLtI, "<", i)
cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.g, c.info, tyBool)
result[0] = cmp
result[1] = newNodeI(nkStmtList, c.info)
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 =
# generate: cast[ptr ObjType](cast[int](addr(x)) - offsetOf(objType.field))
let intType = getSysType(c.g, unknownLineInfo, tyInt)
let addrOf = newNodeIT(nkAddr, c.info, makePtrType(x.owner, x.typ))
addrOf.add newDeref(newSymNode(x))
let castExpr1 = newNodeIT(nkCast, c.info, intType)
castExpr1.add newNodeIT(nkType, c.info, intType)
castExpr1.add addrOf
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
let minusExpr = genBuiltin(c.g, mSubI, "-", castExpr1)
minusExpr.typ = intType
minusExpr.add offsetOf
let objPtr = makePtrType(objType.owner, objType)
result = newNodeIT(nkCast, c.info, objPtr)
result.add newNodeIT(nkType, c.info, objPtr)
result.add minusExpr
proc destructorCall(c: var 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:
result = destroy
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
case n.kind
of nkSym:
if c.filterDiscriminator != nil: return
let f = n.sym
let b = if c.kind == attachedTrace: y else: y.dotField(f)
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
@@ -101,8 +154,14 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
c.kind = prevKind
localEnforceDefaultOp = true
# copy the selector:
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
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
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, c.info)
# XXX generate 'if' that checks same branches
@@ -121,6 +180,11 @@ 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
of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
else:
@@ -179,29 +243,37 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
else:
fillBodyObjTImpl(c, t, body, x, y)
proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
proc newHookCall(c: var TLiftCtx; 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(g, x)
result.add genAddr(c.g, x)
else:
result.add x
if y != nil:
result.add y
proc newOpCall(op: PSym; x: PNode): PNode =
proc newOpCall(c: var TLiftCtx; 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(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(op, y))
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 useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
result = optSeqDestructors in c.g.config.globalOptions and
({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
({tfHasGCedMem, tfHasOwned} * t.flags != {} or usesBuiltinArc(t))
proc requiresDestructor(c: TLiftCtx; t: PType): bool {.inline.} =
result = optSeqDestructors in c.g.config.globalOptions and
@@ -225,7 +297,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
#else:
# markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newHookCall(c.g, op, x, y)
body.add newHookCall(c, op, x, y)
result = true
elif tfHasAsgn in t.flags:
var op: PSym
@@ -254,7 +326,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.g, op, x, y)
body.add newHookCall(c, op, x, y)
result = true
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
@@ -275,7 +347,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
if op != nil:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add destructorCall(c.g, op, x)
body.add destructorCall(c, op, x)
elif useNoGc(c, t):
internalError(c.g.config, c.info,
"type-bound operator could not be resolved")
@@ -293,7 +365,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add destructorCall(c.g, op, x)
body.add destructorCall(c, op, x)
result = true
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
@@ -305,7 +377,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(op, x, y)
body.add newDeepCopyCall(c, op, x, y)
result = true
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
@@ -318,22 +390,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 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)
cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.g, c.info, tyBool)
result[0] = cmp
result[1] = newNodeI(nkStmtList, c.info)
proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
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)
@@ -382,7 +438,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y
doAssert t.destructor != nil
moveCall.add destructorCall(c.g, t.destructor, x)
moveCall.add destructorCall(c, t.destructor, x)
body.add moveCall
of attachedDestructor:
# destroy all elements:
@@ -392,6 +448,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# follow all elements:
forallElements(c, t, body, x, y)
of attachedDispose:
forallElements(c, t, body, x, y)
body.add genBuiltin(c.g, mDestroy, "destroy", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -406,26 +463,32 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy:
doAssert t.assignment != nil
body.add newHookCall(c.g, t.assignment, x, y)
# XXX: replace these with assertions.
if t.assignment == nil:
return # protect from recursion
body.add newHookCall(c, t.assignment, x, y)
of attachedSink:
# we always inline the move for better performance:
let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y
doAssert t.destructor != nil
moveCall.add destructorCall(c.g, t.destructor, x)
moveCall.add destructorCall(c, t.destructor, x)
body.add moveCall
# alternatively we could do this:
when false:
doAssert t.asink != nil
body.add newHookCall(c.g, t.asink, x, y)
body.add newHookCall(c, t.asink, x, y)
of attachedDestructor:
doAssert t.destructor != nil
body.add destructorCall(c.g, t.destructor, x)
body.add destructorCall(c, t.destructor, x)
of attachedTrace:
body.add newHookCall(c.g, t.attachedOps[c.kind], x, y)
if t.attachedOps[c.kind] == nil:
return # protect from recursion
body.add newHookCall(c, t.attachedOps[c.kind], x, y)
of attachedDispose:
body.add newHookCall(c.g, t.attachedOps[c.kind], x, nil)
if t.attachedOps[c.kind] == nil:
return # protect from recursion
body.add newHookCall(c, t.attachedOps[c.kind], x, nil)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -435,7 +498,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y
doAssert t.destructor != nil
moveCall.add destructorCall(c.g, t.destructor, x)
moveCall.add destructorCall(c, t.destructor, x)
body.add moveCall
of attachedDestructor, attachedDispose:
body.add genBuiltin(c.g, mDestroy, "destroy", x)
@@ -446,6 +509,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.lastSon
createTypeBoundOps(c.g, c.c, elemType, c.info)
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
@@ -453,12 +518,12 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
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)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
var cond: PNode
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo)
else:
@@ -477,12 +542,11 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t))
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, 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:
@@ -526,7 +590,6 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
actions.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ))
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
@@ -556,7 +619,6 @@ 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
@@ -584,7 +646,6 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, x, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t))
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace, attachedDispose: discard
@@ -615,10 +676,7 @@ 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:
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)
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
if body.len == 0:
body.add des
else:
@@ -637,7 +695,6 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, xx, actions)
body.add newAsgnStmt(x, y)
of attachedDestructor:
actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ))
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace, attachedDispose: discard
@@ -646,7 +703,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, tyOpt, tyUncheckedArray, tyVar, tyLent:
tyPtr, tyUncheckedArray, tyVar, tyLent:
defaultOp(c, t, body, x, y)
of tyRef:
if c.g.config.selectedGC in {gcArc, gcOrc}:
@@ -722,12 +779,13 @@ 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:
tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:
#internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
discard
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyStatic, tyAlias, tySink:
tyGenericInst, 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 =
@@ -738,43 +796,51 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
typ.attachedOps[kind] = baseType.attachedOps[kind]
result = typ.attachedOps[kind]
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo): PSym =
if typ.kind == tyDistinct:
return produceSymDistinctType(g, c, typ, kind, info)
var a: TLiftCtx
a.info = info
a.g = g
a.kind = kind
a.c = c
let body = newNodeI(nkStmtList, info)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, typ.owner, info)
a.fn = result
a.asgnForType = typ
result = newSym(skProc, procname, 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)
var d: PNode
#if kind notin {attachedTrace, attachedDispose}:
dest.typ = makeVarType(typ.owner, typ)
d = newDeref(newSymNode(dest))
#else:
# dest.typ = typ
# d = newSymNode(dest)
if kind == attachedTrace:
src.typ = getSysType(g, info, tyPointer)
else:
src.typ = typ
result.typ = newProcType(info, typ.owner)
result.typ = newProcType(info, owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedDispose}:
result.typ.addParam src
var n = newNodeI(nkProcDef, info, bodyPos+1)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = newNodeI(nkStmtList, info)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym =
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)
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType:typ)
a.fn = result
let dest = result.typ.n[1].sym
let d = newDeref(newSymNode(dest))
let src = if kind in {attachedDestructor, attachedDispose}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
typ.attachedOps[kind] = result
@@ -782,8 +848,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
sfOverriden in typ.attachedOps[attachedDestructor].flags:
## compiler can use a combination of `=destroy` and memCopy for sink op
dest.flags.incl sfCursor
body.add newOpCall(typ.attachedOps[attachedDestructor], d[0])
body.add newAsgnStmt(d, newSymNode(src))
result.ast[bodyPos].add newOpCall(a, typ.attachedOps[attachedDestructor], d[0])
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
@@ -792,20 +858,35 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
tk = tyNone # no special casing for strings and seqs
case tk
of tySequence:
fillSeqOp(a, typ, body, d, newSymNode(src))
fillSeqOp(a, typ, result.ast[bodyPos], d, src)
of tyString:
fillStrOp(a, typ, body, d, newSymNode(src))
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, body, d, newSymNode(src))
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)
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ)
a.fn = result
a.asgnForType = typ
a.filterDiscriminator = field
a.addMemReset = true
let discrimantDest = result.typ.n[1].sym
let dst = newSym(skVar, getIdent(g.cache, "dest"), result, info)
dst.typ = makePtrType(typ.owner, typ)
let dstSym = newSymNode(dst)
let d = newDeref(dstSym)
let v = newNodeI(nkVarSection, info)
v.addVar(dstSym, genContainerOf(a, typ, field, discrimantDest))
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
var n = newNodeI(nkProcDef, info, bodyPos+1)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = body
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
discard "now a nop"
@@ -843,11 +924,6 @@ 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.
@@ -856,7 +932,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): return
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)
@@ -876,9 +952,18 @@ 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 canon.attachedOps[k] == nil:
if not generics[k]:
discard produceSym(g, c, canon, k, info)
else:
inst(canon.attachedOps[k], canon)

View File

@@ -10,10 +10,20 @@
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
import ropes, tables, pathutils
import ropes, tables, pathutils, hashes
const
explanationsBaseUrl* = "https://nim-lang.org/docs"
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
type
TMsgKind* = enum
@@ -23,7 +33,7 @@ type
errGeneralParseError,
errNewSectionExpected,
errInvalidDirectiveX,
errProveInit,
errProveInit, # deadcode
errGenerated,
errUser,
warnCannotOpenFile,
@@ -40,11 +50,15 @@ type
warnUnsafeSetLen,
warnUnsafeDefault,
warnProveInit, warnProveField, warnProveIndex,
warnUnreachableElse, warnUnreachableCode,
warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser,
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated,
warnObservableStores,
warnUser,
hintSuccess, hintSuccessX, hintCC,
hintLineTooLong, hintXDeclaredButNotUsed,
hintXCannotRaiseY,
hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
@@ -53,7 +67,8 @@ type
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintGlobalVar, hintExpandMacro,
hintUser, hintUserRaw,
hintExtendedContext
hintExtendedContext,
hintMsgOrigin, # since 1.3.5
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -66,7 +81,7 @@ const
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errInvalidDirectiveX: "invalid directive: '$1'",
errProveInit: "Cannot prove that '$1' is initialized.",
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
errGenerated: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
@@ -87,7 +102,8 @@ const
warnWriteToForeignHeap: "write to foreign heap",
warnUnsafeCode: "unsafe code: '$1'",
warnUnusedImportX: "imported and not used: '$1'",
warnInheritFromException: "inherit from a more precise exception type like ValueError, IOError or OSError",
warnInheritFromException: "inherit from a more precise exception type like ValueError, " &
"IOError or OSError. If these don't suit, inherit from CatchableError or Defect.",
warnEachIdentIsTuple: "each identifier is a tuple",
warnUnsafeSetLen: "setLen can potentially expand the sequence, " &
"but the element type '$1' doesn't have a valid default value",
@@ -95,10 +111,12 @@ 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: "'$1' might not have been initialized",
warnUninit: "use explicit initialization of '$1' for clarity",
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",
@@ -106,13 +124,15 @@ const
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnCaseTransition: "Potential object case transition, instantiate new object instead",
warnCycleCreated: "$1",
warnObservableStores: "observable stores to '$1'",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "$loc LOC; $sec sec; $mem; $build build; proj: $project; out: $output",
hintSuccessX: "${loc} lines; ${sec}s; $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'",
@@ -138,6 +158,7 @@ const
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
]
const
@@ -152,19 +173,20 @@ const
"UnsafeCode", "UnusedImport", "InheritFromException",
"EachIdentIsTuple",
"UnsafeSetLen", "UnsafeDefault",
"ProveInit", "ProveField", "ProveIndex",
"ProveInit", "ProveField", "ProveIndex", "UnreachableElse", "UnreachableCode",
"IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "CaseTransition", "CycleCreated", "User"]
"Spacing", "CaseTransition", "CycleCreated",
"ObservableStores", "User"]
HintsToStr* = [
"Success", "SuccessX", "CC", "LineTooLong",
"XDeclaredButNotUsed",
"XDeclaredButNotUsed", "XCannotRaiseY",
"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",
"User", "UserRaw", "ExtendedContext", "MsgOrigin",
]
const
@@ -177,6 +199,12 @@ const
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
proc msgToStr*(msg: TMsgKind): string =
case msg
of warnMin..warnMax: WarningsToStr[ord(msg) - ord(warnMin)]
of hintMin..hintMax: HintsToStr[ord(msg) - ord(hintMin)]
else: "" # we could at least do $msg - prefix `err`
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
@@ -186,11 +214,11 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores}
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
hintSource, hintGlobalVar, hintGCStats}
hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin}
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC}
@@ -245,6 +273,9 @@ 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,12 +71,9 @@ 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 =
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 = true
for i in 0..<substr.len:
if pos+i > last or s[pos+i] != substr[i]: return false
result = ""
if not substrEq(line, a, b, x):
@@ -84,11 +81,6 @@ 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
@@ -136,6 +128,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 = canonPragmaSpelling(w)
let wanted = specialWords[w]
if pragmaName != wanted:
lintReport(conf, info, wanted, pragmaName)

View File

@@ -91,8 +91,15 @@ 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 =
result = strTableGet(c.currentScope.symbols, s)
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)
proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):
@@ -231,6 +238,23 @@ 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 =
@@ -316,8 +340,7 @@ 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
contains(c.ambiguousSymbols, result.id):
elif checkAmbiguity in flags and result != nil and result.id in c.ambiguousSymbols:
errorUseQualifier(c, n.info, result)
of nkSym:
result = n.sym

View File

@@ -59,6 +59,13 @@ 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
@@ -151,7 +158,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)),
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
@@ -362,14 +369,3 @@ 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

@@ -177,3 +177,28 @@ proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
case t.kind
of tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64:
result = getSysMagic(g, info, "==", mEqI)
of tyEnum:
result = getSysMagic(g, info, "==", mEqEnum)
of tyBool:
result = getSysMagic(g, info, "==", mEqB)
of tyRef, tyPtr, tyPointer:
result = getSysMagic(g, info, "==", mEqRef)
of tyString:
result = getSysMagic(g, info, "==", mEqStr)
of tyChar:
result = getSysMagic(g, info, "==", mEqCh)
of tySet:
result = getSysMagic(g, info, "==", mEqSet)
of tyProc:
result = getSysMagic(g, info, "==", mEqProc)
else:
globalError(g.config, info,
"can't find magic equals operator for type kind " & $t.kind)

View File

@@ -13,13 +13,13 @@ when not defined(nimcore):
{.error: "nimcore MUST be defined for Nim's core tooling".}
import
llstream, strutils, ast, lexer, syntaxes, options, msgs,
llstream, strutils, os, ast, lexer, syntaxes, options, msgs,
condsyms, times,
sem, idents, passes, extccomp,
cgen, json, nversion,
platform, nimconf, passaux, depends, vm, idgen,
modules,
modulegraphs, tables, rod, lineinfos, pathutils
modulegraphs, tables, rod, lineinfos, pathutils, vmprofiler
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.errorMax = high(int) # do not stop after first error
graph.config.setErrorMaxHighMaybe
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.errorMax = high(int) # do not stop after first error
graph.config.setErrorMaxHighMaybe
semanticPasses(graph)
if json: registerPass(graph, docgen2JsonPass)
else: registerPass(graph, docgen2Pass)
@@ -68,16 +68,7 @@ when not defined(leanCompiler):
proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config
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
setOutFile(conf)
extccomp.initVars(conf)
semanticPasses(graph)
registerPass(graph, cgenPass)
@@ -89,6 +80,9 @@ proc commandCompileToC(graph: ModuleGraph) =
graph.config.notes = graph.config.mainPackageNotes
return
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
compileProject(graph)
if graph.config.errorCounter > 0:
return # issue #9933
@@ -105,13 +99,13 @@ proc commandJsonScript(graph: ModuleGraph) =
let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj)
when not defined(leanCompiler):
proc commandCompileToJS(graph: ModuleGraph) =
proc commandCompileToJS(graph: ModuleGraph) =
when defined(leanCompiler):
globalError(graph.config, unknownLineInfo, "compiler wasn't built with JS code generator")
else:
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")
@@ -119,7 +113,6 @@ when not defined(leanCompiler):
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)
@@ -136,7 +129,7 @@ proc interactivePasses(graph: ModuleGraph) =
registerPass(graph, evalPass)
proc commandInteractive(graph: ModuleGraph) =
graph.config.errorMax = high(int) # do not stop after first error
graph.config.setErrorMaxHighMaybe
interactivePasses(graph)
compileSystemModule(graph)
if graph.config.commandArgs.len > 0:
@@ -156,8 +149,8 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: TLexer
tok: TToken
L: Lexer
tok: Token
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:
@@ -181,63 +174,103 @@ proc mainCommand*(graph: ModuleGraph) =
conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath)
setId(100)
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
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:
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")
commandCompileToJS(graph)
of "doc0":
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) =
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
else:
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
commandDoc(cache, conf)
of "doc2", "doc":
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")
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)
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, eg for random.rand:
# ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
# ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
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):
@@ -253,41 +286,10 @@ proc mainCommand*(graph: ModuleGraph) =
conf.cmd = cmdRst2tex
loadConfigs(DocTexConfig, cache, conf)
commandRst2TeX(cache, conf)
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 "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 "gendepend":
conf.cmd = cmdGenDepend
commandGenDepend(graph)
@@ -306,15 +308,14 @@ proc mainCommand*(graph: ModuleGraph) =
var hints = newJObject() # consider factoring with `listHints`
for a in hintMin..hintMax:
let key = lineinfos.HintsToStr[ord(a) - ord(hintMin)]
hints[key] = %(a in conf.notes)
hints[a.msgToStr] = %(a in conf.notes)
var warnings = newJObject()
for a in warnMin..warnMax:
let key = lineinfos.WarningsToStr[ord(a) - ord(warnMin)]
warnings[key] = %(a in conf.notes)
warnings[a.msgToStr] = %(a in conf.notes)
var dumpdata = %[
(key: "version", val: %VersionAsString),
(key: "nimExe", val: %(getAppFilename())),
(key: "prefixdir", val: %conf.getPrefixDir().string),
(key: "libpath", val: %conf.libpath.string),
(key: "project_path", val: %conf.projectFull.string),
@@ -362,7 +363,9 @@ 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)
@@ -377,8 +380,18 @@ 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 = $conf.absOutFile
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
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,
@@ -395,5 +408,3 @@ proc mainCommand*(graph: ModuleGraph) =
echo " int tries: ", gCacheIntTries
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
ffDecimal, 3)
resetAttributes(conf)

View File

@@ -72,9 +72,7 @@ type
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
globalDestructors*: seq[PNode]
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.}
strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {.nimcall.}
compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.}
TPassContext* = object of RootObj # the pass's context

View File

@@ -91,8 +91,7 @@ when false:
if result.len > 0: return result
proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
if result.isNil: result = ""
resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
proc lookupPackage(pkg, subdir: PNode): string =
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
@@ -112,8 +111,7 @@ 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,22 +17,29 @@ import
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
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)
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, result.info)
packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, info)
initStrTable(packSym.tab)
graph.packageSyms.strTableAdd(packSym)
else:
let existing = strTableGet(packSym.tab, result.name)
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
let existing = strTableGet(packSym.tab, name)
if existing != nil and existing.info.fileIndex != info.fileIndex:
when false:
# we used to produce an error:
localError(graph.config, result.info,
localError(graph.config, info,
"module names need to be unique per Nimble package; module clashes with " &
toFullPath(graph.config, existing.info.fileIndex))
else:
@@ -40,10 +47,13 @@ proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; fil
# 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, result.info)
packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, 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
@@ -60,13 +70,15 @@ 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: getIdent(graph.cache, splitFile(filename).name),
name: getModuleIdent(graph, filename),
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)
@@ -74,7 +86,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
result = r
if result == nil:
result = newModule(graph, fileIdx)
result.flags = result.flags + flags
result.flags.incl flags
result.id = id
registerModule(graph, result)
else:
@@ -104,7 +116,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.owner.id == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
@@ -125,7 +137,7 @@ proc compileSystemModule*(graph: ModuleGraph) =
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:
fatal(conf, newLineInfo(conf, AbsoluteFile"command line", 1, 1), errGenerated,
fatal(conf, newLineInfo(conf, AbsoluteFile(commandLineDesc), 1, 1), errGenerated,
"command expects a filename")
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
@@ -135,7 +147,12 @@ 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,6 +10,17 @@
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
@@ -34,7 +45,6 @@ proc makeCString*(s: string): Rope =
res.add('\"')
result.add(rope(res))
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result.fullPath = fullPath
#shallow(result.fullPath)
@@ -57,6 +67,12 @@ 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
@@ -64,6 +80,7 @@ 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 =
@@ -80,15 +97,19 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
# This flag indicates that we are working with such a path here
pseudoPath = true
if conf.m.filenameToIndexTbl.hasKey(canon.string):
var canon2: string
forceCopy(canon2, canon.string) # because `canon` may be shallow
canon2.canonicalCase
if conf.m.filenameToIndexTbl.hasKey(canon2):
isKnownFile = true
result = conf.m.filenameToIndexTbl[canon.string]
result = conf.m.filenameToIndexTbl[canon2]
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[canon.string] = result
conf.m.filenameToIndexTbl[canon2] = result
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool
@@ -108,6 +129,7 @@ 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
@@ -132,7 +154,6 @@ 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: "
@@ -145,6 +166,7 @@ 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)
@@ -160,9 +182,6 @@ 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: "???")
@@ -213,16 +232,38 @@ 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, eg: /pathto/bar/foo.nim
foRelProject # relative to project path, eg: ../foo.nim
foMagicSauce # magic sauce, shortest of (foAbs, foRelProject)
foName # lastPathPart, eg: foo.nim
foShort # foName without extension, eg: foo
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 foShort: result = toFilename(conf, fileIdx)
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 =
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
toFilenameOption(conf, info, foMagicSauce)
template toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
toMsgFilename(conf, info.fileIndex)
@@ -233,10 +274,11 @@ 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.} =
# consider calling `helpers.lineInfoToString` instead
result = toMsgFilename(conf, info) & "(" & $info.line & ", " &
$(info.col + ColOffset) & ")"
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -261,15 +303,16 @@ 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):
@@ -298,40 +341,48 @@ 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)
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)
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)
proc coordToStr(coord: int): string =
if coord == -1: result = "???"
else: result = $coord
proc msgKindToString*(kind: TMsgKind): string =
proc msgKindToString*(kind: TMsgKind): string = MsgKindToStr[kind]
# later versions may provide translated error messages
result = MsgKindToStr[kind]
proc getMessageStr(msg: TMsgKind, arg: string): string =
result = msgKindToString(msg) % [arg]
proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) % [arg]
type
TErrorHandling = enum doNothing, doAbort, doRaise
type TErrorHandling* = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File
@@ -345,16 +396,18 @@ proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} =
if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, "No stack traceback available\n" &
"To create a stacktrace, rerun compilation with ./koch temp " &
conf.command & " <file>")
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])
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:
if msg >= errMin and msg <= errMax or
(msg in warnMin..warnMax and msg in conf.warningAsErrors):
inc(conf.errorCounter)
conf.exitcode = 1'i8
if conf.errorCounter >= conf.errorMax:
@@ -379,86 +432,40 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
if context.info != lastinfo and context.info != info:
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, context.info, instantiationFrom,
Severity.Error)
Severity.Hint)
else:
let message = if context.detail == "":
instantiationFrom
else:
instantiationOfFrom.format(context.detail)
styledMsgWriteln(styleBright,
PosFormat % [toMsgFilename(conf, context.info),
coordToStr(context.info.line.int),
coordToStr(context.info.col+ColOffset)],
resetStyle,
message)
styledMsgWriteln(styleBright, conf.toFileLineCol(context.info), " ", 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 sourceLine*(conf: ConfigRef; i: TLineInfo): string =
if i.fileIndex.int32 < 0: return ""
if conf.m.fileInfos[i.fileIndex.int32].lines.len == 0:
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:
try:
for line in lines(toFullPathConsiderDirty(conf, i)):
addSourceLine conf, i.fileIndex, line.string
for line in lines(toFullPathConsiderDirty(conf, fileIdx).string):
addSourceLine conf, fileIdx, line.string
except IOError:
discard
assert i.fileIndex.int32 < conf.m.fileInfos.len
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)
# can happen if the error points to EOF:
if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return ""
if i.line.int > num: return ""
result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1]
@@ -473,101 +480,127 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
of warnMin..warnMax: WarningTitle
of hintMin..hintMax: HintTitle
else: ErrorTitle
result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
coordToStr(info.col+ColOffset)] &
title &
getMessageStr(msg, arg)
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.noinline.} =
var
title: string
color: ForegroundColor
kind: string
ignoreMsg = false
sev: Severity
let kind = if msg != hintUserRaw: msg.msgToStr else: "" # xxx not sure why hintUserRaw is special
case msg
of errMin..errMax:
sev = Severity.Error
writeContext(conf, info)
title = ErrorTitle
color = ErrorColor
# 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
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
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 & (if kind.len > 0: KindFormat % kind else: ""), sev)
conf.structuredErrorHook(conf, info, s & kindmsg, sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind.len > 0:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind))
if msg == hintProcessing:
msgWrite(conf, ".")
else:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
if conf.hasHint(hintSource):
conf.writeSurroundingSrc(info)
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.msgToStr,
resetStyle)
handleError(conf, msg, eh, s)
proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal'
# was executed.
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.
conf.m.errorOutputs = {eStdOut, eStdErr}
liMessage(conf, info, msg, arg, doAbort)
liMessage(conf, info, msg, arg, doAbort, instLoc())
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doRaise)
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, arg: string) =
liMessage(conf, info, errGenerated, 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 localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doRaise, instLoc())
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing)
template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, 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, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing, instLoc())
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) =
liMessage(conf, info, errGenerated, format % params, doNothing, instLoc())
proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
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) =
if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort)
liMessage(conf, info, errInternal, errMsg, doAbort, info2)
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; info: TLineInfo, errMsg: string) =
internalErrorImpl(conf, info, errMsg, instLoc())
template assertNotNil*(conf: ConfigRef; e): untyped =
if e == nil: internalError(conf, $instantiationInfo())
e
template internalError*(conf: ConfigRef; errMsg: string) =
internalErrorImpl(conf, unknownLineInfo, errMsg, instLoc())
template internalAssert*(conf: ConfigRef, e: bool) =
if not e: internalError(conf, $instantiationInfo())
# 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())
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
@@ -577,25 +610,9 @@ proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
else:
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
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)]
])
template listMsg(title, r) =
msgWriteln(conf, title)
for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", a.msgToStr])
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)
proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax)
proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax)

View File

@@ -19,5 +19,10 @@ define:useStdoutAsStdmsg
styleCheck:error
@end
#define:useNodeIds
#gc:markAndSweep
@if nimHasWarningObservableStores:
warning[ObservableStores]: off
@end

View File

@@ -22,9 +22,10 @@ import
commands, options, msgs,
extccomp, strutils, os, main, parseopt,
idents, lineinfos, cmdlinehelper,
pathutils
pathutils, modulegraphs
include nodejs
from std/browsers import openDefaultBrowser
from nodejs import findNodeJs
when hasTinyCBackend:
import tccgen
@@ -33,20 +34,6 @@ 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
@@ -66,7 +53,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
config.commandLine.add ':'
config.commandLine.add p.val.quoteShell
if p.key == " ":
if p.key == "": # `-` was passed to indicate main project is stdin
p.key = "-"
if processArgument(pass, p, argsCount, config): break
else:
@@ -77,14 +64,13 @@ 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"]:
config.arguments.len > 0 and config.command.normalize notin ["run", "e", "r"]:
rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
supportsStdinFile: true,
processCmdLine: processCmdLine,
mainCommand: mainCommand
processCmdLine: processCmdLine
)
self.initDefinesProg(conf, "nim_compiler")
if paramCount() == 0:
@@ -92,7 +78,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
return
self.processCmdLineAndProjectPath(conf)
if not self.loadConfigsAndRunMainCommand(cache, conf): return
var graph = newModuleGraph(cache, conf)
if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return
mainCommand(graph)
if conf.hasHint(hintGCStats): echo(GC_getStatistics())
#echo(GC_getStatistics())
if conf.errorCounter != 0: return
@@ -100,11 +88,23 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
if conf.cmd == cmdRun:
tccgen.run(conf, conf.arguments)
if optRun in conf.globalOptions:
var ex = quoteShell conf.absOutFile
if conf.cmd == cmdCompileToJS:
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
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)
else:
execExternalProgram(conf, ex & ' ' & conf.arguments)
# support as needed
rawMessage(conf, errGenerated, "'$1 cannot handle --run" % [$conf.cmd])
when declared(GC_setMaxPause):
GC_setMaxPause 2_000

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 TLexer, tok: var TToken) =
proc ppGetTok(L: var Lexer, tok: var Token) =
# simple filter
rawGetTok(L, tok)
while tok.tokType in {tkComment}: rawGetTok(L, tok)
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool
proc parseAtom(L: var Lexer, tok: var Token; config: ConfigRef): bool =
if tok.tokType == tkParLe:
ppGetTok(L, tok)
result = parseExpr(L, tok, config)
@@ -35,21 +35,21 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = isDefined(config, tok.ident.s)
ppGetTok(L, tok)
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
proc parseAndExpr(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken; config: ConfigRef): bool =
proc parseExpr(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken; config: ConfigRef): bool =
proc evalppIf(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken; config: ConfigRef): bool =
#var condStack: seq[bool] = @[]
proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
proc doEnd(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool])
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
proc doElse(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
proc doElif(L: var Lexer, tok: var Token; 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 TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool]) =
var nestedIfs = 0
while true:
@@ -110,7 +110,7 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co
else:
ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
@@ -149,16 +149,16 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack
else:
lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok)
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
proc confTok(L: var Lexer, tok: var Token; 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: TLexer, tok: TToken) =
proc checkSymbol(L: Lexer, tok: Token) =
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
proc parseAssignment(L: var TLexer, tok: var TToken;
proc parseAssignment(L: var Lexer, tok: var Token;
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 TLexer, tok: var TToken;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: TLexer
tok: TToken
L: Lexer
tok: Token
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, vm, vmdef,
modulegraphs, idents, os, pathutils, passaux,
scriptconfig
options, sem, semdata, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
passaux, scriptconfig
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
@@ -81,6 +81,9 @@ 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"):
@@ -93,20 +96,22 @@ proc findNimStdLib*(): string =
proc findNimStdLibCompileTime*(): string =
## Same as ``findNimStdLib`` but uses source files used at compile time,
## and asserts on error.
const sourcePath = currentSourcePath()
result = sourcePath.parentDir.parentDir / "lib"
const exe = getCurrentCompilerExe()
result = exe.splitFile.dir.parentDir / "lib"
doAssert fileExists(result / "system.nim"), "result:" & result
proc createInterpreter*(scriptName: string;
searchPaths: openArray[string];
flags: TSandboxFlags = {}): Interpreter =
flags: TSandboxFlags = {},
defines = @[("nimscript", "true")],
registerOps = true): Interpreter =
var conf = newConfigRef()
var cache = newIdentCache()
var graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
for define in defines:
defineSymbol(conf.symbols, define[0], define[1])
registerPass(graph, semPass)
registerPass(graph, evalPass)
@@ -119,6 +124,8 @@ 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)
@@ -127,9 +134,15 @@ 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)
@@ -139,7 +152,7 @@ proc runRepl*(r: TLLRepl;
if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
conf.cmd = cmdInteractive
conf.errorMax = high(int)
conf.setErrorMaxHighMaybe
initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")

View File

@@ -39,7 +39,9 @@ const
type
TBaseLexer* = object of RootObj
bufpos*: int
buf*: string
buf*: cstring
bufStorage: string
bufLen: int
stream*: PLLStream # we read from this stream
lineNumber*: int # the current line number
# private data:
@@ -75,8 +77,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.buf.len)
toCopy = L.buf.len - L.sentinel - 1
assert(L.sentinel < L.bufLen)
toCopy = L.bufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
moveMem(addr L.buf[0], addr L.buf[L.sentinel + 1], toCopy)
@@ -90,7 +92,7 @@ proc fillBuffer(L: var TBaseLexer) =
# compute sentinel:
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.buf.len)
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
@@ -99,16 +101,18 @@ 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.buf.len
L.buf.setLen(L.buf.len * 2)
assert(L.buf.len - oldBufLen == oldBufLen)
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.bufStorage.setLen(L.bufLen)
L.buf = L.bufStorage
assert(L.bufLen - 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.buf.len - 1
s = L.bufLen - 1
proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
assert(pos <= L.sentinel)
@@ -142,7 +146,9 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
assert(bufLen > 0)
L.bufpos = 0
L.offsetBase = 0
L.buf = newString(bufLen)
L.bufStorage = newString(bufLen)
L.buf = L.bufStorage
L.bufLen = bufLen
L.sentinel = bufLen - 1
L.lineStart = 0
L.lineNumber = 1 # lines start at 1
@@ -156,9 +162,9 @@ proc getColNumber(L: TBaseLexer, pos: int): int =
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
result = ""
var i = L.lineStart
while not (L.buf[i] in {CR, LF, EndOfFile}):
result.add(L.buf[i])
inc(i)
result.add("\n")
while L.buf[i] notin {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"

47
compiler/nimpaths.nim Normal file
View File

@@ -0,0 +1,47 @@
##[
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 std/[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, b: var TBitSet) =
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
var first, j: Int128
first = firstOrd(conf, s.typ[0])
bitSetInit(b, int(getSize(conf, s.typ)))
bitSetInit(result, 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(b, toInt64(j - first))
bitSetIncl(result, toInt64(j - first))
inc(j)
else:
bitSetIncl(b, toInt64(getOrdValue(s[i]) - first))
bitSetIncl(result, toInt64(getOrdValue(s[i]) - first))
proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
@@ -106,9 +106,8 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
inc(e)
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
var x = toBitSet(conf, a)
let y = toBitSet(conf, b)
op(x, y)
result = toTreeSet(conf, x, a.typ, a.info)
@@ -118,31 +117,26 @@ 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 =
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
let x = toBitSet(conf, a)
let y = toBitSet(conf, b)
result = bitSetContains(x, y)
proc equalSets*(conf: ConfigRef; a, b: PNode): bool =
var x, y: TBitSet
toBitSet(conf, a, x)
toBitSet(conf, b, y)
let x = toBitSet(conf, a)
let y = toBitSet(conf, b)
result = bitSetEquals(x, y)
proc complement*(conf: ConfigRef; a: PNode): PNode =
var x: TBitSet
toBitSet(conf, a, x)
var x = toBitSet(conf, a)
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 =
var x: TBitSet
toBitSet(conf, a, x)
let x = toBitSet(conf, a)
result = toTreeSet(conf, x, a.typ, a.info)
proc cardSet*(conf: ConfigRef; a: PNode): BiggestInt =
var x: TBitSet
toBitSet(conf, a, x)
let x = toBitSet(conf, a)
result = bitSetCard(x)
proc setHasRange*(s: PNode): bool =

285
compiler/optimizer.nim Normal file
View File

@@ -0,0 +1,285 @@
#
#
# 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:
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:
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
prefixmatches, pathutils, nimpaths, tables
from terminal import isatty
from times import utc, fromUnix, local, getTime, format, DateTime
@@ -25,7 +25,7 @@ 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, optNilCheck, optRefCheck,
optOverflowCheck, optRefCheck,
optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck,
optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize,
@@ -39,10 +39,9 @@ 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]
@@ -57,6 +56,7 @@ 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
optSkipSystemConfigFile, # skip the system's cfg/nims config file
@@ -90,12 +90,14 @@ 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]
@@ -103,12 +105,26 @@ 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, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdNone,
cmdCompileToC, # deadcode
cmdCompileToCpp, # deadcode
cmdCompileToOC, # deadcode
cmdCompileToJS, # deadcode
cmdCompileToLLVM, # deadcode
cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdDump,
cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging)
@@ -120,11 +136,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, gcMarkAndSweep, gcArc, gcOrc,
gcHooks,
gcRefc, gcV2, gcGo
gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc,
gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo
# gcRefc and the GCs that follow it use a write barrier,
# as far as usesWriteBarrier() is concerned
@@ -140,13 +156,16 @@ type
destructor,
notnil,
dynamicBindSym,
forLoopMacros,
forLoopMacros, # not experimental anymore; remains here for backwards compatibility
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,
@@ -162,8 +181,8 @@ type
disabledSf, writeOnlySf, readOnlySf, v2Sf
TSystemCC* = enum
ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl
ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc,
ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl
ExceptionSystem* = enum
excNone, # no exception system selected yet
@@ -180,6 +199,7 @@ type
nimname*: string
cname*, obj*: AbsoluteFile
flags*: set[CfileFlag]
customArgs*: string
CfileList* = seq[Cfile]
Suggest* = ref object
@@ -202,15 +222,24 @@ type
version*: int
Suggestions* = seq[Suggest]
ProfileInfo* = object
time*: float
count*: int
ProfileData* = ref object
data*: TableRef[TLineInfo, ProfileInfo]
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
@@ -237,6 +266,7 @@ 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
@@ -254,13 +284,16 @@ 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
@@ -271,6 +304,7 @@ 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
@@ -293,6 +327,15 @@ 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) =
@@ -307,7 +350,10 @@ 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 =
optHints in conf.options and note in conf.notes
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
proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool =
optWarns in conf.options and note in conf.notes
@@ -323,14 +369,14 @@ template depConfigFields*(fn) {.dirty.} =
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
const
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
optStyleCheck}
DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
optTrMacros, optNilCheck, optStyleCheck, optSinkInference}
optTrMacros, optStyleCheck, optCursorInference}
DefaultGlobalOptions* = {optThreadAnalysis,
optExcessiveStackTrace, optListFullPaths}
@@ -358,6 +404,9 @@ template newPackageCache*(): untyped =
else:
modeCaseSensitive)
proc newProfileData(): ProfileData =
ProfileData(data: newTable[TLineInfo, ProfileInfo]())
proc newConfigRef*(): ConfigRef =
result = ConfigRef(
selectedGC: gcRefc,
@@ -366,6 +415,7 @@ proc newConfigRef*(): ConfigRef =
options: DefaultOptions,
globalOptions: DefaultGlobalOptions,
macrosToExpand: newStringTable(modeStyleInsensitive),
arcToExpand: newStringTable(modeStyleInsensitive),
m: initMsgConfig(),
evalExpr: "",
cppDefines: initHashSet[string](),
@@ -399,7 +449,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: @[],
@@ -410,6 +460,7 @@ proc newConfigRef*(): ConfigRef =
arguments: "",
suggestMaxResults: 10_000,
maxLoopIterationsVM: 10_000_000,
vmProfileData: newProfileData(),
)
setTargetFromSystem(result.target)
# enable colors by default on terminals
@@ -447,7 +498,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
osAndroid, osNintendoSwitch}
osAndroid, osNintendoSwitch, osFreeRTOS}
of "linux":
result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd":
@@ -463,6 +514,10 @@ 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
@@ -497,8 +552,9 @@ const
DefaultConfigNims* = RelativeFile"config.nims"
DocConfig* = RelativeFile"nimdoc.cfg"
DocTexConfig* = RelativeFile"nimdoc.tex.cfg"
const oKeepVariableNames* = true
htmldocsDir* = htmldocsDirname.RelativeDir
docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications
oKeepVariableNames* = true
proc mainCommandArg*(conf: ConfigRef): string =
## This is intended for commands like check or parse
@@ -519,21 +575,23 @@ proc setConfigVar*(conf: ConfigRef; key, val: string) =
conf.configVars[key] = val
proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): AbsoluteFile =
conf.outDir / changeFileExt(filename, ext)
# 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)
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
createDir conf.outDir
result = conf.outDir / conf.outFile
when defined(posix):
if dirExists(result.string):
result.string.add ".out"
result = conf.absOutFile
createDir result.string.parentDir
proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
## Gets the prefix dir, usually the parent directory where the binary resides.
@@ -573,17 +631,6 @@ 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)
@@ -611,7 +658,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.cmd == cmdCompileToJS:
elif conf.backend == backendJs:
conf.projectPath / genSubDir
else:
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
@@ -641,12 +688,10 @@ 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"
let (head, tail) = splitPath(path.string)
result = getNimcacheDir(conf) / RelativeFile changeFileExt(tail, ext)
result = getNimcacheDir(conf) / RelativeFile path.string.splitPath.tail.changeFileExt(ext)
proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
createSubDir: bool = true): AbsoluteFile =
let (head, tail) = splitPath(f.string)
let subdir = getNimcacheDir(conf)
if createSubDir:
try:
@@ -654,7 +699,7 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
except OSError:
writeLine(stdout, "cannot create directory: " & subdir.string)
quit(1)
result = subdir / RelativeFile tail
result = subdir / RelativeFile f.string.splitPath.tail
#echo "completeGeneratedFilePath(", f, ") = ", result
proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile =
@@ -704,7 +749,7 @@ proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile): RelativeF
proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile =
if f.isAbsolute:
result = if f.existsFile: AbsoluteFile(f) else: AbsoluteFile""
result = if f.fileExists: AbsoluteFile(f) else: AbsoluteFile""
else:
result = rawFindFile(conf, RelativeFile f, suppressStdlib)
if result.isEmpty:
@@ -718,7 +763,8 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile
const stdlibDirs = [
"pure", "core", "arch",
"pure/collections",
"pure/concurrency", "impure",
"pure/concurrency",
"pure/unidecode", "impure",
"wrappers", "wrappers/linenoise",
"windows", "posix", "js"]
@@ -839,3 +885,18 @@ 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

@@ -28,8 +28,6 @@ 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

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 low(TSymKind)..high(TSymKind):
for i in 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 low(TNodeKind)..high(TNodeKind):
for i in TNodeKind:
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
result.add(chr(i.ord))
@@ -176,6 +176,7 @@ type
arLocalLValue, # is an l-value, but local var; must not escape
# its stack frame!
arDiscriminant, # is a discriminant
arLentValue, # lent value
arStrange # it is a strange beast like 'typedesc[var T]'
proc exprRoot*(n: PNode): PSym =
@@ -199,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 == tyVar and it.len > 1:
if it.typ != nil and it.typ.kind in {tyVar, tyLent} 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]
@@ -213,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 == tyVar:
if n.typ != nil and n.typ.kind in {tyVar}:
result = arLValue
of nkSym:
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
@@ -222,6 +223,8 @@ 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:
@@ -230,7 +233,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 == tyVar: result = arStrange
if t.kind in {tyVar}: result = arStrange
of nkDotExpr:
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
@@ -260,9 +263,14 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
# types that are equal modulo distinction preserve l-value:
result = isAssignable(owner, n[1], isUnsafeAddr)
of nkHiddenDeref:
if isUnsafeAddr and n[0].typ.kind == tyLent: result = arLValue
elif n[0].typ.kind == tyLent: result = arDiscriminant
else: result = arLValue
let n0 = n[0]
if n0.typ.kind == tyLent:
if isUnsafeAddr or (n0.kind == nkSym and n0.sym.kind == skResult):
result = arLValue
else:
result = arLentValue
else:
result = arLValue
of nkDerefExpr, nkHiddenAddr:
result = arLValue
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
@@ -271,7 +279,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 == tyVar:
elif n.typ != nil and n.typ.kind in {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,10 +113,8 @@ 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.owner.id == graph.config.mainPackageId:
if module.getnimblePkgId == graph.config.mainPackageId:
graph.config.notes = graph.config.mainPackageNotes
else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
@@ -128,7 +126,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: TParsers
p: Parser
a: TPassContextArray
s: PLLStream
fileIdx = module.fileIdx
@@ -166,7 +164,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
else:
s = stream
while true:
openParsers(p, fileIdx, s, graph.cache, graph.config)
openParser(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
@@ -214,7 +212,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
else:
#echo "----- single\n", n
if not processTopLevelStmt(graph, n, a): break
closeParsers(p)
closeParser(p)
if s.kind != llsStdIn: break
closePasses(graph, a)
# id synchronization point for more consistent code generation:

View File

@@ -22,7 +22,7 @@ type
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
type
TInfoOSProp* = enum
@@ -177,6 +177,10 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
props: {ospNeedsPIC, ospPosix}),
(name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
@@ -189,7 +193,7 @@ type
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuWasm32
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuEsp, cpuWasm32
type
TEndian* = enum
@@ -223,6 +227,7 @@ const
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)]
type

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}
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert}
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
wThread, wAsmNoStackFrame,
@@ -61,18 +61,19 @@ const
wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
typePragmas* = declPragmas + {wMagic, wAcyclic,
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
wIncompleteStruct, wByCopy, wByRef,
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
fieldPragmas* = declPragmas + {
wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these?
wGuard, wBitsize, wCursor, wRequiresInit, wNoalias} - {wExportNims, wNodecl} # why exclude these?
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wNoalias}
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,
@@ -92,11 +93,10 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
isStatement: bool = false)
proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
proc recordPragma(c: PContext; n: PNode; args: varargs[string]) =
var recorded = newNodeI(nkCommentStmt, n.info)
recorded.add newStrNode(key, n.info)
recorded.add newStrNode(val, n.info)
if val2.len > 0: recorded.add newStrNode(val2, n.info)
for i in 0..args.high:
recorded.add newStrNode(args[i], n.info)
c.graph.recordStmt(c.graph, c.module, recorded)
const
@@ -179,7 +179,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.cmd == cmdCompileToC:
if c.config.backend == backendC:
let m = s.getModule()
incl(m.flags, sfCompileToCpp)
incl c.config.globalOptions, optMixedMode
@@ -238,7 +238,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 low(TMagic)..high(TMagic):
for m in TMagic:
if substr($m, 1) == v:
s.magic = m
break
@@ -247,7 +247,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
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall))
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind in nkPragmaCallKinds and n.len == 2:
@@ -257,8 +257,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 = resOptions + op
else: resOptions = resOptions - op
if isTurnedOn(c, n): resOptions.incl op
else: resOptions.excl op
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
if isTurnedOn(c, n):
@@ -326,35 +326,32 @@ 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
sym.typ.callConv == ccDefault:
tfExplicitCallConv notin sym.typ.flags:
sym.typ.callConv = ccCDecl
proc processNote(c: PContext, n: PNode) =
template handleNote(toStrArray, msgMin, notes) =
let x = findStr(toStrArray, n[0][1].ident.s)
if x >= 0:
nk = TNoteKind(x + ord(msgMin))
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:
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)
of wHint: handleNote(HintsToStr, hintMin, c.config.notes)
of wWarning: handleNote(WarningsToStr, warnMin, c.config.notes)
of wWarningAsError: handleNote(WarningsToStr, warnMin, c.config.warningAsErrors)
else: invalidPragma(c, n)
else: invalidPragma(c, n)
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
case w
@@ -364,7 +361,6 @@ 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}
@@ -473,14 +469,12 @@ 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)
@@ -496,11 +490,12 @@ proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile =
if result.isEmpty: result = AbsoluteFile s
proc processCompile(c: PContext, n: PNode) =
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile) =
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile; customArgs: string) =
var cf = Cfile(nimname: splitFile(src).name,
cname: src, obj: dest, flags: {CfileFlag.External})
cname: src, obj: dest, flags: {CfileFlag.External},
customArgs: customArgs)
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src.string, dest.string)
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
proc getStrLit(c: PContext, n: PNode; i: int): string =
n[i] = c.semConstExpr(c, n[i])
@@ -518,9 +513,19 @@ proc processCompile(c: PContext, n: PNode) =
var found = parentDir(toFullPath(c.config, n.info)) / s
for f in os.walkFiles(found):
let obj = completeCfilePath(c.config, AbsoluteFile(dest % extractFilename(f)))
docompile(c, it, AbsoluteFile f, obj)
docompile(c, it, AbsoluteFile f, obj, "")
else:
let s = expectStrLit(c, n)
var s = ""
var customArgs = ""
if n.kind in nkCallKinds:
s = getStrLit(c, n, 1)
if n.len <= 3:
customArgs = getStrLit(c, n, 2)
else:
localError(c.config, n.info, "'.compile' pragma takes up 2 arguments")
else:
s = expectStrLit(c, n)
var found = AbsoluteFile(parentDir(toFullPath(c.config, n.info)) / s)
if not fileExists(found):
if isAbsolute(s): found = AbsoluteFile s
@@ -528,7 +533,7 @@ proc processCompile(c: PContext, n: PNode) =
found = findFile(c.config, s)
if found.isEmpty: found = AbsoluteFile s
let obj = toObjFile(c.config, completeCfilePath(c.config, found, false))
docompile(c, it, found, obj)
docompile(c, it, found, obj, customArgs)
proc processLink(c: PContext, n: PNode) =
let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
@@ -538,7 +543,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 = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
result = newNodeI(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
var str = n[1].strVal
if str == "":
localError(con.config, n.info, "empty 'asm' statement")
@@ -569,7 +574,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
a = c + 1
else:
illFormedAstLocal(n, con.config)
result = newNode(nkAsmStmt, n.info)
result = newNodeI(nkAsmStmt, n.info)
proc pragmaEmit(c: PContext, n: PNode) =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -632,7 +637,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 = newNode(nkPragma, n.info, n.sons[i+1..^1])
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
strTableAdd(c.userPragmas, userPragma)
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
@@ -776,6 +781,15 @@ 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
@@ -803,8 +817,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.cmd != cmdCompileToCpp:
localError(c.config, it.info, "exportcpp requires `nim cpp`, got " & $c.config.cmd)
if c.config.backend != backendCpp:
localError(c.config, it.info, "exportcpp requires `cpp` backend, got " & $c.config.backend)
else:
incl(sym.flags, sfMangleCpp)
incl(sym.flags, sfUsed) # avoid wrong hints
@@ -825,7 +839,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.cmd != cmdCompileToJS:
if c.config.backend != backendJs:
localError(c.config, it.info, "`importjs` pragma requires the JavaScript target")
let name = getOptionalStr(c, it, "$1")
incl(sym.flags, sfImportc)
@@ -870,6 +884,9 @@ 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})
@@ -910,7 +927,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wNoreturn:
noVal(c, it)
# Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
if c.config.exc notin {excQuirky, excGoto}:
if c.config.exc != excQuirky:
incl(sym.flags, sfNoReturn)
if sym.typ[0] != nil:
localError(c.config, sym.ast[paramsPos][0].info,
@@ -984,7 +1001,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 = ccDefault
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
of wGcSafe:
noVal(c, it)
if sym != nil:
@@ -1039,7 +1056,9 @@ 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)
of wPop:
processPop(c, it)
result = true
of wPragma:
if not sym.isNil and sym.kind == skTemplate:
sym.flags.incl sfCustomPragma
@@ -1067,7 +1086,9 @@ 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)
else:
sym.typ.callConv = wordToCallConv(k)
sym.typ.flags.incl tfExplicitCallConv
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(c, it)
@@ -1078,6 +1099,10 @@ 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}:

View File

@@ -11,7 +11,7 @@
# This is needed for proper handling of forward declarations.
import
ast, astalgo, msgs, semdata, types, trees, strutils
ast, astalgo, msgs, semdata, types, trees, strutils, lookups
proc equalGenericParams(procA, procB: PNode): bool =
if procA.len != procB.len: return false
@@ -28,40 +28,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
if not exprStructuralEquivalent(a.ast, b.ast): return
result = true
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 =
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
@@ -83,15 +50,13 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
discard
result = nextIdentIter(it, scope.symbols)
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
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
when false:
proc paramsFitBorrow(child, parent: PNode): bool =

7
compiler/readme.md Normal file
View File

@@ -0,0 +1,7 @@
## 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.

View File

@@ -1,5 +0,0 @@
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,10 +20,11 @@ import
type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples,
renderIr
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
kind*: TTokType
kind*: TokType
length*: int16
sym*: PSym
@@ -31,6 +32,7 @@ type
TSrcGen* = object
indent*: int
lineLen*: int
col: int
pos*: int # current position for iteration over the buffer
idx*: int # current token index for iteration over the buffer
tokens*: TRenderTokSeq
@@ -47,11 +49,20 @@ 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)):
@@ -108,12 +119,11 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
g.inGenericParams = false
g.config = config
proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
setLen(g.tokens, g.tokens.len + 1)
g.tokens[^1].kind = kind
g.tokens[^1].length = int16(s.len)
g.tokens[^1].sym = sym
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
g.buf.add(s)
if kind != tkSpaces:
inc g.col, s.len
proc addPendingNL(g: var TSrcGen) =
if g.pendingNL >= 0:
@@ -123,6 +133,7 @@ proc addPendingNL(g: var TSrcGen) =
const newlines = "\n"
addTok(g, tkSpaces, newlines & spaces(g.pendingNL))
g.lineLen = g.pendingNL
g.col = g.pendingNL
g.pendingNL = - 1
g.pendingWhitespace = -1
elif g.pendingWhitespace >= 0:
@@ -131,7 +142,10 @@ proc addPendingNL(g: var TSrcGen) =
proc putNL(g: var TSrcGen, indent: int) =
if g.pendingNL >= 0: addPendingNL(g)
else: addTok(g, tkSpaces, "\n")
else:
addTok(g, tkSpaces, "\n")
g.col = 0
g.pendingNL = indent
g.lineLen = indent
g.pendingWhitespace = -1
@@ -168,21 +182,22 @@ proc dedent(g: var TSrcGen) =
dec(g.pendingNL, IndentWidth)
dec(g.lineLen, IndentWidth)
proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
if kind != tkSpaces:
addPendingNL(g)
if s.len > 0:
addTok(g, kind, s, sym)
inc(g.lineLen, s.len)
else:
g.pendingWhitespace = s.len
inc g.col, s.len
inc(g.lineLen, s.len)
proc putComment(g: var TSrcGen, s: string) =
if s.len == 0: return
var i = 0
let hi = s.len - 1
var isCode = (s.len >= 2) and (s[1] != ' ')
var ind = g.lineLen
let isCode = (s.len >= 2) and (s[1] != ' ')
let ind = g.col
var com = "## "
while i <= hi:
case s[i]
@@ -208,7 +223,7 @@ proc putComment(g: var TSrcGen, s: string) =
# compute length of the following word:
var j = i
while j <= hi and s[j] > ' ': inc(j)
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
if not isCode and (g.col + (j - i) > MaxLineLen):
put(g, tkComment, com)
optNL(g, ind)
com = "## "
@@ -240,7 +255,7 @@ proc maxLineLength(s: string): int =
inc(lineLen)
inc(i)
proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
proc putRawStr(g: var TSrcGen, kind: TokType, s: string) =
var i = 0
let hi = s.len - 1
var str = ""
@@ -290,15 +305,18 @@ proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
proc gcom(g: var TSrcGen, n: PNode) =
assert(n != nil)
if shouldRenderComment(g, n):
var oneSpaceAdded = 0
if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '):
put(g, tkSpaces, Space)
oneSpaceAdded = 1
# Before long comments we cannot make sure that a newline is generated,
# because this might be wrong. But it is no problem in practice.
if (g.pendingNL < 0) and (g.buf.len > 0) and
(g.lineLen < LineCommentColumn):
(g.col < LineCommentColumn):
var ml = maxLineLength(n.comment)
if ml + LineCommentColumn <= MaxLineLen:
put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
put(g, tkSpaces, spaces(LineCommentColumn - g.col))
dec g.col, oneSpaceAdded
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
proc gcoms(g: var TSrcGen) =
@@ -309,8 +327,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
@@ -326,7 +344,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 shl (size*8)) - 1)
var y = if size < sizeof(BiggestInt): x and ((1.BiggestInt shl (size*8)) - 1)
else: x
result = "0o" & toOct(y, size * 3)
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
@@ -449,8 +467,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 = result + lsub(g, n[^2]) + 2
if n[^1].kind != nkEmpty: result = result + lsub(g, n[^1]) + 3
if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2
if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3
of nkVarTuple:
if n[^1].kind == nkEmpty:
result = lcomma(g, n, 0, - 2) + len("()")
@@ -461,8 +479,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 = result + lsub(g, n[0])
result = result + lcomma(g, n, 1)
if n.len >= 1: result += lsub(g, n[0])
result += lcomma(g, n, 1)
of nkExprColonExpr: result = lsons(g, n) + 2
of nkInfix: result = lsons(g, n) + 2
of nkPrefix:
@@ -526,7 +544,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 = result + lsub(g, n[0]) + 2
if n[0].kind != nkEmpty: result += lsub(g, n[0]) + 2
of nkExceptBranch:
result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_")
of nkObjectTy:
@@ -565,7 +583,7 @@ proc hasCom(n: PNode): bool =
for i in 0..<n.len:
if hasCom(n[i]): return true
proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
proc putWithSpace(g: var TSrcGen, kind: TokType, s: string) =
put(g, kind, s)
put(g, tkSpaces, Space)
@@ -608,7 +626,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: TTokType,
proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TokType,
k: string) =
if n.len == 0: return # empty var sections are possible
putWithSpace(g, kind, k)
@@ -837,7 +855,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: TTokType
var t: TokType
var s = atom(g, n)
if s.len > 0 and s[0] in lexer.SymChars:
if n.kind == nkIdent:
@@ -845,12 +863,19 @@ proc gident(g: var TSrcGen, n: PNode) =
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
t = tkSymbol
else:
t = TTokType(n.ident.id + ord(tkSymbol))
t = TokType(n.ident.id + ord(tkSymbol))
else:
t = tkSymbol
else:
t = tkOpr
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
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):
s.add '_'
s.addInt n.sym.id
when defined(debugMagics):
@@ -874,12 +899,23 @@ proc gsub(g: var TSrcGen; n: PNode; i: int) =
else:
put(g, tkOpr, "<<" & $i & "th child missing for " & $n.kind & " >>")
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
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 skipHiddenNodes(n: PNode): PNode =
result = n
@@ -892,10 +928,11 @@ 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 OpChars: true
elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in OpChars: true
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
else: false
if isOperator:
@@ -954,12 +991,7 @@ 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 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:
if n.len > 1 and n.lastSon.kind in {nkStmtList, nkStmtListExpr}:
accentedName(g, n[0])
if n.len > 2:
put(g, tkParLe, "(")
@@ -967,10 +999,41 @@ 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])
@@ -978,16 +1041,34 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
else:
gsub(g, n, 1)
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
of nkHiddenStdConv, nkHiddenSubConv:
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")
put(g, tkBracketLe, "[")
gsub(g, n, 0)
put(g, tkBracketRi, "]")
if n.len > 0 and n[0].kind != nkEmpty:
put(g, tkBracketLe, "[")
gsub(g, n, 0)
put(g, tkBracketRi, "]")
put(g, tkParLe, "(")
gsub(g, n, 1)
put(g, tkParRi, ")")
@@ -1579,7 +1660,7 @@ proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
initSrcGen(r, renderFlags, newPartialConfigRef())
gsub(r, n)
proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
proc getNextTok*(r: var TSrcGen, kind: var TokType, literal: var string) =
if r.idx < r.tokens.len:
kind = r.tokens[r.idx].kind
let length = r.tokens[r.idx].length.int
@@ -1599,9 +1680,9 @@ proc quoteExpr*(a: string): string {.inline.} =
## can be used for quoting expressions in error msgs.
"'" & a & "'"
proc genFieldError*(field: PSym, disc: PSym): string =
proc genFieldDefect*(field: PSym, disc: PSym): string =
## this needs to be in a module accessible by jsgen, ccgexprs, and vm to
## provide this error msg FieldError; msgs would be better but it does not
## provide this error msg FieldDefect; 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 " &

152
compiler/renderverbatim.nim Normal file
View File

@@ -0,0 +1,152 @@
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, os, strutils,
intsets, ast, idents, algorithm, renderer, strutils,
msgs, modulegraphs, syntaxes, options, modulepaths,
lineinfos
@@ -100,37 +100,14 @@ 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])
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:
@@ -209,42 +186,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)
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:
sn.add cs[i].pnode[0]
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
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
@@ -291,17 +268,17 @@ proc hasAccQuoted(n: PNode): bool =
if hasAccQuoted(a):
return true
const extandedProcDefs = procDefs + {nkMacroDef, nkTemplateDef}
const extendedProcDefs = 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 extandedProcDefs:
of extendedProcDefs:
result = n[0].hasAccQuoted
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for a in n:
if a.hasAccQuotedDef:
if hasAccQuotedDef(a):
return true
else:
result = false
@@ -317,7 +294,7 @@ proc hasBody(n: PNode): bool =
case n.kind
of nkCommand, nkCall:
result = true
of extandedProcDefs:
of extendedProcDefs:
result = n[^1].kind == nkStmtList
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for a in n:
@@ -410,8 +387,7 @@ 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.
result = newSeq[seq[DepN]]()
var s = newSeq[DepN]()
var s: seq[DepN]
var idx = 0
for v in g.mitems:
if v.idx < 0:
@@ -423,7 +399,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

@@ -838,11 +838,12 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
of "warning": message(g.config, n.info, warnUser, n[1].strVal)
of "error": localError(g.config, n.info, errUser, n[1].strVal)
of "compile":
internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit
let cname = AbsoluteFile n[1].strVal
var cf = Cfile(nimname: splitFile(cname).name, cname: cname,
obj: AbsoluteFile n[2].strVal,
flags: {CfileFlag.External})
flags: {CfileFlag.External},
customArgs: n[3].strVal)
extccomp.addExternalFileToCompile(g.config, cf)
of "link":
extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal)
@@ -916,6 +917,8 @@ 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,16 +80,14 @@ 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(result)
result = low(typeof(result))
else:
result = high(result)
result = high(typeof(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(result)
result = low(typeof(result))
else:
result = high(result)
result = high(typeof(result))
proc `|abs|`*(a: BiggestInt): BiggestInt =
if a != low(a):
if a != low(typeof(a)):
if a >= 0: result = a
else: result = -a
else:
result = low(a)
result = low(typeof(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(a) and b == -1'i64:
result = high(result)
elif a == low(typeof(a)) and b == -1'i64:
result = high(typeof(result))
else:
result = a div b
@@ -74,6 +74,6 @@ proc `|*|`*(a, b: BiggestInt): BiggestInt =
return result
if floatProd >= 0.0:
result = high(result)
result = high(typeof(result))
else:
result = low(result)
result = low(typeof(result))

View File

@@ -228,11 +228,14 @@ 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 == gcUnselected:
conf.selectedGC = oldSelectedGC
if conf.selectedGC in {gcArc, gcOrc}:
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph)

View File

@@ -16,7 +16,8 @@ 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
lowerings, plugins/active, rod, lineinfos, strtabs, int128,
isolation_check, typeallowed
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
@@ -183,7 +184,7 @@ proc endsInNoReturn(n: PNode): bool =
var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
result = it.kind in nkLastBlockStmts or
result = it.kind in (nkLastBlockStmts-{nkReturnStmt}) or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc commonType*(x: PType, y: PNode): PType =
@@ -197,15 +198,13 @@ 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 '" &
$result.kind & "' as a '" & $kind & "'")
localError(c.config, n.info, "cannot use symbol of kind '$1' as a '$2'" %
[result.kind.toHumanStr, kind.toHumanStr])
when false:
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym:
@@ -229,20 +228,22 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags)
let t = typeAllowed(typ, kind, c, flags)
if t != nil:
var err: string
if t == typ:
localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
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)]
else:
localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
typeToString(typ), toHumanStr(kind)]
localError(c.config, info, err)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
typeAllowedCheck(c, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -323,7 +324,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
let oldErrorOutputs = c.config.m.errorOutputs
c.config.m.errorOutputs = {}
c.config.errorMax = high(int)
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
try:
result = evalConstExpr(c.module, c.graph, e)
@@ -377,14 +378,15 @@ 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
when false:
# hopefully not required:
proc resetSemFlag(n: PNode) =
excl n.flags, nfSem
for i in 0..<n.safeLen:
resetSemFlag(n[i])
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 =
@@ -399,8 +401,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
c.friendModules.add(s.owner.getModule)
idSynchronizationPoint(5000)
result = macroResult
excl(result.flags, nfSem)
#resetSemFlag n
resetSemFlag result
if s.typ[0] == nil:
result = semStmt(c, result, flags)
else:
@@ -468,7 +469,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, n, nOrig, sym)
result = evalMacroCall(c.module, c.graph, c.templInstCounter, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
if c.config.macrosToExpand.hasKey(sym.name.s):
@@ -481,15 +482,10 @@ proc forceBool(c: PContext, n: PNode): PNode =
if result == nil: result = n
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
let nn = semExprWithType(c, n)
result = fitNode(c, getSysType(c.graph, n.info, tyBool), nn, nn.info)
if result == nil:
result = forceBool(c, semConstExpr(c, n))
if result.kind != nkIntLit:
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
@@ -506,7 +502,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
n.add prc.ast
c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} =
var c = newContext(graph, module)
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
@@ -522,6 +518,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
c.semTypeNode = semTypeNode
c.instTypeBoundOp = sigmatch.instTypeBoundOp
c.hasUnresolvedArgs = hasUnresolvedArgs
c.templInstCounter = new int
pushProcCon(c, module)
pushOwner(c, c.module)
@@ -597,7 +594,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 =
proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} =
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,10 +94,6 @@ 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
@@ -219,7 +215,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam: candidates.add("\n unknown named parameter: " & $nArg[0])
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
@@ -318,7 +318,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
sym = nextOverloadIter(o, c, f)
let ident = considerQuotedIdent(c, f, n).s
if nfDotField in n.flags and nfExplicitCall notin n.flags:
if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}:
let sym = n[1].typ.sym
var typeHint = ""
if sym == nil:
@@ -495,9 +495,14 @@ proc updateDefaultParams(call: PNode) =
proc getCallLineInfo(n: PNode): TLineInfo =
case n.kind
of nkAccQuoted, nkBracketExpr, nkCall, nkCallStrLit, nkCommand:
getCallLineInfo(n[0])
of nkDotExpr: getCallLineInfo(n[1])
else: n.info
if len(n) > 0:
return getCallLineInfo(n[0])
of nkDotExpr:
if len(n) > 1:
return getCallLineInfo(n[1])
else:
discard
result = n.info
proc semResolvedCall(c: PContext, x: TCandidate,
n: PNode, flags: TExprFlags): PNode =
@@ -527,7 +532,10 @@ proc semResolvedCall(c: PContext, x: TCandidate,
for s in instantiateGenericParamList(c, gp, x.bindings):
case s.kind
of skConst:
x.call.add s.ast
if not s.ast.isNil:
x.call.add s.ast
else:
x.call.add c.graph.emptyNode
of skType:
x.call.add newSymNode(s, n.info)
else:
@@ -549,7 +557,7 @@ proc tryDeref(n: PNode): PNode =
result.add n
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode =
filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} =
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:
@@ -633,7 +641,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) & " type(s) but expected " & $expected)
"'; got " & $(n.len-1) & " typeof(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(c, n)
@@ -673,13 +681,14 @@ 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(tyVar, c)
x = newTypeS(param.typ.kind, c)
x.addSonSkipIntLit t.baseOfDistinct
else:
x = t.baseOfDistinct
call.add(newNodeIT(nkEmpty, fn.info, x))
if hasDistinct:
var resolved = semOverloadedCall(c, call, call, {fn.kind}, {})
let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind}
var resolved = semOverloadedCall(c, call, call, filter, {})
if resolved != nil:
result = resolved[0].sym
if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct):

View File

@@ -21,6 +21,7 @@ type
notes*: TNoteKinds
features*: set[Feature]
otherPragmas*: PNode # every pragma can be pushed
warningAsErrors*: TNoteKinds
POptionEntry* = ref TOptionEntry
PProcCon* = ref TProcCon
@@ -34,7 +35,6 @@ 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]]
@@ -84,6 +84,7 @@ 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!)
@@ -142,6 +143,7 @@ type
# would otherwise fail.
unusedImports*: seq[(PSym, TLineInfo)]
exportIndirections*: HashSet[(int, int)]
lastTLineInfo*: TLineInfo
template config*(c: PContext): ConfigRef = c.graph.config
@@ -210,9 +212,10 @@ proc considerGenSyms*(c: PContext; n: PNode) =
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
new(result)
result.options = conf.options
result.defaultCC = ccDefault
result.defaultCC = ccNimCall
result.dynlib = nil
result.notes = conf.notes
result.warningAsErrors = conf.warningAsErrors
proc pushOptionEntry*(c: PContext): POptionEntry =
new(result)
@@ -221,12 +224,14 @@ 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)
@@ -274,10 +279,13 @@ proc addToLib*(lib: PLib, sym: PSym) =
proc newTypeS*(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner(c))
proc makePtrType*(c: PContext, baseType: PType): PType =
result = newTypeS(tyPtr, c)
proc makePtrType*(owner: PSym, baseType: PType): PType =
result = newType(tyPtr, owner)
addSonSkipIntLit(result, baseType)
proc makePtrType*(c: PContext, baseType: PType): PType =
makePtrType(getCurrOwner(c), baseType)
proc makeTypeWithModifier*(c: PContext,
modifier: TTypeKind,
baseType: PType): PType =
@@ -314,7 +322,8 @@ 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
typedesc.addSonSkipIntLit(assertNotNil(c.config, typ))
internalAssert(c.config, typ != nil)
typedesc.addSonSkipIntLit(typ)
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info,
c.config.options).linkTo(typedesc)
return newSymNode(sym, info)
@@ -372,8 +381,7 @@ proc makeNotType*(c: PContext, t1: PType): PType =
result.flags.incl tfHasMeta
proc nMinusOne(c: PContext; n: PNode): PNode =
result = newNode(nkCall, n.info, @[
newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n])
result = newTreeI(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 =
@@ -382,9 +390,8 @@ 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 = newNode(nkRange, n.info, @[
newIntTypeNode(0, intType),
makeStaticExpr(c, nMinusOne(c, n))])
result.n = newTreeI(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, efFromHlo in flags)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, c.templInstCounter, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
popInfoContext(c.config)
@@ -62,12 +62,18 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semExprCheck(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}))
@@ -76,11 +82,7 @@ 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 =
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})
if result.kind == nkEmpty:
# do not produce another redundant error message:
result = errorNode(c, n)
result = semExprCheck(c, n, flags)
if result.typ == nil:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
@@ -176,7 +178,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
else:
discard
proc isCastable(conf: ConfigRef; dst, src: PType): bool =
proc isCastable(c: PContext; 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)
@@ -189,6 +191,14 @@ proc isCastable(conf: ConfigRef; 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)
@@ -201,7 +211,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool =
result = false
elif srcSize < 0:
result = false
elif typeAllowed(dst, skParam) != nil:
elif typeAllowed(dst, skParam, c) != nil:
result = false
elif dst.kind == tyProc and dst.callConv == ccClosure:
result = src.kind == tyProc and src.callConv == ccClosure
@@ -329,7 +339,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.config, targetType, castedExpr.typ):
if not isCastable(c, targetType, castedExpr.typ):
let tar = $targetType
let alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar
@@ -622,11 +632,12 @@ proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
proc isUnresolvedSym(s: PSym): bool =
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} != {})
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} != {})
proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
# Checks whether an expression depends on generic parameters that
@@ -652,7 +663,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.cmd == cmdCompileToCpp or
if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or
sfCompileToCpp in c.module.flags):
checkSonsLen(n, 1, c.config)
result = n[0]
@@ -704,7 +715,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 == tyVar:
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
let it = n[i]
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
if it.kind != nkHiddenAddr:
@@ -725,7 +736,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 == tyVar:
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
if n[i].kind != nkHiddenAddr:
n[i] = analyseIfAddressTaken(c, n[i])
@@ -784,7 +795,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) != nil: return
if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
var call = newNodeIT(nkCall, n.info, n.typ)
call.add(n[0])
@@ -945,8 +956,17 @@ 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(n[0].typ))
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))
localError(c.config, n.info, msg)
return errorNode(c, n)
result = nil
@@ -1184,17 +1204,6 @@ 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:
@@ -1263,6 +1272,54 @@ 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)
@@ -1293,28 +1350,6 @@ 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.
@@ -1327,40 +1362,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
return nil
else:
ty = ty.base
argIsType = true
else:
argIsType = isTypeExpr(n[0])
return tryReadingTypeField(c, n, i, ty.base)
elif isTypeExpr(n.sons[0]):
return tryReadingTypeField(c, n, i, ty)
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})
@@ -1404,7 +1409,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)
tryReadingGenericParam(t)
result = tryReadingGenericParam(c, n, i, t)
proc dotTransformation(c: PContext, n: PNode): PNode =
if isSymChoice(n[1]):
@@ -1552,10 +1557,9 @@ 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 = newNode(nkCall, n.info, sons = @[setterId, a[0],
semExprWithType(c, n[1])])
result = newTreeI(nkCall, n.info, setterId, a[0], semExprWithType(c, n[1]))
result.flags.incl nfDotSetter
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
if result != nil:
@@ -1568,17 +1572,22 @@ 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/var_t_return.html" % [
root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3" % [
root.name.s, renderTree(n, {renderNoComments}), url])
elif root.kind == skParam and root.position != 0:
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])
localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3" % [
root.name.s, renderTree(n, {renderNoComments}), url])
case n.kind
of nkHiddenAddr, nkAddr: return n
of nkHiddenDeref, nkDerefExpr: return n[0]
of 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:
@@ -1592,7 +1601,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} and x.kind == nkSym and x.sym.kind == skResult:
if (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView) 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
@@ -1702,9 +1711,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 != tyVar and
isAssignable(c, a) == arNone) or
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
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):
# Direct assignment to a discriminant is allowed!
localError(c.config, a.info, errXCannotBeAssignedTo %
renderTree(a, {renderNoComments}))
@@ -1724,7 +1733,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.config, n.info, rhsTyp, skResult)
typeAllowedCheck(c, n.info, rhsTyp, skResult)
lhs.typ = rhsTyp
c.p.resultSym.typ = rhsTyp
c.p.owner.typ[0] = rhsTyp
@@ -1745,17 +1754,21 @@ 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:
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
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``
var a = newNodeI(nkAsgn, n[0].info)
a.add newSymNode(c.p.resultSym)
a.add n[0]
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
n[0] = a
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")
@@ -1817,7 +1830,11 @@ 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: discard
else:
when false:
# XXX investigate what we really need here.
if isViewType(t):
n[0] = takeImplicitAddr(c, n[0], false)
proc semYield(c: PContext, n: PNode): PNode =
result = n
@@ -1845,29 +1862,32 @@ 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 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 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, n: PNode, onlyCurrentScope: bool): PSym =
proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
case n.kind
of nkIdent:
result = lookUpForDefined(c, n.ident, onlyCurrentScope)
of nkIdent, nkAccQuoted:
result = if onlyCurrentScope:
localSearchInScope(c, considerQuotedIdent(c, n))
else:
searchInScopes(c, considerQuotedIdent(c, n))
of nkDotExpr:
result = nil
if onlyCurrentScope: return
checkSonsLen(n, 2, c.config)
var m = lookUpForDefined(c, n[0], onlyCurrentScope)
var m = lookUpForDeclared(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:
@@ -1876,15 +1896,11 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
result = nil
proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
proc semDeclared(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)
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.intVal = ord lookUpForDeclared(c, n[1], onlyCurrentScope) != nil
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
@@ -2033,7 +2049,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 newNode(nkIdentDefs, n.info, ids)
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, dummyTemplate)
quotes[0] = tmpl[namePos]
@@ -2045,14 +2061,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
newIdentNode(getIdent(c.cache, "newIdentNode"), n.info)
else:
identNodeSym.newSymNode
quotes[1] = newNode(nkCall, n.info, @[identNode, newStrNode(nkStrLit, "result")])
result = newNode(nkCall, n.info, @[
quotes[1] = newTreeI(nkCall, n.info, identNode, newStrNode(nkStrLit, "result"))
result = newTreeI(nkCall, n.info,
createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
newNode(nkCall, n.info, quotes)])
newTreeI(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
@@ -2061,8 +2081,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if c.compilesContextId == 0:
inc c.compilesContextIdGenerator
c.compilesContextId = c.compilesContextIdGenerator
# do not halt after first error:
c.config.errorMax = high(int)
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
# open a scope for temporary symbol inclusions:
let oldScope = c.currentScope
@@ -2102,6 +2121,9 @@ 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:
@@ -2140,7 +2162,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 = result.flags - {sfCompilerProc, sfExportc, sfImportc}
result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
result.loc.r = nil
proc setMs(n: PNode, s: PSym): PNode =
@@ -2172,10 +2194,13 @@ 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), false)
of mDefinedInScope:
result = semDefined(c, setMs(n, s))
of mDeclared:
markUsed(c, n.info, s)
result = semDefined(c, setMs(n, s), true)
result = semDeclared(c, setMs(n, s), false)
of mDeclaredInScope:
markUsed(c, n.info, s)
result = semDeclared(c, setMs(n, s), true)
of mCompiles:
markUsed(c, n.info, s)
result = semCompiles(c, setMs(n, s), flags)
@@ -2415,7 +2440,7 @@ proc checkPar(c: PContext; n: PNode): TParKind =
for i in 0..<n.len:
if result == paTupleFields:
if (n[i].kind != nkExprColonExpr) or
n[i][0].kind notin {nkSym, nkIdent}:
n[i][0].kind notin {nkSym, nkIdent, nkAccQuoted}:
localError(c.config, n[i].info, errNamedExprExpected)
return paNone
else:
@@ -2562,6 +2587,43 @@ 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
@@ -2690,6 +2752,15 @@ 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

@@ -23,7 +23,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
result = newNode(nkEmpty)
return
case n.kind
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = copyNode(n)
of nkIdent, nkSym:
result = n
let ident = considerQuotedIdent(c.c, n)
@@ -52,8 +52,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
if n.kind == nkContinueStmt:
localError(c.c.config, n.info,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, n.len)
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = instFieldLoopBody(c, n[i], forLoop)

View File

@@ -475,15 +475,13 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
else:
localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkBracket:
idx = idx - toInt64(firstOrd(g.config, x.typ))
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
@@ -549,9 +547,13 @@ 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:
@@ -560,6 +562,8 @@ 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:
@@ -639,9 +643,9 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
discard
else:
result = magicCall(m, n, g)
except OverflowError:
except OverflowDefect:
localError(g.config, n.info, "over- or underflow")
except DivByZeroError:
except DivByZeroDefect:
localError(g.config, n.info, "division by zero")
of nkAddr:
var a = getConstExpr(m, n[0], g)
@@ -715,8 +719,14 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result.typ = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n, g)
of nkDotExpr: result = foldFieldAccess(m, n, g)
of nkCheckedFieldExpr:
result = foldFieldAccess(m, n[0], g)
of nkStmtListExpr:
if n.len == 2 and n[0].kind == nkComesFrom:
result = getConstExpr(m, n[1], g)
var i = 0
while i <= n.len - 2:
if n[i].kind in {nkComesFrom, nkCommentStmt, nkEmpty}: i.inc
else: break
if i == n.len - 1:
result = getConstExpr(m, n[i], g)
else:
discard

View File

@@ -28,7 +28,7 @@ proc getIdentNode(c: PContext; n: PNode): PNode =
type
GenericCtx = object
toMixin: IntSet
toMixin, toBind: 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:
if withinBind in flags or s.id in ctx.toBind:
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:
if withinBind in flags or s.id in ctx.toBind:
result = newDot(result, symChoice(c, n, s, scClosed))
elif s.isMixedIn:
result = newDot(result, symChoice(c, n, s, scForceOpen))
@@ -211,6 +211,8 @@ 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)
@@ -226,8 +228,11 @@ proc semGenericStmt(c: PContext, n: PNode,
var mixinContext = false
if s != nil:
incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr}
let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
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)
case s.kind
of skMacro:
if macroToExpand(s) and sc.safeLen <= 1:
@@ -260,7 +265,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:
inc first
first = result.safeLen # see trunnableexamples.fun3
of skGenericParam:
result[0] = newSymNodeTypeDesc(s, fn.info)
onUse(fn.info, s)
@@ -492,12 +497,14 @@ 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 = s.flags + {sfUsed, sfFromGeneric}
s.flags.incl {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)
initIdTable(typeMap.topLayer)
cl.typeMap = addr(typeMap)
cl.typeMap = LayeredIdTable()
initIdTable(cl.typeMap.topLayer)
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, addr(typeMap), info, nil)
var cl = initTypeVars(c, typeMap, info, nil)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
@@ -320,7 +320,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
popInfoContext(c.config)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
info: TLineInfo): PSym {.nosinks.} =
## 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,9 +42,6 @@ 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])
@@ -402,14 +399,18 @@ 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(n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
proc transform(procSym: PSym; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
result = shallowCopy(n)
if sameTypeOrNil(n.typ, old):
result.typ = fresh
if n.kind == nkSym and n.sym == oldParam:
result.sym = newParam
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
for i in 0 ..< safeLen(n):
result[i] = transform(n[i], old, fresh, oldParam, newParam)
result[i] = transform(procSym, n[i], old, fresh, oldParam, newParam)
#if n.kind == nkDerefExpr and sameType(n[0].typ, old):
# result =
@@ -423,21 +424,35 @@ 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(orig.ast, origParamType, newParamType, oldParam, newParam)
result.ast = transform(result, 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 =
checkMinSonsLen(n, 2, c.config)
checkSonsLen(n, 2, c.config)
openScope(c)
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]))
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]))
closeScope(c)
proc semOld(c: PContext; n: PNode): PNode =
@@ -512,12 +527,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 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, n[^1].sym.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == n[^1].sym:
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, n[^1].sym, n.info), n, attachedDestructor)
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
result = n
of mDestroy:
result = n
@@ -543,6 +560,13 @@ 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

View File

@@ -139,8 +139,7 @@ template quoteStr(s: string): string = "'" & s & "'"
proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string =
result = ""
for field in directFieldsInRecList(fieldsRecList):
let assignment = locateFieldInInitExpr(c, field.sym, initExpr)
if assignment != nil:
if locateFieldInInitExpr(c, field.sym, initExpr) != nil:
if result.len != 0: result.add ", "
result.add field.sym.name.s.quoteStr
@@ -154,20 +153,20 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
if assignment == nil:
constrCtx.missingFields.add r.sym
proc semConstructFields(c: PContext, recNode: PNode,
proc semConstructFields(c: PContext, n: PNode,
constrCtx: var ObjConstrContext,
flags: TExprFlags): InitStatus =
result = initUnknown
case recNode.kind
case n.kind
of nkRecList:
for field in recNode:
for field in n:
let status = semConstructFields(c, field, constrCtx, flags)
mergeInitStatus(result, status)
of nkRecCase:
template fieldsPresentInBranch(branchIdx: int): string =
let branch = recNode[branchIdx]
let branch = n[branchIdx]
let fields = branch[^1]
fieldsPresentInInitExpr(c, fields, constrCtx.initExpr)
@@ -176,12 +175,12 @@ proc semConstructFields(c: PContext, recNode: PNode,
let fields = branchNode[^1]
collectMissingFields(c, fields, constrCtx)
let discriminator = recNode[0]
let discriminator = n[0]
internalAssert c.config, discriminator.kind == nkSym
var selectedBranch = -1
for i in 1..<recNode.len:
let innerRecords = recNode[i][^1]
for i in 1..<n.len:
let innerRecords = n[i][^1]
let status = semConstructFields(c, innerRecords, constrCtx, flags)
if status notin {initNone, initUnknown}:
mergeInitStatus(result, status)
@@ -217,9 +216,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
localError(c.config, discriminatorVal.info, ("possible values " &
"$2 are in conflict with discriminator values for " &
"selected object branch $1.") % [$selectedBranch,
valsDiff.renderAsType(recNode[0].typ)])
valsDiff.renderAsType(n[0].typ)])
let branchNode = recNode[selectedBranch]
let branchNode = n[selectedBranch]
let flags = flags*{efAllowDestructor} + {efPreferStatic,
efPreferNilResult}
var discriminatorVal = semConstrField(c, flags,
@@ -230,7 +229,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
if discriminatorVal.kind notin nkLiterals and (
not isOrdinalType(discriminatorVal.typ, true) or
lengthOrd(c.config, discriminatorVal.typ) > MaxSetElements or
lengthOrd(c.config, recNode[0].typ) > MaxSetElements):
lengthOrd(c.config, n[0].typ) > MaxSetElements):
localError(c.config, discriminatorVal.info,
"branch initialization with a runtime discriminator only " &
"supports ordinal types with 2^16 elements or less.")
@@ -242,14 +241,14 @@ proc semConstructFields(c: PContext, recNode: PNode,
if ctorCase == nil:
if discriminatorVal.typ.kind == tyRange:
let rangeVals = c.getIntSetOfType(discriminatorVal.typ)
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
let recBranchVals = branchVals(c, n, selectedBranch, false)
let diff = rangeVals - recBranchVals
if diff.len != 0:
valuesInConflictError(diff)
else:
badDiscriminatorError()
elif discriminatorVal.sym.kind notin {skLet, skParam} or
discriminatorVal.sym.typ.kind == tyVar:
discriminatorVal.sym.typ.kind in {tyVar}:
localError(c.config, discriminatorVal.info,
"runtime discriminator must be immutable if branch fields are " &
"initialized, a 'let' binding is required.")
@@ -260,7 +259,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
else:
var
ctorBranchVals = branchVals(c, ctorCase, ctorIdx, true)
recBranchVals = branchVals(c, recNode, selectedBranch, false)
recBranchVals = branchVals(c, n, selectedBranch, false)
branchValsDiff = ctorBranchVals - recBranchVals
if branchValsDiff.len != 0:
valuesInConflictError(branchValsDiff)
@@ -271,14 +270,14 @@ proc semConstructFields(c: PContext, recNode: PNode,
failedBranch = selectedBranch
else:
# With an else clause, check that all other branches don't match:
for i in 1..<recNode.len - 1:
if recNode[i].caseBranchMatchesExpr(discriminatorVal):
for i in 1..<n.len - 1:
if n[i].caseBranchMatchesExpr(discriminatorVal):
failedBranch = i
break
if failedBranch != -1:
if discriminatorVal.typ.kind == tyRange:
let rangeVals = c.getIntSetOfType(discriminatorVal.typ)
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
let recBranchVals = branchVals(c, n, selectedBranch, false)
let diff = rangeVals - recBranchVals
if diff.len != 0:
valuesInConflictError(diff)
@@ -301,22 +300,22 @@ proc semConstructFields(c: PContext, recNode: PNode,
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = recNode.pickCaseBranch defaultValue
let matchedBranch = n.pickCaseBranch defaultValue
collectMissingFields matchedBranch
else:
result = initPartial
if discriminatorVal.kind == nkIntLit:
# When the discriminator is a compile-time value, we also know
# which branch will be selected:
let matchedBranch = recNode.pickCaseBranch discriminatorVal
let matchedBranch = n.pickCaseBranch discriminatorVal
if matchedBranch != nil: collectMissingFields matchedBranch
else:
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<recNode.len: collectMissingFields recNode[i]
for i in 1..<n.len: collectMissingFields n[i]
of nkSym:
let field = recNode.sym
let field = n.sym
let e = semConstrField(c, flags, field, constrCtx.initExpr)
result = if e != nil: initFull else: initNone

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