Compare commits

..

224 Commits

Author SHA1 Message Date
narimiran
88a0edba4b bump version to 0.20.2 2019-07-16 21:24:02 +02:00
Kaushal Modi
5a12553394 [bugfix] critbits styleCheck fix: consistent var naming (#11752)
(cherry picked from commit 44d80dd863)
2019-07-16 21:21:59 +02:00
Kaushal Modi
7469f5fa78 [bugfix] openssl styleCheck fix: consistent var naming (#11750)
(cherry picked from commit 3f7142fcfd)
2019-07-16 21:21:59 +02:00
Kaushal Modi
6bd301ca9c styleCheck fix: type naming: s/outType/OutType/ (#11749)
(cherry picked from commit 0b511b15ea)
2019-07-16 21:21:59 +02:00
Tristano Ajmone
0047f7cf4f Fix Typos in Internal Docs (#11735) [ci skip]
(cherry picked from commit 8550a8127c)
2019-07-16 21:21:47 +02:00
Araq
8be734bf46 fixes #11723
(cherry picked from commit 76f9ddb6ab)
2019-07-16 21:21:47 +02:00
narimiran
9b0cb52d74 styleCheck fix 2019-07-16 10:17:00 +02:00
Kartik Saranathan
1aefa74e46 fix broken link (#11736) [ci skip]
(cherry picked from commit ec9d0ee86d)
2019-07-15 16:18:34 +02:00
Araq
c0085bc2b7 styleCheck fixes [bugfix]
(cherry picked from commit dd7dd1b6dc)
2019-07-15 16:18:17 +02:00
Araq
43cba52ed8 styleCheck fixes [bugfix]
(cherry picked from commit ad67a46e5d)
2019-07-15 16:18:17 +02:00
Araq
d6d5dd30e9 styleCheck fixes [bugfix]
(cherry picked from commit 52cbd0c558)
2019-07-15 16:18:17 +02:00
Araq
073651237a newruntime: progress to make 'async' work with --newruntime
(cherry picked from commit edbe02b4e1)
2019-07-15 16:18:17 +02:00
Andreas Rumpf
f23ca7f539 makes devel green again
(cherry picked from commit df53c68a36)
2019-07-15 16:18:17 +02:00
Araq
2bf1985f1a 'nim check' stability improvements
(cherry picked from commit 58e0dad371)
2019-07-15 16:18:17 +02:00
Araq
abebc395d3 makes --styleCheck:error the default for the Nim compiler itself
(cherry picked from commit e06046ab51)
2019-07-15 16:18:17 +02:00
Araq
ac41aec348 minor update for the genode target
(cherry picked from commit fab70e4fe3)
2019-07-15 16:18:17 +02:00
Araq
575f688545 make 'koch temp' work again
(cherry picked from commit 44c12d9d20)
2019-07-15 16:18:17 +02:00
Araq
95fd0d0a6f [refactoring] moves transformation for 'spawn' into its own spawn.nim implementation
(cherry picked from commit 9db369063c)
2019-07-15 16:18:17 +02:00
alaviss
c4cbc5f449 os: confine osErrorMsg example to Linux (#11725)
POSIX does **not** define the exact number for each errors. This caused
a failure in docs building on Haiku.

(cherry picked from commit a59fb5b352)
2019-07-15 16:18:17 +02:00
Jacek Sieka
d5d661b70e times: use posix constant instead of import (#11692)
* times: use posix constant instead of import

* simplify clock id usage

(cherry picked from commit cf36e4a44a)
2019-07-15 16:18:17 +02:00
Andreas Rumpf
46cb304770 fixes #11715 (#11721)
(cherry picked from commit de1ede77fe)
2019-07-15 16:18:17 +02:00
narimiran
b4742cc496 fix failing tests 2019-07-15 09:39:35 +02:00
Araq
abd4330dd0 newruntime: refchecks:on|off switch
(cherry picked from commit 423e8cca91)
2019-07-15 08:06:47 +02:00
Araq
876d0aaade made --newruntime ready for multi-threading
(cherry picked from commit 416ba133ad)
2019-07-15 08:06:47 +02:00
Araq
8b6ea5d451 atomics.nim: minor improvements
(cherry picked from commit bb5ca0772e)
2019-07-15 08:06:47 +02:00
Araq
4771b08ab5 documented --newruntime switch
(cherry picked from commit f45a1b927a)
2019-07-15 08:06:47 +02:00
Araq
a59efc53f2 preparations to be able to use atomics in runtime_v2.nim
(cherry picked from commit 03ded27021)
2019-07-15 08:06:47 +02:00
Andreas Rumpf
ae04734031 fixes tcompiletimerange [bugfix] (#11720)
(cherry picked from commit 2895ad70c8)
2019-07-15 08:06:47 +02:00
Ico Doornekamp
75f0a7a7af Moved 'Case statement macros' documentation out of manual into manual_experimental (#11716)
(cherry picked from commit 38b836b49e)
2019-07-15 08:06:47 +02:00
Araq
d91b4b1bb7 [bugfix] VM: finally do inheritance properly
(cherry picked from commit 7606efc0bf)
2019-07-15 08:06:46 +02:00
Araq
5a11ae85b1 document 'nim' defines prefix
(cherry picked from commit 13253f4154)
2019-07-15 08:03:53 +02:00
Araq
8eb66f6c6b nimpretty: implement a --maxLineLen command line option
(cherry picked from commit 5bf3734984)
2019-07-15 08:03:53 +02:00
Araq
6f214131a2 JS codegen: supports toOpenArray [bugfix]
(cherry picked from commit eaf4b42ff9)
2019-07-15 08:03:53 +02:00
Araq
d2f9a40b3c koch temp bugfix
(cherry picked from commit 511b6ae27c)
2019-07-15 08:03:53 +02:00
Miran
622eadff52 nimpretty: fix #11700, no extra newlines (#11714)
(cherry picked from commit 2f0a50fa51)
2019-07-15 08:03:53 +02:00
Dominik Picheta
93b58ebe1b Give NilAccessError a message (#11706)
(cherry picked from commit b8be1ccb85)
2019-07-15 08:03:16 +02:00
Andreas Rumpf
f7b061f597 make async tests green again
(cherry picked from commit ac458448d8)
2019-07-15 08:03:16 +02:00
Araq
e34a318b9f minor style changes
(cherry picked from commit cb3c3c306c)
2019-07-15 08:03:16 +02:00
Araq
641d1e1175 minor style changes
(cherry picked from commit 38bdf1cd7f)
2019-07-15 08:03:16 +02:00
Araq
07505d87e2 make tests green again
(cherry picked from commit b2f9447896)
2019-07-15 08:03:16 +02:00
Araq
6ffe82a5aa there is only one style -- my style
(cherry picked from commit 87a2ced1ba)
2019-07-15 08:02:24 +02:00
Araq
2b4a7ff6f6 fixes linter regressions
(cherry picked from commit 73cc029fec)
2019-07-15 07:59:14 +02:00
Araq
3d33e96388 make editdistance work with --styleCheck:error
(cherry picked from commit dc0bbba3fa)
2019-07-15 07:59:14 +02:00
Araq
19225b71ab fixes #10901
(cherry picked from commit 78174857f8)
2019-07-15 07:59:14 +02:00
Araq
e5e2b067f4 fixes #11683
(cherry picked from commit b03421d087)
2019-07-15 07:59:14 +02:00
Araq
3866e3302a make more parts of the stdlib compile with --styleCheck:error
(cherry picked from commit bc7733827d)
2019-07-15 07:59:14 +02:00
Araq
607ce16acf fixes #11691
(cherry picked from commit 6663dbbe57)
2019-07-15 07:59:14 +02:00
Araq
694d57c899 styleCheck: make the compiler and large parts of the stdlib compatible with --styleCheck:error
(cherry picked from commit c94647aeca)
2019-07-15 07:58:45 +02:00
Araq
ed627cff3a linter: refactorings
(cherry picked from commit 18182e4bfd)
2019-07-15 07:58:27 +02:00
Araq
8a5860d196 style changes
(cherry picked from commit ff4a9a226f)
2019-07-15 07:58:27 +02:00
Araq
b5ab4dabe2 nim styleChecker: implemented all the missing features (bugfix)
(cherry picked from commit bd689849f2)
2019-07-15 07:58:27 +02:00
Araq
b3b10ec849 minor system.nim style changes
(cherry picked from commit c6c9e30379)
2019-07-15 07:58:27 +02:00
Araq
6ec566cdd8 koch temp: use -d:leanCompiler if possible
(cherry picked from commit 7a39eb13a5)
2019-07-15 07:58:27 +02:00
Miran
c4e26f7400 [other] prettify collections (#11695)
(cherry picked from commit 2255d8795b)
2019-07-15 07:58:27 +02:00
Araq
ab98141c75 newruntime: async progress
(cherry picked from commit 55e8aefbea)
2019-07-15 07:58:27 +02:00
Araq
14c6e3a6ab control flow graph: don't ignore yield statements
(cherry picked from commit 73c570d1d9)
2019-07-15 07:58:27 +02:00
Araq
808746e864 newruntime: map system.reset to =destroy
(cherry picked from commit ad58ed344a)
2019-07-15 07:58:27 +02:00
Arne Döring
386f126dd7 closes #11551 (#11693)
(cherry picked from commit eb059fa848)
2019-07-15 07:58:26 +02:00
Araq
ce9eaee303 newruntime: 'owned distinct' is a valid construct (required by async)
(cherry picked from commit a85e20c125)
2019-07-15 07:58:26 +02:00
Araq
7c7bab0626 make tests green again
(cherry picked from commit fa982b43f0)
2019-07-15 07:58:26 +02:00
narimiran
da2a149522 nimpretty: more comment indentation fixes
(cherry picked from commit 96d49608c0)
2019-07-15 07:58:26 +02:00
Araq
8afe92a1ab nimpretty: more improvements
(cherry picked from commit eefcea8892)
2019-07-15 07:58:26 +02:00
Araq
2a0c9dc063 nimpretty: code cleanups
(cherry picked from commit fc34193483)
2019-07-15 07:58:26 +02:00
Araq
e0b4d034bc nimpretty: yet another improvement
(cherry picked from commit 0193c8ad2e)
2019-07-15 07:58:26 +02:00
Araq
12baecb42d async: more 'owned' annotations
(cherry picked from commit 7993d61d00)
2019-07-15 07:58:26 +02:00
Araq
a144bc96b9 asyncmacro produces 'owned' types
(cherry picked from commit 2c2f2de614)
2019-07-15 07:58:26 +02:00
Araq
e0991c4bcf bugfix: allow type conversions between 'owned ref' types
(cherry picked from commit f64179e7fe)
2019-07-15 07:58:26 +02:00
Araq
40c2f504fb better error message for invalid types
(cherry picked from commit 7c62de0cb7)
2019-07-15 07:58:26 +02:00
Arne Döring
80e51bb407 Offsetof fixes (#11690)
* first fixes

* more tests and fixes

* code normalization

(cherry picked from commit 11dad688fe)
2019-07-15 07:58:26 +02:00
Miran
9b217c10e6 [other] test more packages (#11687)
(cherry picked from commit b50ae6817a)
2019-07-15 07:58:26 +02:00
Andreas Rumpf
78b665cc7f fixes #11530
(cherry picked from commit 124a584eb2)
2019-07-15 07:58:26 +02:00
Timothee Cour
092154de02 [refactoring] nimbase.h: remove dead code which was confusing (#11682)
(cherry picked from commit 655cb08461)
2019-07-08 11:33:20 +02:00
Jacek Sieka
0646d6a720 dynlib: use posix module (#11623)
(cherry picked from commit 9e7d885f35)
2019-07-08 11:33:20 +02:00
Miran
585a08548a nimpretty: don't introduce extra spaces after a colon or a comma (#11672)
(cherry picked from commit d0616ed115)
2019-07-08 11:33:20 +02:00
Araq
f77bc2522f fixes #11350
(cherry picked from commit 085a21ebf4)
2019-07-08 11:33:20 +02:00
Andreas Rumpf
5cc49aad44 fixes #11660 (#11677)
(cherry picked from commit bab1f67971)
2019-07-08 11:33:20 +02:00
awr1
e3c6f4d21b [HCR] Added warning for using performCodeReload() in main module (#11667)
* [HCR] Added error for using performCodeReload() in main module

* [HCR] changed this to a warning, clarified usage

* [HCR] fixed typo

(cherry picked from commit 6a7f8e8ab5)
2019-07-08 11:33:20 +02:00
Andreas Rumpf
615be176e6 fixes #11671
(cherry picked from commit 3258c1e2a3)
2019-07-08 11:33:20 +02:00
Andreas Rumpf
5dfec61597 improved the error message for #11494; closes #11494
(cherry picked from commit 465815e894)
2019-07-08 11:33:20 +02:00
Andreas Rumpf
df32d891a9 fixes a finish.exe regression
(cherry picked from commit 6ce6bce12e)
2019-07-08 11:33:20 +02:00
Andreas Rumpf
c96e6682a0 fixes #11447
(cherry picked from commit d2684cdfd2)
2019-07-08 11:33:19 +02:00
Andreas Rumpf
753f8a05d2 fixes #3333
(cherry picked from commit cab0c3e544)
2019-07-08 11:33:19 +02:00
Andreas Rumpf
00ccdec238 fixes #8316 (#11673)
(cherry picked from commit 64e1408920)
2019-07-08 11:33:00 +02:00
Andreas Rumpf
49de021b1a fixes #7057
(cherry picked from commit 2678fa679a)
2019-07-08 11:28:42 +02:00
Andreas Rumpf
5ecfbb5a4a ABI fixes for OSX/BSD; fixes #6860 (#11666)
(cherry picked from commit 02b9af2f75)
2019-07-08 11:28:42 +02:00
Juan Carlos
1b10f926c8 Documentation Diff, Typo (#11566)
* Documentation for Diff, add Examples and runnableExamples

(cherry picked from commit 25cd8a5490)
2019-07-08 11:28:42 +02:00
Miran
a31b3ef3cf nimpretty: improved detection of commas and semicolons (#11661)
* nimpretty: improved detection of commas and semicolons

* address the comments

(cherry picked from commit 34c09a98c7)
2019-07-08 11:28:42 +02:00
Arne Döring
8501971a60 introduce internal Int128 type, use it to fix case stmt checks (#11652)
* initial version of int128
* use int128 in case stmt
* fixes #11552

(cherry picked from commit 7d5d9f7703)
2019-07-08 11:28:42 +02:00
Miran
5863461d47 nimpretty: don't touch formatted multiline comments (#11663)
(cherry picked from commit 176eaf5c90)
2019-07-08 11:28:42 +02:00
cooldome
cb3a920097 Fixes #11662: render ops priority (#11664)
(cherry picked from commit d1f6c820dd)
2019-07-08 11:28:42 +02:00
narimiran
88896194bd nimpretty: nicer debugging [ci skip]
(cherry picked from commit 2c0c0e772c)
2019-07-08 11:28:42 +02:00
Miran
5689003410 nimpretty: relax line length rules when dealing with (inline) comments (#11657)
(cherry picked from commit 96a19ea1b4)
2019-07-08 11:28:42 +02:00
Timothee Cour
789c8e0065 fix #11651 exportc symbol not exported, leading to link error (#11658)
(cherry picked from commit 95f2f2396f)
2019-07-08 11:28:41 +02:00
Andreas Rumpf
e74e85a41e fixes #11610 (#11659)
(cherry picked from commit 28c9c062a4)
2019-07-08 11:28:41 +02:00
Tomohiro
2ee6d209c2 manual: document block expression (#11638)
(cherry picked from commit b64dd795b1)
2019-07-08 11:28:41 +02:00
Andreas Rumpf
3e8c4519d4 newruntime for async (#11650)
* fixes overloading resolution for passing owned(Future[string]) to Future[T]
* WIP: make --newruntime work with .async
* memtracker: make it compile again
* make Nimble compile again

(cherry picked from commit 5f515410af)
2019-07-08 11:28:41 +02:00
Akito13
cbdba3ceb3 Corrected example shown in documentation (#11654) [ci skip]
Used template within example was added to imports.

(cherry picked from commit 0a501932c2)
2019-07-08 11:27:15 +02:00
Graeme Cross
a9322ed873 Fix the broken link in math.nim (#11653) [ci skip]
(cherry picked from commit dad3c40f55)
2019-07-08 11:27:15 +02:00
narimiran
66660eca32 nimpretty: fix out of bounds error [ci skip]
(cherry picked from commit 4450fca6fd)
2019-07-08 11:27:15 +02:00
Araq
d13c75eb2f nimpretty: nimpretty now understands splitting newlines
(cherry picked from commit a59f0adc50)
2019-07-08 11:27:15 +02:00
Araq
f70a0c90f1 nimpretty: distinguish between the different kinds of newlines in Nim
(cherry picked from commit 7d29f8b1a4)
2019-07-08 11:27:15 +02:00
Timothee Cour
6a23772e23 fixes #8405: -d:useNimRtl now works even when {.rtl.} procs are used at compile time; CTFFI now works with {dynlib} (#11635)
(cherry picked from commit 64168d4aea)
2019-07-08 11:27:15 +02:00
Miran
da3a7b852d [bugfix] fix wrong nimpretty unidents, refs #11616 (#11645)
(cherry picked from commit 0718d6c2cd)
2019-07-08 11:27:15 +02:00
Andreas Rumpf
7ab44997aa fixes #11585
(cherry picked from commit 045eeab6b4)
2019-07-08 11:27:15 +02:00
Timothee Cour
b94e7b65a0 [bugfix] fix mach_absolute_time header; refs #11591 (#11593)
(cherry picked from commit 0ca71dd92c)
2019-07-08 11:27:15 +02:00
Miran
20f6acc0da [bugfix] fix #11484, acknowledge 'danger' flag (#11486)
(cherry picked from commit 1e9316e23c)
2019-07-08 11:27:15 +02:00
Araq
b0e86d0f05 fixes #11510
(cherry picked from commit c0db1705dc)
2019-07-08 11:27:15 +02:00
Araq
6a6a9423e4 fixes #11636
(cherry picked from commit 476b4ff372)
2019-07-08 11:27:15 +02:00
Arne Döring
191b7e0bde [backport] fix #11320 (#11538)
* [backport] fix #11320
* fix test for 32 bit test

(cherry picked from commit 20d0ef8afb)
2019-07-08 11:26:20 +02:00
Hugo Locurcio
1e48169bbc Implement some custom formatting for input fields in the documentation (#11632)
* Implement some custom formatting for input fields in the documentation

Aside of resulting in more consistent appearance across browsers,
this also fixes input form rendering when using Firefox with a
dark system theme on Linux.

* change the expected html in the tests

(cherry picked from commit 0a1cb631a2)
2019-07-08 11:26:20 +02:00
Graeme Cross
bd35d44808 Documentation improvements to the times module (#11639)
* Typo and grammar fixes for the times module
* Minor typo fixes to the times module

(cherry picked from commit ab6dec6e90)
2019-07-08 11:26:20 +02:00
Andreas Rumpf
d1de6b9fe4 fixes #11479 (#11641)
(cherry picked from commit 71b7383f12)
2019-07-08 11:26:20 +02:00
Miran
466d5ba060 [bugfix] nimpretty indents multiline comments correctly (#11607)
(cherry picked from commit c522a455df)
2019-07-02 13:57:12 +02:00
Andreas Rumpf
7938947907 fixes #11633
(cherry picked from commit cce8a739da)
2019-07-02 13:57:12 +02:00
Andreas Rumpf
476b3b1c13 fixes #11515 (#11624)
* fixes #11515

* better fix for #11515; make tests green

(cherry picked from commit 766960dc15)
2019-07-02 13:57:12 +02:00
Andreas Rumpf
59fbd261a6 fixes #11618 (#11631)
(cherry picked from commit 9b949855c7)
2019-07-02 13:57:12 +02:00
alaviss
eb295bbb7d assertions: fixes #11545 (#11605)
* assertions: properly fix #11545

* tests/assert: enable excessiveStackTrace

* tests/assert: add test case for #11545

* tfailedassert_stacktrace: disable excessiveStackTrace

* assertions: weird workaround for failing tests

This fixes megatest on *nix, but have no idea why

(cherry picked from commit 2c10b246ec)
2019-07-02 13:56:55 +02:00
Araq
e6c963259c fixes #11617
(cherry picked from commit bd55c862a6)
2019-07-02 13:56:55 +02:00
Araq
c454cdac49 fixes #11628
(cherry picked from commit c352892232)
2019-07-02 13:56:55 +02:00
Araq
09d43c1d8f fixes #11614
(cherry picked from commit 413dff03a0)
2019-07-02 13:56:55 +02:00
Ico Doornekamp
281baadb33 Make repr use 'ptr' for ptr types instead of 'ref' (#11626)
(cherry picked from commit a5686961bd)
2019-07-02 13:56:55 +02:00
Juan Carlos
d7ea8588c5 Remove IO.js compat (long dead vanished project,superseed by NodeJS) (#11627)
(cherry picked from commit d7a7662a7f)
2019-07-02 13:56:55 +02:00
Araq
10fa252426 [bugfix] make -d:nimSetUtf8CodePage switch work again
(cherry picked from commit dd39b11b13)
2019-07-02 13:56:55 +02:00
Andreas Rumpf
b228b741a3 added destructors.rst document
(cherry picked from commit d37c4e44d3)
2019-07-02 13:56:55 +02:00
alaviss
c2d0e0f7d5 msgs, ccgstmts: fixes #11572 (#11621)
* [refactor] msgs: toFilename now return just the filename

The C codegen uses just the file name for stacktrace when
excessiveStackTrace is off (see quotedName),
so there aren't any reason for other codegen to not do the same.

The file name is now cached in TFileInfo.shortName, which was introduced
for nimsuggest, and went unused after several refactoring of the
compiler.

A toProjPath() proc has been added for the previous behavior of
toFilename().

* ccgstmt: use quotedFilename() for raiseExceptionEx

This is the same proc used for stacktrace when --stacktrace:on

Fixes #11572

* msgs: handle case where file name is not available

(cherry picked from commit e259f80fc7)
2019-07-02 13:56:27 +02:00
Andreas Rumpf
95df6af527 [other] additions to the manual
(cherry picked from commit 7113c1e931)
2019-07-02 13:56:27 +02:00
Araq
199aa1f3a1 fixes #11606
(cherry picked from commit 3606e035f5)
2019-07-02 13:56:27 +02:00
Araq
57df2c9c3a fixes #11611
(cherry picked from commit 7ddb31262e)
2019-07-02 13:56:27 +02:00
Ivan Bobev
17cac707d0 Pass additional koch options to the nim compiler (#11615)
Add possibility when "koch tools" command is used, nim compiler options
to be passed. The current options are kept and the new user specified
options will be added to the end of the command line if present.

Example:
> koch --latest tools -d:danger --debugInfo --lineDir:on
bin\nim.exe c -o:bin\nimsuggest.exe -d:release -d:danger -d:danger
 --debugInfo --lineDir:on nimsuggest/nimsuggest.nim
...
bin\nim.exe c -o:bin\nimgrep.exe -d:release -d:danger --debugInfo
 --lineDir:on tools/nimgrep.nim
...
bin\nim.exe c -o:bin\vccexe.exe -d:danger --debugInfo --lineDir:on
 tools/vccexe/vccexe.nim
...
bin\nim.exe c -o:bin\nimpretty.exe -d:release -d:danger --debugInfo
 --lineDir:on nimpretty/nimpretty.nim
...
bin\nim.exe c -o:bin\nimfind.exe -d:release -d:danger --debugInfo
 --lineDir:on tools/nimfind.nim
...
bin\nim.exe c -o:bin\nimble.exe --noNimblePath --nilseqs:on -d:release
 -d:danger --debugInfo --lineDir:on dist\nimble\src\nimble.nim

(cherry picked from commit 5be5bf0222)
2019-07-02 13:56:15 +02:00
Araq
970c7616bc nimpretty: bugfix [bugfix]
(cherry picked from commit 284a8cb58a)
2019-07-02 13:55:37 +02:00
Andreas Rumpf
1503970c3b contributing.rst guide: Make the rules reflect the reality.
(cherry picked from commit 765ff4b67b)
2019-07-02 13:54:42 +02:00
Andreas Rumpf
922a4ed195 manual: typo
(cherry picked from commit 17bbce7c8a)
2019-07-02 13:54:42 +02:00
Andreas Rumpf
c39a799aec manual: document how accessors are resolved; fixes #11514
(cherry picked from commit d9604d7d0b)
2019-07-02 13:54:42 +02:00
Zestyr
62691c5d73 Fix typo in xmltree docs [ci skip]
(cherry picked from commit bab83c4d8b)
2019-07-02 13:54:42 +02:00
Araq
ab5bd9e6ff make tests green again
(cherry picked from commit f36a61e6d4)
2019-07-02 13:54:42 +02:00
Andreas Rumpf
3c3f07cfde fixes #11445
(cherry picked from commit fb878330a9)
2019-07-02 13:54:41 +02:00
Andreas Rumpf
843ae0073b fixes #11523
(cherry picked from commit 135fdde6a9)
2019-07-02 13:54:41 +02:00
Andreas Rumpf
d206e881e9 fixes #11525
(cherry picked from commit 19b142401c)
2019-07-02 13:52:20 +02:00
Miran
712d9ce1b9 [bugfix] fix #11532, nimpretty should ignore source code filters (#11603)
(cherry picked from commit f65eaa51f1)
2019-06-27 20:59:46 +02:00
Andreas Rumpf
ba6eb0151c fixes #11098
(cherry picked from commit e083a1533b)
2019-06-27 20:59:46 +02:00
narimiran
28708e0b8e [bugfix] fix #11588, don't check if SharedTable is initialized
(cherry picked from commit 326e3ad09d)
2019-06-27 20:59:46 +02:00
Araq
e08cf5a947 fixes #11600
(cherry picked from commit b6fb47df77)
2019-06-27 20:59:46 +02:00
Miran
38aa7f6d20 [bugfix] fix #11469, new rules for a newline in nimpretty (#11512)
* [bugfix] fix #11469, new rules for a newline in nimpretty
* concatenate two lines if they have the same indentation level

(cherry picked from commit f288e1b11a)
2019-06-27 20:59:46 +02:00
Araq
763357089e fixes #11577
(cherry picked from commit 0a81b038fd)
2019-06-27 20:59:46 +02:00
alaviss
6576c1ab5c [refactor] compiler/[msgs, reorder, semstmts]: use toMsgFilename where appropriate (#11595)
* compiler/msgs: toMsgFilename now operates on FileIndex
* compiler/reorder: use toMsgFilename for compiler messages
* compiler/semstmts: respect listFullPaths for recursive deps error

(cherry picked from commit 993b3909a8)
2019-06-27 20:59:45 +02:00
alaviss
8a16fb972b compiler/[msgs, options]: confine --listFullPaths to compiler messages (#11583)
* compiler/[msgs, options]: make toFilename independent of listFullPaths

toFilename is used mainly in codegen, as such it should not follow
--listFullPaths

* compiler/msgs: use toMsgFilename for toFileLineCol

This proc is mainly used for compiler messages, so it should follow
--listFullPaths

* compiler/msgs: remove toFileLine

unused proc

* compiler/msgs: cleanup toMsgFilename

Also improved path choosing logic, /home should now be preferred over
../home on *nix

(cherry picked from commit 2f1a1b7106)
2019-06-27 20:59:45 +02:00
Toshiyuki-Tega
f1b2182035 VCC discovery using vswhere (#6540) (#11559)
(cherry picked from commit b7f8031e98)
2019-06-27 20:59:45 +02:00
Juan Carlos
50358e6d4a Documentation highlite (#11596)
* Add Documentation with examples for highlite

* Add Documentation with examples for highlite

(cherry picked from commit 206f2478b8)
2019-06-27 20:59:45 +02:00
Andreas Rumpf
48770b04bd fixes #11563 (#11594)
(cherry picked from commit 0f868b587b)
2019-06-27 20:59:45 +02:00
cooldome
7e702d95c1 increase dfa instruction limit (#11579)
(cherry picked from commit 0d50b0c8a7)
2019-06-27 20:59:45 +02:00
Jasper Jenkins
8396ddb3a4 [bugfix] remove dangling ref (#11576)
(cherry picked from commit 91f0626dcb)
2019-06-27 20:59:45 +02:00
Gérôme Fournier
8ab0be4530 Fix out of bound access in cgi module (#11578)
When an HTTP request with a zero CONTENT_LENGTH is made,
attempting to access addr(result[0]) raise an exception as the 0 index
is out of bound

(cherry picked from commit 181350f6c9)
2019-06-27 20:59:45 +02:00
WhiteDuke
30d7cf02ad Fix typo (#11573)
(cherry picked from commit 2a7cf71db3)
2019-06-27 20:59:45 +02:00
alaviss
98b9ffa3a4 assertions: make assert follow excessiveStackTrace (#11574)
(cherry picked from commit 403fd3ac43)
2019-06-27 20:59:45 +02:00
Arne Döring
a5a62b562f [refactoring] remove zeroExtend and friends from the compiler builtins. (#11531)
* remove zeroExtend and friends from the compiler builtins.
* fix jssys

(cherry picked from commit e90d91f0e4)
2019-06-27 20:59:45 +02:00
alaviss
06904a212a nim.cfg: disable excessiveStackTrace on release (#11575)
(cherry picked from commit e9a23cee0a)
2019-06-27 20:59:45 +02:00
narimiran
a74104eda5 [documentation] fix #4630, document unsupported functions for JS
(cherry picked from commit 436f570651)
2019-06-27 18:16:54 +02:00
Simon Krauter
f8087a2815 Spelling fixes in nimc.rst (#11569)
(cherry picked from commit 800bc661b6)
2019-06-27 18:15:53 +02:00
Juan Carlos
6a7b490046 [other] Documentation NimScript (#11548)
* Documentation of NimScript, update and expand, mention the benefits aside of its limitations, add examples, update the list of usable std lib modules

(cherry picked from commit bb9b60604b)
2019-06-27 18:15:46 +02:00
Miran
ceafb7f771 [bugfix] fix OrderedTable iterators (#11562)
(cherry picked from commit 3d50f7e2a1)
2019-06-27 18:14:36 +02:00
Andreas Rumpf
433dfaf288 [bugfix] fixes #11524
(cherry picked from commit 79c721d418)
2019-06-27 18:14:36 +02:00
Andreas Rumpf
4d18ee498a closes #11533
(cherry picked from commit 0db3c670ac)
2019-06-27 18:14:36 +02:00
Andreas Rumpf
ef018d7a63 [bugfix] fixes #11556
(cherry picked from commit 35df59b3ce)
2019-06-27 18:14:35 +02:00
narimiran
2a36cb7fc9 [documentation] fix wrong link [ci skip]
(cherry picked from commit 12eebf48b6)
2019-06-27 18:14:35 +02:00
Kaushal Modi
810166ca95 [other] Improve the "tabs are not allowed" error message (#11554)
(cherry picked from commit a4c613c110)
2019-06-27 18:14:35 +02:00
Miran
10407fefec [bugfix] fix delete in strutils and sequtils (#11535)
(cherry picked from commit 23e95dc629)
2019-06-27 18:14:35 +02:00
Miran
d5ea497cff [bugfix] correct 'source' for documentation (#11540)
(cherry picked from commit d6b0e46ee4)
2019-06-27 18:13:55 +02:00
Miran
c6ab69b84e [bugfix] fix OrderedTable default initialization (#11549)
(cherry picked from commit 45bbf1ef5b)
2019-06-27 18:13:55 +02:00
Andreas Rumpf
edc151fa64 [other] new experimental pragma .nodestroy for easier custom destructors
(cherry picked from commit 55da84e141)
2019-06-27 18:13:55 +02:00
Andreas Rumpf
6d977e66cb [other] added system.dispose for owned refs
(cherry picked from commit f310cf5250)
2019-06-27 18:13:55 +02:00
Andreas Rumpf
f3ae2dcfa3 [bugfix] system.nim: make pop work with --newruntime
(cherry picked from commit 280193cc07)
2019-06-27 18:13:55 +02:00
Andreas Rumpf
cd49bba7b3 [bugfix] proper destruction for strings/seqs for --newruntime
(cherry picked from commit 7e4748beee)
2019-06-27 18:13:55 +02:00
Andreas Rumpf
194eebd4b8 [bugfix] system.nim: make pop work with --newruntime
(cherry picked from commit bc9fb4885b)
2019-06-27 18:13:55 +02:00
Araq
b41d31e887 [other] newruntime: add a simple closure iterator test
(cherry picked from commit 678beb8ef9)
2019-06-20 11:59:50 +02:00
Araq
cb4bb4d6c7 [bugfix] newruntime: trivial closure iterator works
(cherry picked from commit 6adcc09877)
2019-06-20 11:59:50 +02:00
Araq
cd35f9664c [refactoring] closureiters.nim: style change
(cherry picked from commit c83914b435)
2019-06-20 11:59:50 +02:00
Araq
0ba1624325 wip
(cherry picked from commit 50afafdb38)
2019-06-20 11:59:50 +02:00
Andreas Rumpf
6ad45a1c97 WIP: closures for the newruntime [ci skip]
(cherry picked from commit af10788dcc)
2019-06-20 11:59:50 +02:00
narimiran
5cf9cbe9a5 [bugfix] fix #11546, correct link for sequtils
(cherry picked from commit 16d81fa205)
2019-06-20 11:59:50 +02:00
narimiran
9789146899 [bugfix] fix #11543, add std/sums to theindex.html
(cherry picked from commit 96bed814d2)
2019-06-20 11:59:50 +02:00
Andreas Rumpf
905fc43abe newruntime: added yet another test
(cherry picked from commit 0adb1c6223)
2019-06-20 11:59:50 +02:00
Andreas Rumpf
aacc97e854 [bugfix] owned closures (#11544)
(cherry picked from commit c65a5d754b)
2019-06-20 11:59:50 +02:00
Arne Döring
e0b41736b3 change newLit on Seq (#11542)
(cherry picked from commit 1a074fffa4)
2019-06-20 11:59:50 +02:00
Araq
8d46524b1b [bugfix] fixes #11517
(cherry picked from commit ab36ffbeb1)
2019-06-20 11:55:37 +02:00
Araq
3aa034f40d libffi: style changes
(cherry picked from commit ff89f7e33a)
2019-06-20 11:55:24 +02:00
Miran
eb9ac127b9 [other] update homebrew, fix travis fails on OSX (#11541)
(cherry picked from commit ae5a4cea98)
2019-06-20 11:54:46 +02:00
narimiran
22c515b067 [other] documentation: deprecation comments are now auto-generated
(cherry picked from commit cf47c2c60c)
2019-06-20 11:54:46 +02:00
alaviss
4c7dec34d5 [bugfix] gc_common: export foreign thread gc docs (#11536)
(cherry picked from commit 24ac13f653)
2019-06-20 11:54:46 +02:00
Araq
81f15184e5 fixes #11436
(cherry picked from commit 296c48de5e)
2019-06-20 11:53:37 +02:00
Phạm Ngọc Quang Nam
368e12ed36 [bugfix] Fix smtp.nim unhandled exception (#11498)
(cherry picked from commit 7c637c2faf)
2019-06-20 11:53:08 +02:00
Araq
c57485e67b add HCR document to the tools.rst list
(cherry picked from commit c99ce5051e)
2019-06-20 11:52:51 +02:00
Araq
2d606e38ea HCR: better documentation
(cherry picked from commit 38f05bb9a3)
2019-06-20 11:52:44 +02:00
Benjamin Summerton
c1097ea949 Add cbrt() bindings for the JS Target (#11528)
`Math.cbrt()` exists:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt

The binding was missing for the JavaScript backend.

(cherry picked from commit a009cbdc2f)
2019-06-20 11:52:37 +02:00
Miran
4144893ba2 [bugfix] fix #11450, random.initRand crashes in JS backend (#11522)
(cherry picked from commit ac3449b93b)
2019-06-20 11:49:17 +02:00
Miran
dacd1d071a [bugfix] fix #11482, fix nimsuggest range error (#11519)
The default starting parameters for `line` and `col` were switched.

See line 141: "line starts at 1, column at 0, dirtyfile is optional".
Also, in `TLineInfo` object, `line` is uint16, `col` is int16.

(cherry picked from commit 6cad5c7861)
2019-06-20 11:49:07 +02:00
narimiran
1348cb525b [other] introduce a separate changelog for backports, update
contributing guidelines

(cherry picked from commit b70fd0400e)
2019-06-20 11:48:32 +02:00
Juan Carlos
77166176b2 [bugfix] Fixes #11434 , Update Tools Documentation (#11449)
(cherry picked from commit eb087b3546)
2019-06-20 11:46:12 +02:00
Juan Carlos
e15ce6bdeb [bugfix] Fixes #11495 , Remove TinyC from help (#11508)
(cherry picked from commit aa7f23e1ee)
2019-06-20 11:46:12 +02:00
Charles Blake
464142683f [bugfix] fix #11430, strutils rfind (#11487) 2019-06-16 17:44:06 +02:00
Kaushal Modi
7095a3dfa4 [bugfix] Fix the link to "For Loop Macro" section (#11505)
(cherry picked from commit d1ce86fdc6)
2019-06-16 17:19:43 +02:00
SolitudeSF
7e235779f0 [bugfix] Add .47 as supported libssl version
(cherry picked from commit e96afd6324)
2019-06-16 17:19:43 +02:00
Kaushal Modi
b68ee27dd5 [bugfix] Minor formatting fix in tut2 [ci skip] (#11501)
Monospace `untyped` like elsewhere in the tutorial.

(cherry picked from commit c656714623)
2019-06-16 17:19:43 +02:00
Araq
63116d94ae [bugfix] nimpretty: better alignment; fixes #11467
(cherry picked from commit 57a83df745)
2019-06-16 17:19:43 +02:00
Juan Carlos
01fcde2146 [bugfix] document the norewrite pragma (#11453)
* fixes #9454
* Peer review feedback, wording, move to experimental manual

(cherry picked from commit 80320c72d3)
2019-06-16 17:19:43 +02:00
Jasper Jenkins
ea4d72a379 [refactoring] error instead of quit for basename (#11491)
(cherry picked from commit bda9fd149c)
2019-06-16 17:19:43 +02:00
Jasper Jenkins
78c6f01b90 [bugfix] fix quit errormsg in nimvm (#11490)
(cherry picked from commit 06ef56ba72)
2019-06-16 17:18:58 +02:00
Simon Krauter
41e0fc593c Update tut1: -d:release does not turn off *allruntime checks off anymore (#11492)
According to https://nim-lang.org/blog/2019/06/06/version-0200-released.html
"The -d:release switch now does not disable runtime checks anymore. "

(cherry picked from commit e2f99a2026)
2019-06-16 17:18:58 +02:00
Araq
21910d6eb1 [bugfix] nimpretty: fixes #11470
(cherry picked from commit 165ea46284)
2019-06-16 17:18:58 +02:00
Araq
7bfde5fa40 [bugfix] nimpretty: fixes #11468
(cherry picked from commit af39f26a3a)
2019-06-16 17:18:58 +02:00
Araq
9e28b3ccc9 [other] nimsuggest: adhere to our style guide
(cherry picked from commit b70295c768)
2019-06-16 17:18:58 +02:00
alaviss
b4464f1dfa [other] appveyor: use official dlls on nim-lang.org (#11473)
(cherry picked from commit 08fdffc717)
2019-06-16 17:18:58 +02:00
Dominik Picheta
4f69f7b62d [bugfix] Fixes async IO operations stalling even after socket is closed. (#11232)
(cherry picked from commit 73c44c6e9b)
2019-06-16 17:18:58 +02:00
Jasper Jenkins
6530a4100a [bugfix] fix nimpretty for absolute paths (#11480)
(cherry picked from commit da035e9c83)
2019-06-16 17:17:42 +02:00
Araq
9797da3615 [refactoring] liftdestructors.nim is callable from lambdalifting; refs #11217
(cherry picked from commit b056d32a79)
2019-06-16 17:17:41 +02:00
Arne Döring
0af9085e78 fix regression in semfold for old right shift (#11477)
(cherry picked from commit e4d0f4fee0)
2019-06-16 17:17:41 +02:00
Araq
e1c29d7a19 [refactoring] liftdestructors is now a module of its own
(cherry picked from commit c07973e313)
2019-06-16 17:17:41 +02:00
Araq
32cecf3a42 [other] make typeAllowed easier to debug by using structured programming
(cherry picked from commit 549d8cc0c6)
2019-06-16 17:17:41 +02:00
Andreas Rumpf
05d647398a [other] preparations for --styleCheck:error for the Nim compiler (#11478)
(cherry picked from commit 572b7c37a5)
2019-06-16 17:17:41 +02:00
Arne Döring
4c8a02165e [refactoring] refactor the compiler and stdlib to deprecation warnings (#11419)
(cherry picked from commit c7e1c665a1)
2019-06-16 17:17:41 +02:00
Juan Carlos
7e6c3f3684 [bugfix] Add .nimf to mimetypes (#11417)
(cherry picked from commit 3d13103443)
2019-06-16 17:17:41 +02:00
Miran
65a2b3bb6f [other] better error message for IndexError for empty containers (#11476)
(cherry picked from commit b3d2cd738a)
2019-06-16 17:16:49 +02:00
narimiran
8dfebb3282 Revert "VM can now cast integer type arbitrarily. (#11459) [feature]"
This is a new feature, which shouldn't be backported.
2019-06-16 17:15:23 +02:00
narimiran
de2c271293 Merge remote-tracking branch 'upstream/devel' into version-0-20 2019-06-11 12:13:57 +02:00
narimiran
022cd2c144 bump version to 0.20.1 2019-06-11 12:13:35 +02:00
3559 changed files with 244825 additions and 239559 deletions

9
.gitattributes vendored
View File

@@ -1,9 +0,0 @@
# 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
# bug https://github.com/dom96/choosenim/issues/256 for WSL CRLF
*.sh text eol=lf
/config/build_config.txt text eol=lf

2
.github/FUNDING.yml vendored
View File

@@ -1,7 +1,7 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: 'araq' # Replace with a single Patreon username
patreon: # Replace with a single Patreon username
open_collective: 'nim' # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

46
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,46 @@
---
name: Bug report
about: Have you found an unexpected behavior? Use this template.
---
<!-- Think about the title, twice. -->
<!-- Summarize the problem here, keep it short and simple. -->
Function `echo` outputs the wrong string.
### Example
<!-- Paste your example in the code-block below. -->
```nim
echo "Hello World!"
```
### Current Output
```
Hola mundo!
```
### Expected Output
<!-- What should be the correct output? -->
```
Hello World!
```
### Possible Solution
<!--- Have you found a possible solution? Post it here. -->
### Additional Information
<!--- For Example:
* Your Nim version (output of `nim -v`).
* Was it working in the previous Nim releases?
* A link to a related issue or discussion.
* A project reference where (and how) the issue causes problems.
-->
```
$ nim -v
Nim Compiler Version 0.1.2
```

View File

@@ -1,73 +0,0 @@
name: "Bug Report"
description: "Create a new bug report. Have you found an unexpected behavior? Use this form."
title: "Think about the title, twice."
labels: ["unconfirmed"]
body:
- type: markdown
attributes:
value: |
Please provide a minimal code example that reproduces the bug if possible.
Reports with a reproducible example or detailed information will likely receive fixes faster.
- type: textarea
id: description
attributes:
label: Description
description: |
Describe the problem. Code example can be given here.
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
validations:
required: true
- type: textarea
id: nim-version
attributes:
label: Nim Version
description: |
Can be obtained from `nim -v` on the command line along with the OS/architecture.
For development versions, make sure to include the commit hash.
validations:
required: true
- type: textarea
id: current-logs
attributes:
label: Current Output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
render: text
- type: textarea
id: expected-logs
attributes:
label: Expected Output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
render: text
- type: textarea
id: known-workarounds
attributes:
label: Known Workarounds
description: Provide any known workarounds.
validations:
required: false
- type: textarea
id: extra-info
attributes:
label: Additional Information
description: Any additional relevant information.
validations:
required: false
- type: markdown
attributes:
value: |
- Please check whether the problem still exists in the devel branch, which can be installed via [choosenim](https://github.com/nim-lang/choosenim/), [nightlies](https://github.com/nim-lang/nightlies/), or by [creating a temporary build of the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler-building-an-instrumented-compiler).
- Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html).
- If it's a pre-existing compiler bug, see [debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) which should give more context on a compiler crash.
- If it's a regression, you can help us by identifying which version introduced the bug by [bisecting](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions) or at least trying known past releases (e.g. `choosenim 2.0.0`).
The Nim repo also supports bisecting in issue comments by adding `!nim c`, `!nim js` etc. before a code block, see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)

View File

@@ -1,10 +0,0 @@
contact_links:
- name: Forum
url: https://forum.nim-lang.org
about: Please ask and answer questions here.
- name: Discord
url: https://discord.gg/nim
about: Please ask and answer questions here.
- name: Stack Overflow
url: https://stackoverflow.com/questions/tagged/nim-lang
about: Please ask and answer questions here.

View File

@@ -0,0 +1,32 @@
---
name: Feature request
about: Do you want to suggest a new feature? Use this template.
---
<!---
Notice there is now a separate repository for the detailed RFCs and proposals:
https://github.com/nim-lang/RFCs
If you have a simple feature request, you can post it here using this template,
but bear in mind that adding new features to the language is currently a low priority.
-->
### Summary
<!--- Short summary of your proposed feature -->
### Description
<!--- Describe your solution, what problem does it fix? -->
### Alternatives
<!--- Are there any alternatives you've considered? -->
### Additional Information
<!--- For Example:
* A link to a project where the issue is relevant.
* A link to a related issue or discussion.
-->

View File

@@ -1,72 +0,0 @@
name: "Feature request"
description: "Create a new Feature Request. Do you want to suggest a new feature? Use this form."
title: "Think about the title, twice."
labels: ["unconfirmed"]
body:
- type: markdown
attributes:
value: |
- Please provide a minimal code example that illustrates the basic idea behind your feature request.
Reports with full repro code and descriptive detailed information will likely receive feedback faster.
- There is a separate repository for the detailed RFCs and proposals: https://github.com/nim-lang/RFCs.
If you have a simple feature request, you can post it here using this form,
but bear in mind that adding new features to the language is currently a low priority.
- type: textarea
id: summary
attributes:
label: Summary
description: |
Use DETAILED DESCRIPTIVE information about the feature request.
Here, you go into more details about your ideas. This section can be a few paragraphs long.
placeholder: Short summary of your proposed feature.
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: Describe your solution, what problem does it fix?
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives
description: Are there any alternatives you've considered?
validations:
required: false
- type: textarea
id: Examples
attributes:
label: Examples
description: Provide examples for your feature request here.
placeholder: Example code here.
- type: textarea
id: incompatibility
attributes:
label: Backwards Compatibility
description: If your Feature Request introduces backward-incompatible changes, describe them and propose how to deal with them.
validations:
required: false
- type: textarea
id: links
attributes:
label: Links
description: Please copy and paste any relevant links to projects, issues, discussions, technical documentations, code samples, etc.
validations:
required: false
- type: markdown
attributes:
value: |
- Thanks for your contributions!, your ideas will receive feedback from the community soon...
- **Remember to :star: Star the Nim project on GitHub!.**
- Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html).
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)

View File

@@ -1,31 +0,0 @@
# See https://github.com/juancarlospaco/nimrun-action/issues/3#issuecomment-1607344901
name: issue comments bisects
on:
issue_comment:
types: created
jobs:
bisects:
if: |
github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '!nim ') && github.event.issue.pull_request == null && github.event.comment.author_association != 'NONE'
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
name: ${{ matrix.platform }}-bisects
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- uses: juancarlospaco/nimrun-action@nim
if: |
runner.os == 'Linux' && contains(github.event.comment.body, '-d:linux' ) ||
runner.os == 'Windows' && contains(github.event.comment.body, '-d:windows') ||
runner.os == 'macOS' && contains(github.event.comment.body, '-d:osx' ) ||
runner.os == 'Linux' && !contains(github.event.comment.body, '-d:linux') && !contains(github.event.comment.body, '-d:windows') && !contains(github.event.comment.body, '-d:osx')
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,116 +0,0 @@
name: Nim Docs CI
on:
push:
paths:
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
- '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/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
- 'doc/nimdoc.css'
- 'lib/**.nim'
- 'nimdoc/testproject/expected/testproject.html'
- 'tools/dochack/dochack.nim'
- 'tools/kochdocs.nim'
- '.github/workflows/ci_docs.yml'
- 'koch.nim'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
target: [linux, windows, osx]
include:
- target: linux
os: ubuntu-20.04
- target: windows
os: windows-2019
- target: osx
os: macos-13
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install build dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install make
- name: 'Install build dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'System information'
shell: bash
run: . ci/funs.sh && nimCiSystemInfo
- name: 'Build csourcesAny (posix)'
# this would work on windows and other CI use this on windows,
# but we ensure here that `ci/build_autogen.bat` keeps working on windows.
if: runner.os != 'Windows'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc
# was previously using caching via `actions/cache@v1` but this wasn't
# used in other CI pipelines and it's unclear the added complexity
# was worth the saving; can be revisited if needed.
- name: 'Build csourcesAny (windows)'
if: runner.os == 'Windows'
shell: cmd
run: ci/build_autogen.bat
- name: 'Build koch'
shell: bash
run: nim c koch
- name: 'Build the real compiler'
shell: bash
run: ./koch boot -d:release
- name: 'Build documentation'
shell: bash
run: ./koch doc --git.commit:devel
- name: 'Publish documentation to Github Pages'
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: crazy-max/ghaction-github-pages@v4
with:
build_dir: doc/html
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,76 +0,0 @@
name: GCC 14
on:
pull_request:
push:
branches:
- 'devel'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt update -qq
sudo apt remove needrestart
DEBIAN_FRONTEND='noninteractive' \
sudo apt 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 (Linux amd64 gcc 14)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo add-apt-repository universe
sudo apt update -qq
sudo apt install -y gcc-14 g++-14 libpcre3 liblapack-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
- 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: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'NIM_TESTAMENT_DISABLE_SSL'
shell: bash
run: echo "NIM_TESTAMENT_DISABLE_SSL=1" >> $GITHUB_ENV
- name: 'System information'
shell: bash
run: . ci/funs.sh && nimCiSystemInfo
- name: 'Build csourcesAny'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'koch, Run CI'
shell: bash
run: . ci/funs.sh && nimInternalBuildKochAndRunCI

View File

@@ -1,75 +0,0 @@
name: Packages CI
on:
pull_request:
push:
branches:
- 'devel'
- 'version-2-0'
- 'version-1-6'
- 'version-1-2'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-13]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
env:
NIM_TEST_PACKAGES: "1"
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '20.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
# XXX can't find boehm and gtk on macos 13
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'System information'
shell: bash
run: . ci/funs.sh && nimCiSystemInfo
- name: 'Build csourcesAny'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'koch, Run CI'
shell: bash
run: . ci/funs.sh && nimInternalBuildKochAndRunCI

View File

@@ -1,90 +0,0 @@
name: Tracking orc-booting compiler memory usage
on:
pull_request_target:
types: [closed]
jobs:
build:
if: github.event.pull_request.merged == true
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '20.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: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'System information'
shell: bash
run: . ci/funs.sh && nimCiSystemInfo
- name: 'Build csourcesAny'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'Build koch'
shell: bash
run: nim c koch
- name: 'Build Nim'
shell: bash
run: ./koch boot -d:release -d:nimStrictMode --lib:lib
- name: 'Action'
shell: bash
run: nim c -r -d:release ci/action.nim
- name: 'Comment'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
try {
const data = fs.readFileSync('ci/nimcache/results.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: data
})
} catch (err) {
console.error(err);
}

View File

@@ -1,25 +0,0 @@
# https://github.com/actions/stale#usage
name: Stale pull requests
on:
schedule:
- cron: '0 0 * * *' # Midnight.
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
days-before-pr-stale: 365
days-before-pr-close: 30
days-before-issue-stale: -1
days-before-issue-close: -1
exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]"
exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority"
stale-pr-message: >
This pull request is stale because it has been open for 1 year with no activity.
Contribute more commits on the pull request and rebase it on the latest devel,
or it will be closed in 30 days. Thank you for your contributions.
close-pr-message: >
This pull request has been marked as stale and closed due to inactivity after 395 days.

42
.gitignore vendored
View File

@@ -3,9 +3,9 @@
!*.*
# Cache
nimcache*/
rnimcache*/
dnimcache*/
nimcache/
rnimcache/
dnimcache/
*.o
!/icons/*.o
@@ -30,7 +30,7 @@ deinstall.sh
doc/html/
doc/*.html
doc/pdf
doc/*.pdf
doc/*.idx
/web/upload
/build/*
@@ -64,51 +64,23 @@ lib/**/*.html
testament.db
/tests/**/*.json
/tests/**/*.js
/csources
/csources_v1
/csources_v2
/dist/
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it
dist/
# Private directories and files (IDEs)
.*/
~*
# testament cruft; TODO: generate these in a gitignore'd dir (./build) in the first place.
# testament cruft; TODO: generate these in a gitignore'd dir in the first place.
testresults/
test.txt
/test.ini
tweeter.db
tweeter_test.db
/tests/megatest.nim
/tests/ic/*_temp.nim
/tests/navigator/*_temp.nim
megatest.nim
/outputExpected.txt
/outputGotten.txt
/t15148.txt
/tests/vm/tfile_rw.txt
/lib/pure/*.js
!/.builds/
!/.github
# ignore debug dirs generated by dsymutil on OSX
*.dSYM
# 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
# except here:
!/nimdoc/testproject/expected/*
pkgs/
/compiler/compiler/

60
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,60 @@
image: ubuntu:16.04
stages:
- pre-build
- build
- deploy
- test
.linux_set_path: &linux_set_path_def
before_script:
- export PATH=$(pwd)/bin${PATH:+:$PATH}
tags:
- linux
.windows_set_path: &win_set_path_def
before_script:
- set PATH=%CD%\bin;%PATH%
tags:
- windows
build-windows:
stage: build
script:
- ci\build.bat
artifacts:
paths:
- bin\nim.exe
- bin\nimd.exe
- compiler\nim.exe
- koch.exe
expire_in: 1 week
tags:
- windows
deploy-windows:
stage: deploy
script:
- koch.exe winrelease
artifacts:
paths:
- build/*.exe
- build/*.zip
expire_in: 1 week
tags:
- windows
- fast
test-windows:
stage: test
<<: *win_set_path_def
script:
- call ci\deps.bat
- nim c testament\tester
- testament\tester.exe --pedantic all
tags:
- windows
- fast

92
.travis.yml Normal file
View File

@@ -0,0 +1,92 @@
sudo: false
language: c
dist: xenial
matrix:
fast_finish: true
include:
- os: linux
env:
- NIM_COMPILE_TO_CPP=false
- CPU=amd64
- os: linux
env:
- NIM_COMPILE_TO_CPP=false
- CPU=i386
addons:
apt:
packages:
- gcc-multilib
- g++-multilib
- libcurl4-openssl-dev:i386
- libgc-dev:i386
- libglib2.0-dev:i386
- libpulse-dev:i386
- libsdl1.2-dev:i386
- libsfml-dev:i386
- os: osx
env:
- NIM_COMPILE_TO_CPP=false
- CPU=amd64
- os: osx
env:
- NIM_COMPILE_TO_CPP=true
- CPU=amd64
# To allow failures for a failing configuration, use something like:
# allow_failures:
# - env: NIM_COMPILE_TO_CPP=true
# - os: osx
addons:
apt:
# update the list above if more deps are introduced
packages:
- libcurl4-openssl-dev
- libsdl1.2-dev
- libgc-dev
- libsfml-dev
homebrew:
packages:
- boehmgc
- make
- sfml
update: true
install:
- if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which gcc) -m32 \"\$@\"" > bin/gcc; fi
- if [[ $CPU = i386 ]]; then chmod 755 bin/gcc; fi
- if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which g++) -m32 \"\$@\"" > bin/g++; fi
- if [[ $CPU = i386 ]]; then chmod 755 bin/g++; fi
before_script:
- git clone --depth 1 https://github.com/nim-lang/csources.git
- export PATH="$PWD/bin${PATH:+:$PATH}"
- make -C csources -j 2 LD=$CC ucpu=$CPU
script:
- echo "travis_fold:start:nim_c_koch"
- nim c koch
- echo "travis_fold:end:nim_c_koch"
- ./koch runCI
before_deploy:
# Make https://nim-lang.github.io/Nim work the same as https://nim-lang.github.io/Nim/overview.html
- cp -f ./doc/html/overview.html ./doc/html/index.html
deploy: # https://nim-lang.github.io/Nim
provider: pages
# local-dir *has* to be a relative path from the repo root.
local-dir: "doc/html"
skip-cleanup: true
github-token: "$GITHUB_OAUTH_TOKEN"
keep-history: false
on:
branch: devel
# Extract failed tests
after_failure: nim c -r tools/ci_testresults.nim

39
appveyor.yml Normal file
View File

@@ -0,0 +1,39 @@
version: '{build}'
environment:
DLLS_URL: https://nim-lang.org/download/dlls.zip
DLLS_ARCHIVE: dlls.zip
MINGW_DIR: mingw64
MINGW_URL: https://nim-lang.org/download/mingw64-6.3.0.7z
MINGW_ARCHIVE: mingw64-6.3.0.7z
matrix:
- NIM_TEST_PACKAGES: false
- NIM_TEST_PACKAGES: true
cache:
- '%MINGW_ARCHIVE%'
- '%DLLS_ARCHIVE%'
matrix:
#allow_failures:
# - NIM_TEST_PACKAGES: true
fast_finish: true
install:
- ps: Install-Product node 8 # node 8 or later is required to test js async stuff
- IF not exist "%DLLS_ARCHIVE%" appveyor DownloadFile "%DLLS_URL%" -FileName "%DLLS_ARCHIVE%"
- 7z x -y "%DLLS_ARCHIVE%" -o"%CD%\BIN"> nul
- IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%"
- 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul
- SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH%
- git clone --depth 1 https://github.com/nim-lang/csources
- cd csources
- build64.bat
- cd ..
build_script:
- bin\nim c koch
- koch runCI
deploy: off

View File

@@ -1,169 +0,0 @@
trigger:
branches:
include:
- 'devel'
- 'version-*'
pr:
branches:
include:
- '*'
variables:
- name: skipci
value: false
jobs:
- job: packages
timeoutInMinutes: 90 # default `60` led to lots of cancelled jobs; use 0 for unlimited (may be undesirable)
strategy:
matrix:
Linux_amd64:
vmImage: 'ubuntu-20.04'
CPU: amd64
# regularly breaks, refs bug #17325
# Linux_i386:
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-13'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-13'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
vmImage: 'windows-2019'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
pool:
vmImage: $(vmImage)
workspace:
clean: all
steps:
- bash: git config --global core.autocrlf false
displayName: 'Disable auto conversion to CRLF by git (Windows-only)'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- checkout: self
fetchDepth: 2 # see D20210329T004830
- bash: |
set -e
. ci/funs.sh
if nimIsCiSkip; then
echo '##vso[task.setvariable variable=skipci]true'
fi
displayName: 'Check whether to skip CI'
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Install node.js 20.x'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
- bash: |
set -e
. ci/funs.sh
echo_run sudo apt-fast update -qq
DEBIAN_FRONTEND='noninteractive' \
echo_run sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
displayName: 'Install dependencies (amd64 Linux)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
- bash: |
set -e
. ci/funs.sh
echo_run sudo dpkg --add-architecture i386
# Downgrade llvm:
# - llvm has to be downgraded to have 32bit version installed for sfml.
cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel
Package: libllvm6.0
Pin: origin "azure.archive.ubuntu.com"
Pin-Priority: 1001
EOF
# echo_run sudo apt-fast update -qq
echo_run sudo apt-fast update -qq || echo "failed, see bug #17343"
# `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get:
# `could not load: libffi.so` during dynamic loading.
DEBIAN_FRONTEND='noninteractive' \
echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386
cat << EOF > bin/gcc
#!/bin/bash
exec $(which gcc) -m32 "\$@"
EOF
cat << EOF > bin/g++
#!/bin/bash
exec $(which g++) -m32 "\$@"
EOF
echo_run chmod 755 bin/gcc
echo_run chmod 755 bin/g++
displayName: 'Install dependencies (i386 Linux)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386'))
- bash: brew install boehmgc make sfml
displayName: 'Install dependencies (OSX)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin'))
# XXX can't find boehm on macos 13
- bash: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin'
displayName: 'Install dependencies (Windows)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Windows_NT'))
- bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
displayName: 'Add build binaries to PATH'
- bash: . ci/funs.sh && nimCiSystemInfo
condition: and(succeeded(), eq(variables['skipci'], 'false'))
displayName: 'System information'
- bash: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu=$(CPU)
condition: and(succeeded(), eq(variables['skipci'], 'false'))
displayName: 'Build csourcesAny'
# this could be revived if performance justifies it (needs a few updates)
# - task: Cache@2
# inputs:
# key: 'csourcesAny | "$(Agent.OS)" | $(CPU) | $(csources_version)'
# path: $(nim_csources)
# condition: and(succeeded(), eq(variables['skipci'], 'false'))
# displayName: 'Restore built csourcesAny'
- bash: . ci/funs.sh && nimInternalBuildKochAndRunCI
# would could also show on failure: echo '##vso[task.complete result=Failed]'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
displayName: 'koch, Run CI'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

View File

@@ -5,16 +5,10 @@ set -e
which nim > /dev/null || (echo "nim not in PATH"; exit 1)
which gdb > /dev/null || (echo "gdb not in PATH"; exit 1)
which readlink > /dev/null || (echo "readlink not in PATH."; exit 1)
if [[ $(uname -s) == Darwin || $(uname -s) == *BSD ]]; then
NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim))))
else
NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim))))
fi
# Find out where the pretty printer Python module is
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py"
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
# Set the environment variable `NIM_GDB` to overwrite the call to a
@@ -22,4 +16,6 @@ GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py"
NIM_GDB="${NIM_GDB:-gdb}"
# exec replaces the new process of bash with gdb. It is always good to
# have fewer processes.
exec "${NIM_GDB}" -eval-command="source $GDB_PYTHON_MODULE_PATH" "$@"
exec ${NIM_GDB} \
-eval-command "source $GDB_PYTHON_MODULE_PATH" \
"$@"

View File

@@ -1,14 +0,0 @@
@echo off
for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i)
for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi)
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py
set @NIM_GDB=gdb.exe
@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt
%@NIM_GDB% --command="wingdbcommand.txt" %*
del wingdbcommand.txt /f /q
EXIT /B %ERRORLEVEL%
@echo on

View File

@@ -1,29 +0,0 @@
@echo off
rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim`
rem Build development version of the compiler; can be rerun safely
rem bare bones version of ci/funs.sh adapted for windows.
rem Read in some common shared variables (shared with other tools),
rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file
for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H
SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe
echo "building from csources: %nim_csources%"
if not exist %nim_csourcesDir% (
git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir%
)
if not exist %nim_csources% (
cd %nim_csourcesDir%
git checkout %nim_csourcesHash%
echo "%PROCESSOR_ARCHITECTURE%"
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" (
SET ARCH=64
)
CALL build.bat
cd ..
copy /y bin\nim.exe %nim_csources%
)
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
koch tools --skipUserCfg --skipParentCfg --hints:off

36
build_all.sh Executable file → Normal file
View File

@@ -1,17 +1,33 @@
#!/bin/sh
# DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim`
#! /bin/sh
# build development version of the compiler; can be rerun safely.
# arguments can be passed, e.g.:
# CC=gcc ucpu=amd64 uos=darwin
# build development version of the compiler; can be rerun safely
set -u # error on undefined variables
set -e # exit on first error
. ci/funs.sh
nimBuildCsourcesIfNeeded "$@"
echo_run(){
printf "\n$*\n"
"$@"
}
echo_run bin/nim c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
echo_run ./koch tools --skipUserCfg --skipParentCfg --hints:off
[ -d csources ] || echo_run git clone --depth 1 https://github.com/nim-lang/csources.git
nim_csources=bin/nim_csources
build_nim_csources(){
## avoid changing dir in case of failure
(
echo_run cd csources
echo_run sh build.sh $@
)
# keep $nim_csources in case needed to investigate bootstrap issues
# without having to rebuild from csources
echo_run cp bin/nim $nim_csources
}
[ -f $nim_csources ] || echo_run build_nim_csources $@
# Note: if fails, may need to `cd csources && git pull`
echo_run bin/nim c --skipUserCfg --skipParentCfg koch
echo_run ./koch boot -d:release
echo_run ./koch tools # Compile Nimble and other tools.

View File

@@ -1,28 +1,37 @@
# v2.x.x - yyyy-mm-dd
# v1.1 - XXXX-XX-XX
## Changes affecting backward compatibility
## Changes affecting backwards compatibility
- `-d:nimPreviewFloatRoundtrip` becomes the default. `system.addFloat` and `system.$` now can produce string representations of
floating point numbers that are minimal in size and possess round-trip and correct
rounding guarantees (via the
[Dragonbox](https://raw.githubusercontent.com/jk-jeon/dragonbox/master/other_files/Dragonbox.pdf) algorithm). Use `-d:nimLegacySprintf` to emulate old behaviors.
- The `default` parameter of `tables.getOrDefault` has been renamed to `def` to
avoid conflicts with `system.default`, so named argument usage for this
parameter like `getOrDefault(..., default = ...)` will have to be changed.
### Breaking changes in the standard library
## Standard library additions and changes
[//]: # "Changes:"
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
### Breaking changes in the compiler
## Library additions
## Library changes
- Added `os.delEnv` and `nimscript.delEnv`. (#11466)
- Enable Oid usage in hashtables. (#11472)
#
# Language additions
## Language changes
## Compiler changes
### Tool changes
## Tool changes
### Compiler changes
- VM can now cast integer type arbitrarily. (#11459)
## Bugfixes

55
changelog_v020.md Normal file
View File

@@ -0,0 +1,55 @@
# v0.20.2 - XXXX-XX-XX
## Changes affecting backwards compatibility
- All `strutils.rfind` procs now take `start` and `last` like `strutils.find`
with the same data slice/index meaning. This is backwards compatible for
calls *not* changing the `rfind` `start` parameter from its default. (#11487)
In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`,
then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This
should minimize gotchas porting code from other languages like Python or C++.)
- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch
`-d:nimBinaryStdFiles` for a transition period.
### Breaking changes in the standard library
- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type
conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)``
need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``.
### Breaking changes in the compiler
## Library additions
- `toOpenArray` is now available for the JS target.
## Library changes
- Fix async IO operations stalling even after socket is closed. (#11232)
- More informative error message for `streams.openFileStream`. (#11438)
## Language additions
## Language changes
### Tool changes
### Compiler changes
- Better error message for IndexError for empty containers. (#11476)
- Fix regression in semfold for old right shift. (#11477)
- Fix for passing tuples as static params to macros. (#11423)
## Bugfixes

View File

@@ -100,7 +100,7 @@
- We changed how array accesses "from backwards" like ``a[^1]`` or ``a[0..^1]`` are
implemented. These are now implemented purely in ``system.nim`` without compiler
support. There is a new "heterogeneous" slice type ``system.HSlice`` that takes 2
support. There is a new "heterogenous" slice type ``system.HSlice`` that takes 2
generic parameters which can be ``BackwardsIndex`` indices. ``BackwardsIndex`` is
produced by ``system.^``.
This means if you overload ``[]`` or ``[]=`` you need to ensure they also work
@@ -660,4 +660,4 @@ for i in a..b:
- Fixed "C++: SIGABRT instead of IndexError for out-of-bounds"
([#6512](https://github.com/nim-lang/Nim/issues/6512))
- Fixed "An uncaught exception in cpp mode doesn't show the exception name/msg"
([#6431](https://github.com/nim-lang/Nim/issues/6431))
([#6431](https://github.com/nim-lang/Nim/issues/6431))

View File

@@ -15,7 +15,7 @@
at runtime. Use ``ref object`` with inheritance rather than ``object`` with
inheritance to prevent this issue.
- The ``not nil`` type annotation now has to be enabled explicitly
via ``{.experimental: "notnil".}`` as we are still not pleased with how this
via ``{.experimental: "notnil"}`` as we are still not pleased with how this
feature works with Nim's containers.
- The parser now warns about inconsistent spacing around binary operators as
these can easily be confused with unary operators. This warning will likely

View File

@@ -1,55 +0,0 @@
# v0.20.2 - 2019-07-17
## Changes affecting backwards compatibility
- All `strutils.rfind` procs now take `start` and `last` like `strutils.find`
with the same data slice/index meaning. This is backwards compatible for
calls *not* changing the `rfind` `start` parameter from its default. (#11487)
In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`,
then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This
should minimize gotchas porting code from other languages like Python or C++.)
- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch
`-d:nimBinaryStdFiles` for a transition period.
### Breaking changes in the standard library
- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type
conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)``
need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``.
### Breaking changes in the compiler
## Library additions
- `toOpenArray` is now available for the JS target.
## Library changes
- Fix async IO operations stalling even after socket is closed. (#11232)
- More informative error message for `streams.openFileStream`. (#11438)
## Language additions
## Language changes
### Tool changes
### Compiler changes
- Better error message for IndexError for empty containers. (#11476)
- Fix regression in semfold for old right shift. (#11477)
- Fix for passing tuples as static params to macros. (#11423)
## Bugfixes

View File

@@ -1,138 +0,0 @@
# v1.0 - 2019-09-23
## Changes affecting backwards compatibility
- The switch ``-d:nimBinaryStdFiles`` does not exist anymore. Instead
stdin/stdout/stderr are binary files again. This change only affects
Windows.
- On Windows console applications the code-page is set at program startup
to UTF-8. Use the new switch `-d:nimDontSetUtf8CodePage` to disable this
feature.
- The language definition and compiler are now stricter about ``gensym``'ed
symbols in hygienic templates. See the section in the
[manual](https://nim-lang.org/docs/manual.html#templates-hygiene-in-templates)
for further details. Use the compiler switch `--oldgensym:on` for a
transition period.
### Breaking changes in the standard library
- We removed `unicode.Rune16` without any deprecation period as the name
was wrong (see the [RFC](https://github.com/nim-lang/RFCs/issues/151) for details)
and we didn't find any usages of it in the wild. If you still need it, add this
piece of code to your project:
```nim
type
Rune16* = distinct int16
```
- `exportc` now uses C instead of C++ mangling with `nim cpp`, matching behavior
of `importc`, see #10578.
Use the new `exportcpp` to mangle as C++ when using `nim cpp`.
### Breaking changes in the compiler
- A bug allowing `int` to be implicitly converted to range types of smaller size
(e.g `range[0'i8..10'i8]`) has been fixed.
## Library additions
- `encodings.getCurrentEncoding` now distinguishes between the console's
encoding and the OS's encoding. This distinction is only meaningful on
Windows.
- Added `system.getOsFileHandle` which is usually more useful
than `system.getFileHandle`. This distinction is only meaningful on
Windows.
- Added a `json.parseJsonFragments` iterator that can be used to speedup
JSON processing substantially when there are JSON fragments separated
by whitespace.
## Library changes
- Added `os.delEnv` and `nimscript.delEnv`. (#11466)
- Enabled Oid usage in hashtables. (#11472)
- Added `unsafeColumnAt` procs, that return unsafe cstring from InstantRow. (#11647)
- Make public `Sha1Digest` and `Sha1State` types and `newSha1State`,
`update` and `finalize` procedures from `sha1` module. (#11694)
- Added the `std/monotimes` module which implements monotonic timestamps.
- Consistent error handling of two `exec` overloads. (#10967)
- Officially the following modules now have an unstable API:
- std/varints
- core/allocators
- core/hotcodereloading
- asyncstreams
- base64
- browsers
- collections/rtarrays
- collections/sharedlist
- collections/sharedtable
- concurrency/atomics
- concurrency/cpuload
- concurrency/threadpool
- coro
- endians
- httpcore
- parsesql
- pathnorm
- reservedmem
- typetraits
Every other stdlib module is API stable with respect to version 1.
## Language additions
- Inline iterators returning `lent T` types are now supported, similarly to
iterators returning `var T`:
```nim
iterator myitems[T](x: openarray[T]): lent T
iterator mypairs[T](x: openarray[T]): tuple[idx: int, val: lent T]
```
- Added an `importjs` pragma that can now be used instead of `importcpp`
and `importc` to import symbols from JavaScript. `importjs` for routines always
takes a "pattern" for maximum flexibility.
## Language changes
- `uint64` is now finally a regular ordinal type. This means `high(uint64)` compiles
and yields the correct value.
### Tool changes
- The Nim compiler now does not recompile the Nim project via ``nim c -r`` if
no dependent Nim file changed. This feature can be overridden by
the ``--forceBuild`` command line option.
- The Nim compiler now warns about unused module imports. You can use a
top level ``{.used.}`` pragma in the module that you want to be importable
without producing this warning.
- The "testament" testing tool's name was changed
from `tester` to `testament` and is generally available as a tool to run Nim
tests automatically.
### Compiler changes
- VM can now cast integer type arbitrarily. (#11459)
## Bugfixes

View File

@@ -1,56 +0,0 @@
# v1.0.2 - 2019-10-23
## Bugfixes
* fixes the --verbosity:2 regression
* Fixed "Fail to compile a file twice under Windows (v1.0 bug)." [#12242](https://github.com/nim-lang/Nim/issues/12242)
* fix nimpretty removing space before pragma
* JS: gensym is stricter for 'this'
* Fixed "VM Assertion Error with newruntime" [#12294](https://github.com/nim-lang/Nim/issues/12294)
* Fixed "Assertion error when running `nim check` on compiler/nim.nim" [#12281](https://github.com/nim-lang/Nim/issues/12281)
* Fixed "Compiler crash with empty array and generic instantiation with int as parameter" [#12264](https://github.com/nim-lang/Nim/issues/12264)
* Fixed "Regression in JS backend codegen "Error: request to generate code for .compileTime proc"" [#12240](https://github.com/nim-lang/Nim/issues/12240)
* Fix how `relativePath` handle case sensitiviy
* Fixed "SIGSEGV in compiler when using generic types and seqs" [#12336](https://github.com/nim-lang/Nim/issues/12336)
* Fixed "[1.0.0] weird interaction between `import os` and casting integer to char on macosx trigger bad codegen" [#12291](https://github.com/nim-lang/Nim/issues/12291)
* VM: no special casing for big endian machines
* Fixed "`internal error: environment misses` with a simple template inside one of Jester macros" [#12323](https://github.com/nim-lang/Nim/issues/12323)
* nimsuggest: fix tcp socket leak
* nimsuggest: fix tcp socket leak for epc backend
* Fixed "`writeFile` and `write(f, str)` skip null bytes on Windows" [#12315](https://github.com/nim-lang/Nim/issues/12315)
* Fixed "Crash in intsets symmetric_difference" [#12366](https://github.com/nim-lang/Nim/issues/12366)
* Fixed "[regression] VM crash when dealing with var param of a proc result" [#12244](https://github.com/nim-lang/Nim/issues/12244)
* fixes a koch regression that made 'koch boot --listcmd' not work anymore
* Fixed "[regression] inconsistent signed int `mod` operator between runtime, compiletime, and semfold" [#12332](https://github.com/nim-lang/Nim/issues/12332)
* Fixed "Boehm disables interior pointer checking" [#12286](https://github.com/nim-lang/Nim/issues/12286)
* Fixes semCustomPragma when nkSym
* Fixed yield in nkCheckedFieldExpr
* Fixed "`randomize()` from `random` not working on JS" [#12418](https://github.com/nim-lang/Nim/issues/12418)
* Fixed "Compiler crash with invalid object variant" [#12379](https://github.com/nim-lang/Nim/issues/12379)
* fix type's case in random.nim
* Fixed "Update docs with a better way to signal unimplemented methods" [#10804](https://github.com/nim-lang/Nim/issues/10804)
* Fixed "Nim language manual, push pragma is not explained well" [#10824](https://github.com/nim-lang/Nim/issues/10824)
* Fixed "[regression] Importing more than one module with same name from different packages produce bad codegen" [#12420](https://github.com/nim-lang/Nim/issues/12420)
* Namespace unittest enums to avoid name conflicts
* Fixed "VM checks unsigned integers for overflow." [#12310](https://github.com/nim-lang/Nim/issues/12310)
* Fixed "line directive is not generated for first line of function definition" [#12426](https://github.com/nim-lang/Nim/issues/12426)
## Documentation improvements
* threadpool: fix link in docs (#12258)
* Fix spellings (#12277)
* fix #12278, don't expose internal PCRE documentation
* Fixed "Documentation of quitprocs is wrong" [#12279(https://github.com/nim-lang/Nim/issues/12279)
* Fix typo in docs
* Fix reference to parseSpec proc in readme
* [doc/tut1] removed discard discussion in comments
* Documentation improvements around the db interface
* Easier build instructions for windows - just run `build_all.bat`.
* fix a few dead links and a missing sentence in documentation
* Macro docs additions
* Updated the code example in the os module to use better grammar.
* Mention "lambdas" and `=>` in the manual
* Better documentation on Garbage Collector

View File

@@ -1,535 +0,0 @@
# v1.2.0 - 2020-04-02
## 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`,
`CountTable.pop`, `Table.pop`.
- Added `strtabs.clear` overload that reuses the existing mode.
- Added `browsers.osOpen` const alias for the operating system specific *"open"* command.
- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle`
into operations that work on a copy of the data and return the mutated copy,
like the existing `sorted` does.
- Added `sugar.collect` that does comprehension for seq/set/table collections.
- Added `sugar.capture` for capturing some local loop variables when creating a
closure. This is an enhanced version of `closureScope`.
- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple,
and `typetraits.get` to get the ith element of a type tuple.
- Added `typetraits.genericParams` to return a tuple of generic params from a
generic instantiation.
- `options` now treats `proc` like other pointer types, meaning `nil` proc variables
are converted to `None`.
- Added `os.normalizePathEnd` for additional path sanitization.
- Added `times.fromUnixFloat,toUnixFloat`, sub-second resolution versions of
`fromUnix`,`toUnixFloat`.
- Added `wrapnils` module for chains of field-access and indexing where the LHS
can be nil. This simplifies code by reducing need for if-else branches around
intermediate maybe nil values. E.g. `echo ?.n.typ.kind`.
- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module.
- Added `os.isRelativeTo` to tell whether a path is relative to another.
- Added `resetOutputFormatters` to `unittest`.
- Added `expectIdent` to the `macros` module.
- Added `os.isValidFilename` that returns `true` if `filename` argument is valid
for cross-platform use.
- 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.
- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for
retrieving the verified certificate chain of the peer we are connected to
through an SSL-wrapped `Socket`/`AsyncSocket`.
- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3.
- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target.
- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12`
- Added new module `std/stackframes`, in particular `setFrameMsg`, which enables
custom runtime annotation of stackframes, see #13351 for examples.
Turn on/off via `--stackTraceMsgs:on/off`.
- Added `sequtils.countIt`, allowing for counting items using a predicate.
- Added a `with` macro for easy function chaining that's available everywhere,
there is no need to concern your APIs with returning the first argument
to enable "chaining", instead use the dedicated macro `with` that
was designed for it. For example:
```nim
import std/with
type
Foo = object
col, pos: string
proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b)
proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y)
var f: Foo
with(f, setColor(2, 3, 4), setPosition(0.0, 1.0))
echo f
```
- `macros.newLit` now works for ref object types.
- `macro pragmas` can now be used in type sections.
- 5 new pragmas were added to Nim in order to make the upcoming tooling more
convenient to use. Nim compiler checks these pragmas for syntax but otherwise
ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`.
- `system.writeFile` has been overloaded to also support `openarray[byte]`.
- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations`
and only returns once all pending async operations are guaranteed to have completed.
- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples
now do not have fields named "a" and "b".
- `distinctBase` has been moved from `sugar` to `typetraits` and now it is
implemented as compiler type trait instead of macro. `distinctBase` in sugar
module is now deprecated.
- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it
was an oversight to be included in v1.0.
- `tables.merge(CountTable, CountTable): CountTable` has been removed.
It didn't work well together with the existing inplace version of the same proc
(`tables.merge(var CountTable, CountTable)`).
It was an oversight to be included in v1.0.
- `asyncdispatch.drain` now consistently uses the passed timeout value for all
iterations of the event loop, and not just the first iteration.
This is more consistent with the other asyncdispatch APIs, and allows
`asyncdispatch.drain` to be more efficient.
- `base64.encode` and `base64.decode` were made faster by about 50%.
- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support
(ISO 40314).
- `macros.eqIdent` is now invariant to export markers and backtick quotes.
- `htmlgen.html` allows `lang` in the `<html>` tag and common valid attributes.
- `macros.basename` and `basename=` got support for `PragmaExpr`,
so that an expression like `MyEnum {.pure.}` is handled correctly.
- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values
serve no purpose whatsoever.
- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers`
argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`.
- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is
empty. This was required for intuitive behaviour of the strscans module
(see bug #13605).
- `strutils.formatFloat` with `precision = 0` has the same behavior in all
backends, and it is compatible with Python's behavior,
e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`.
- `times.parse` now only uses input to compute its result, and not `now`:
`parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of
`2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when
used on 29th, 30th, 31st of each month.
- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical
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.
- `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),
`os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for
subdirs, otherwise it would be impossible to resume iteration.
- The `FD` variant of `selector.unregister` for `ioselector_epoll` and
`ioselector_select` now properly handle the `Event.User` select event type.
- `joinPath` path normalization when `/` is the first argument works correctly:
`assert "/" / "/a" == "/a"`. Fixed the edge case: `assert "" / "" == ""`.
- `xmltree` now adds indentation consistently to child nodes for any number
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.
- `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.
- `os.joinPath(a, b)` now honors trailing slashes in `b` (or `a` if `b` = "").
- `base64.encode` no longer supports `lineLen` and `newLine`.
Use `base64.encodeMime` instead.
### Breaking changes
- `net.newContext` now performs SSL Certificate checking on Linux and OSX.
Define `nimDisableCertificateValidation` to disable it globally.
## Language changes
- An `align` pragma can now be used for variables and object fields, similar
to the `alignas` declaration modifier in C/C++.
- The `=sink` type bound operator is now optional. The compiler can now use a
combination of `=destroy` and `copyMem` to move objects efficiently.
- Unsigned integer operators have been fixed to allow promotion of the first operand.
- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim
versions. The documentation was improved to acknowledge this special case.
See https://github.com/nim-lang/RFCs/issues/175 for more details.
- There is a new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by
`import std/decls`.
- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for
non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`).
## Compiler changes
- The generated JS code uses spaces, instead of mixing spaces and tabs.
- 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
pass specific compiler options to the C(++) backend for the C(++) file
that was produced from the current Nim module.
- The compiler now inferes "sink parameters". To disable this for a specific routine,
annotate it with `.nosinks`. To disable it for a section of code, use
`{.push sinkInference: off.}`...`{.pop.}`.
- The compiler now supports a new switch `--panics:on` that turns runtime
errors like `IndexError` or `OverflowError` into fatal errors that **cannot**
be caught via Nim's `try` statement. `--panics:on` can improve the
runtime efficiency and code size of your program significantly.
- The compiler now warns about inheriting directly from `system.Exception` as
this is **very bad** style. You should inherit from `ValueError`, `IOError`,
`OSError` or from a different specific exception type that inherits from
`CatchableError` and cannot be confused with a `Defect`.
- The error reporting for Nim's effect system has been improved.
- Implicit conversions for `const` behave correctly now, meaning that code like
`const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now.
Simply write `const SOMECONST = 0` instead.
- The `{.dynlib.}` pragma is now required for exporting symbols when making
shared objects on POSIX and macOS, which make it consistent with the behavior
on Windows.
- The compiler is now more strict about type conversions concerning proc
types: Type conversions cannot be used to hide `.raise` effects or side
effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the
old behaviour is emulated.
- The Nim compiler now implements a faster way to detect overflows based
on GCC's `__builtin_sadd_overflow` family of functions. (Clang also
supports these). Some versions of GCC lack this feature and unfortunately
we cannot detect this case reliably. So if you get compilation errors like
"undefined reference to `__builtin_saddll_overflow`" compile your programs
with `-d:nimEmulateOverflowChecks`.
## Bugfixes
- Fixed "`nimgrep --nocolor` is ignored on posix; should be instead: `--nimgrep --color=[auto]|true|false`"
([#7591](https://github.com/nim-lang/Nim/issues/7591))
- Fixed "Runtime index on const array (of converted obj) causes C-compiler error"
([#10514](https://github.com/nim-lang/Nim/issues/10514))
- Fixed "windows x86 with vcc compile error with "asmNoStackFrame""
([#12298](https://github.com/nim-lang/Nim/issues/12298))
- Fixed "[TODO] regression: Error: Locks requires --threads:on option"
([#12330](https://github.com/nim-lang/Nim/issues/12330))
- Fixed "Add --cc option to --help or --fullhelp output"
([#12010](https://github.com/nim-lang/Nim/issues/12010))
- Fixed "questionable `csize` definition in `system.nim`"
([#12187](https://github.com/nim-lang/Nim/issues/12187))
- Fixed "os.getAppFilename() returns incorrect results on OpenBSD"
([#12389](https://github.com/nim-lang/Nim/issues/12389))
- Fixed "HashSet[uint64] slow insertion depending on values"
([#11764](https://github.com/nim-lang/Nim/issues/11764))
- Fixed "Differences between compiling 'classic call syntax' vs 'method call syntax' ."
([#12453](https://github.com/nim-lang/Nim/issues/12453))
- Fixed "c -d:nodejs --> SIGSEGV: Illegal storage access"
([#12502](https://github.com/nim-lang/Nim/issues/12502))
- Fixed "Closure iterator crashes on --newruntime due to "dangling references""
([#12443](https://github.com/nim-lang/Nim/issues/12443))
- Fixed "No `=destroy` for elements of closure environments other than for latest devel --gc:destructors"
([#12577](https://github.com/nim-lang/Nim/issues/12577))
- Fixed "strutils:formatBiggestFloat() gives different results in JS mode"
([#8242](https://github.com/nim-lang/Nim/issues/8242))
- Fixed "Regression (devel): the new `csize_t` definition isn't consistently used, nor tested thoroughly..."
([#12597](https://github.com/nim-lang/Nim/issues/12597))
- Fixed "tables.take() is defined only for `Table` and missed for other table containers"
([#12519](https://github.com/nim-lang/Nim/issues/12519))
- Fixed "`pthread_key_t` errors on OpenBSD"
([#12135](https://github.com/nim-lang/Nim/issues/12135))
- Fixed "newruntime: simple seq pop at ct results in compile error"
([#12644](https://github.com/nim-lang/Nim/issues/12644))
- Fixed "[Windows] finish.exe C:\Users\<USERNAME>\.nimble\bin is not in your PATH environment variable."
([#12319](https://github.com/nim-lang/Nim/issues/12319))
- Fixed "Error with strformat + asyncdispatch + const"
([#12612](https://github.com/nim-lang/Nim/issues/12612))
- Fixed "MultipartData needs $"
([#11863](https://github.com/nim-lang/Nim/issues/11863))
- Fixed "Nim stdlib style issues with --styleCheck:error"
([#12687](https://github.com/nim-lang/Nim/issues/12687))
- Fixed "new $nimbleDir path substitution yields unexpected search paths"
([#12767](https://github.com/nim-lang/Nim/issues/12767))
- Fixed "Regression: inlined procs now get multiple rounds of destructor injection"
([#12766](https://github.com/nim-lang/Nim/issues/12766))
- Fixed "newruntime: compiler generates defective code"
([#12669](https://github.com/nim-lang/Nim/issues/12669))
- Fixed "broken windows modules path handling because of 'os.relativePath' breaking changes"
([#12734](https://github.com/nim-lang/Nim/issues/12734))
- Fixed "for loop tuple syntax not rendered correctly"
([#12740](https://github.com/nim-lang/Nim/issues/12740))
- Fixed "Crash when trying to use `type.name[0]`"
([#12804](https://github.com/nim-lang/Nim/issues/12804))
- Fixed "Enums should be considered Trivial types in Atomics"
([#12812](https://github.com/nim-lang/Nim/issues/12812))
- Fixed "Produce static/const initializations for variables when possible"
([#12216](https://github.com/nim-lang/Nim/issues/12216))
- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors"
([#12821](https://github.com/nim-lang/Nim/issues/12821))
- Fixed "nimsuggest `use` command does not return all instances of symbol"
([#12832](https://github.com/nim-lang/Nim/issues/12832))
- Fixed "@[] is a problem for --gc:destructors"
([#12820](https://github.com/nim-lang/Nim/issues/12820))
- Fixed "Codegen ICE in allPathsAsgnResult"
([#12827](https://github.com/nim-lang/Nim/issues/12827))
- Fixed "seq[Object with ref and destructor type] doesn't work in old runtime"
([#12882](https://github.com/nim-lang/Nim/issues/12882))
- Fixed "Destructor not invoked because it is instantiated too late, old runtime"
([#12883](https://github.com/nim-lang/Nim/issues/12883))
- Fixed "The collect macro does not handle if/case correctly"
([#12874](https://github.com/nim-lang/Nim/issues/12874))
- Fixed "allow typed/untyped params in magic procs (even if not in stdlib)"
([#12911](https://github.com/nim-lang/Nim/issues/12911))
- Fixed "ARC/newruntime memory corruption"
([#12899](https://github.com/nim-lang/Nim/issues/12899))
- Fixed "tasyncclosestall.nim still flaky test: Address already in use"
([#12919](https://github.com/nim-lang/Nim/issues/12919))
- Fixed "newruntime and computed goto: variables inside the loop are in generated code uninitialised"
([#12785](https://github.com/nim-lang/Nim/issues/12785))
- Fixed "osx: dsymutil needs to be called for debug builds to keep debug info"
([#12735](https://github.com/nim-lang/Nim/issues/12735))
- Fixed "codegen ICE with ref objects, gc:destructors"
([#12826](https://github.com/nim-lang/Nim/issues/12826))
- Fixed "mutable iterator cannot yield named tuples"
([#12945](https://github.com/nim-lang/Nim/issues/12945))
- Fixed "parsecfg stores "\r\n" line breaks just as "\n""
([#12970](https://github.com/nim-lang/Nim/issues/12970))
- Fixed "db_postgres.getValue issues warning when no rows found"
([#12973](https://github.com/nim-lang/Nim/issues/12973))
- Fixed "ARC: Unpacking tuple with seq causes segfault"
([#12989](https://github.com/nim-lang/Nim/issues/12989))
- Fixed "ARC/newruntime: strutils.join on seq with only empty strings causes segfault"
([#12965](https://github.com/nim-lang/Nim/issues/12965))
- Fixed "regression (1.0.4): `{.push exportc.}` wrongly affects generic instantiations, causing codegen errors"
([#12985](https://github.com/nim-lang/Nim/issues/12985))
- Fixed "cdt, crash with --gc:arc, works fine with default gc"
([#12978](https://github.com/nim-lang/Nim/issues/12978))
- Fixed "ARC: No indexError thrown on out-of-bound seq access, SIGSEGV instead"
([#12961](https://github.com/nim-lang/Nim/issues/12961))
- Fixed "ARC/async: Returning in a try-block results in wrong codegen"
([#12956](https://github.com/nim-lang/Nim/issues/12956))
- Fixed "asm keyword is generating wrong output C code when --cc:tcc"
([#12988](https://github.com/nim-lang/Nim/issues/12988))
- Fixed "Destructor not invoked"
([#13026](https://github.com/nim-lang/Nim/issues/13026))
- Fixed "ARC/newruntime: Adding inherited var ref object to seq with base type causes segfault"
([#12964](https://github.com/nim-lang/Nim/issues/12964))
- Fixed "Style check error with JS compiler target"
([#13032](https://github.com/nim-lang/Nim/issues/13032))
- Fixed "regression(1.0.4): undeclared identifier: 'readLines'; plus another regression and bug"
([#13013](https://github.com/nim-lang/Nim/issues/13013))
- Fixed "regression(1.04) `invalid pragma: since` with nim js"
([#12996](https://github.com/nim-lang/Nim/issues/12996))
- Fixed "Sink to MemMove optimization in injectdestructors"
([#13002](https://github.com/nim-lang/Nim/issues/13002))
- Fixed "--gc:arc: `catch` doesn't work with exception subclassing"
([#13072](https://github.com/nim-lang/Nim/issues/13072))
- Fixed "nim c --gc:arc --exceptions:{setjmp,goto} incorrectly handles raise; `nim cpp --gc:arc` is ok"
([#13070](https://github.com/nim-lang/Nim/issues/13070))
- Fixed "typetraits feature request - get subtype of a generic type"
([#6454](https://github.com/nim-lang/Nim/issues/6454))
- Fixed "CountTable inconsistencies between keys() and len() after setting value to 0"
([#12813](https://github.com/nim-lang/Nim/issues/12813))
- Fixed "{.align.} pragma is not applied if there is a generic field"
([#13122](https://github.com/nim-lang/Nim/issues/13122))
- Fixed "ARC, finalizer, allow rebinding the same function multiple times"
([#13112](https://github.com/nim-lang/Nim/issues/13112))
- Fixed "`nim doc` treats `export localSymbol` incorrectly"
([#13100](https://github.com/nim-lang/Nim/issues/13100))
- Fixed "--gc:arc SIGSEGV (double free?)"
([#13119](https://github.com/nim-lang/Nim/issues/13119))
- Fixed "codegen bug with arc"
([#13105](https://github.com/nim-lang/Nim/issues/13105))
- Fixed "symbols not defined in the grammar"
([#10665](https://github.com/nim-lang/Nim/issues/10665))
- Fixed "[JS] Move is not defined"
([#9674](https://github.com/nim-lang/Nim/issues/9674))
- Fixed "[TODO] pathutils.`/` can return invalid AbsoluteFile"
([#13121](https://github.com/nim-lang/Nim/issues/13121))
- Fixed "regression(1.04) `nim doc main.nim` generates broken html (no css)"
([#12998](https://github.com/nim-lang/Nim/issues/12998))
- Fixed "Wrong supportsCopyMem on string in type section"
([#13095](https://github.com/nim-lang/Nim/issues/13095))
- Fixed "Arc, finalizer, out of memory"
([#13157](https://github.com/nim-lang/Nim/issues/13157))
- Fixed "`--genscript` messes up nimcache and future nim invocations"
([#13144](https://github.com/nim-lang/Nim/issues/13144))
- Fixed "--gc:arc with --exceptions:goto for "nim c" generate invalid c code"
([#13186](https://github.com/nim-lang/Nim/issues/13186))
- Fixed "[regression] duplicate member `_i1` codegen bug"
([#13195](https://github.com/nim-lang/Nim/issues/13195))
- Fixed "RTree investigations with valgrind for --gc:arc"
([#13110](https://github.com/nim-lang/Nim/issues/13110))
- Fixed "relativePath("foo", ".") returns wrong path"
([#13211](https://github.com/nim-lang/Nim/issues/13211))
- Fixed "asyncftpclient - problem with welcome.msg"
([#4684](https://github.com/nim-lang/Nim/issues/4684))
- Fixed "Unclear error message, lowest priority"
([#13256](https://github.com/nim-lang/Nim/issues/13256))
- Fixed "Channel messages are corrupted"
([#13219](https://github.com/nim-lang/Nim/issues/13219))
- Fixed "Codegen bug with exportc and case objects"
([#13281](https://github.com/nim-lang/Nim/issues/13281))
- Fixed "[bugfix] fix #11590: c compiler warnings silently ignored, giving undefined behavior"
([#11591](https://github.com/nim-lang/Nim/issues/11591))
- Fixed "[CI] tnetdial flaky test"
([#13132](https://github.com/nim-lang/Nim/issues/13132))
- Fixed "Cross-Compiling with -d:mingw fails to locate compiler under OSX"
([#10717](https://github.com/nim-lang/Nim/issues/10717))
- Fixed "`nim doc --project` broken with imports below main project file or duplicate names"
([#13150](https://github.com/nim-lang/Nim/issues/13150))
- Fixed "regression: isNamedTuple(MyGenericTuple[int]) is false, should be true"
([#13349](https://github.com/nim-lang/Nim/issues/13349))
- Fixed "--gc:arc codegen bug copying objects bound to C structs with missing C struct fields"
([#13269](https://github.com/nim-lang/Nim/issues/13269))
- Fixed "write requires conversion to string"
([#13182](https://github.com/nim-lang/Nim/issues/13182))
- Fixed "Some remarks to stdlib documentation"
([#13352](https://github.com/nim-lang/Nim/issues/13352))
- Fixed "a `check` in unittest generated by template doesn't show actual value"
([#6736](https://github.com/nim-lang/Nim/issues/6736))
- Fixed "Implicit return with case expression fails with 'var' return."
([#3339](https://github.com/nim-lang/Nim/issues/3339))
- Fixed "Segfault with closure on arc"
([#13314](https://github.com/nim-lang/Nim/issues/13314))
- Fixed "[Macro] Crash on malformed case statement with multiple else"
([#13255](https://github.com/nim-lang/Nim/issues/13255))
- Fixed "regression: `echo 'discard' | nim c -r -` generates a file '-' ; `-` should be treated specially"
([#13374](https://github.com/nim-lang/Nim/issues/13374))
- Fixed "on OSX, debugging (w gdb or lldb) a nim program crashes at the 1st call to `execCmdEx`"
([#9634](https://github.com/nim-lang/Nim/issues/9634))
- Fixed "Internal error in getTypeDescAux"
([#13378](https://github.com/nim-lang/Nim/issues/13378))
- Fixed "gc:arc mode breaks tuple let"
([#13368](https://github.com/nim-lang/Nim/issues/13368))
- Fixed "Nim compiler hangs for certain C/C++ compiler errors"
([#8648](https://github.com/nim-lang/Nim/issues/8648))
- Fixed "htmlgen does not support `data-*` attributes"
([#13444](https://github.com/nim-lang/Nim/issues/13444))
- Fixed "[gc:arc] setLen will cause string not to be null-terminated."
([#13457](https://github.com/nim-lang/Nim/issues/13457))
- Fixed "joinPath("", "") is "/" ; should be """
([#13455](https://github.com/nim-lang/Nim/issues/13455))
- Fixed "[CI] flaky test on windows: tests/osproc/texitcode.nim"
([#13449](https://github.com/nim-lang/Nim/issues/13449))
- Fixed "Casting to float32 on NimVM is broken"
([#13479](https://github.com/nim-lang/Nim/issues/13479))
- Fixed "`--hints:off` doesn't work (doesn't override ~/.config/nim.cfg)"
([#8312](https://github.com/nim-lang/Nim/issues/8312))
- Fixed "joinPath("", "") is "/" ; should be """
([#13455](https://github.com/nim-lang/Nim/issues/13455))
- Fixed "tables.values is broken"
([#13496](https://github.com/nim-lang/Nim/issues/13496))
- Fixed "global user config can override project specific config"
([#9405](https://github.com/nim-lang/Nim/issues/9405))
- Fixed "Non deterministic macros and id consistency problem"
([#12627](https://github.com/nim-lang/Nim/issues/12627))
- Fixed "try expression doesn't work with return on expect branch"
([#13490](https://github.com/nim-lang/Nim/issues/13490))
- Fixed "CI will break every 4 years on feb 28: times doesn't handle leap years properly"
([#13543](https://github.com/nim-lang/Nim/issues/13543))
- Fixed "[minor] `nimgrep --word` doesn't work with operators (eg misses `1 +% 2`)"
([#13528](https://github.com/nim-lang/Nim/issues/13528))
- Fixed "`as` is usable as infix operator but its existence and precedence are not documented"
([#13409](https://github.com/nim-lang/Nim/issues/13409))
- Fixed "JSON unmarshalling drops seq's items"
([#13531](https://github.com/nim-lang/Nim/issues/13531))
- Fixed "os.joinPath returns wrong path when head ends '\' or '/' and tail starts '..'."
([#13579](https://github.com/nim-lang/Nim/issues/13579))
- Fixed "Block-local types with the same name lead to bad codegen (sighashes regression)"
([#5170](https://github.com/nim-lang/Nim/issues/5170))
- Fixed "tuple codegen error"
([#12704](https://github.com/nim-lang/Nim/issues/12704))
- Fixed "newHttpHeaders does not accept repeated headers"
([#13573](https://github.com/nim-lang/Nim/issues/13573))
- Fixed "regression: --incremental:on fails on simplest example"
([#13319](https://github.com/nim-lang/Nim/issues/13319))
- Fixed "strscan can't get value of last element in format"
([#13605](https://github.com/nim-lang/Nim/issues/13605))
- Fixed "hashes_examples crashes with "Bus Error" (unaligned access) on sparc64"
([#12508](https://github.com/nim-lang/Nim/issues/12508))
- Fixed "gc:arc bug with re-used `seq[T]`"
([#13596](https://github.com/nim-lang/Nim/issues/13596))
- Fixed "`raise CatchableError` is broken with --gc:arc when throwing inside a proc"
([#13599](https://github.com/nim-lang/Nim/issues/13599))
- Fixed "cpp --gc:arc --exceptions:goto fails to raise with discard"
([#13436](https://github.com/nim-lang/Nim/issues/13436))
- Fixed "terminal doesn't compile with -d:useWinAnsi"
([#13607](https://github.com/nim-lang/Nim/issues/13607))
- Fixed "Parsing "sink ptr T" - region needs to be an object type"
([#12757](https://github.com/nim-lang/Nim/issues/12757))
- Fixed "gc:arc + threads:on + closures compilation error"
([#13519](https://github.com/nim-lang/Nim/issues/13519))
- Fixed "[ARC] segmentation fault"
([#13240](https://github.com/nim-lang/Nim/issues/13240))
- Fixed "times.toDateTime buggy on 29th, 30th and 31th of each month"
([#13558](https://github.com/nim-lang/Nim/issues/13558))
- Fixed "Deque misbehaves on VM"
([#13310](https://github.com/nim-lang/Nim/issues/13310))
- Fixed "Nimscript listFiles should throw exception when path is not found"
([#12676](https://github.com/nim-lang/Nim/issues/12676))
- Fixed "koch boot fails if even an empty config.nims is present in ~/.config/nims/ [devel regression]"
([#13633](https://github.com/nim-lang/Nim/issues/13633))
- Fixed "nim doc generates lots of false positive LockLevel warnings"
([#13218](https://github.com/nim-lang/Nim/issues/13218))
- Fixed "Arrays are passed by copy to iterators, causing crashes, unnecessary allocations and slowdowns"
([#12747](https://github.com/nim-lang/Nim/issues/12747))
- Fixed "Range types always uses signed integer as a base type"
([#13646](https://github.com/nim-lang/Nim/issues/13646))
- Fixed "Generate c code cannot compile with recent devel version"
([#13645](https://github.com/nim-lang/Nim/issues/13645))
- Fixed "[regression] VM: Error: cannot convert -1 to uint64"
([#13661](https://github.com/nim-lang/Nim/issues/13661))
- Fixed "Spurious raiseException(Exception) detected"
([#13654](https://github.com/nim-lang/Nim/issues/13654))
- Fixed "gc:arc memory leak"
([#13659](https://github.com/nim-lang/Nim/issues/13659))
- Fixed "Error: cannot convert -1 to uint (inside tuples)"
([#13671](https://github.com/nim-lang/Nim/issues/13671))
- Fixed "strformat issue with --gc:arc"
([#13622](https://github.com/nim-lang/Nim/issues/13622))
- Fixed "astToStr doesn't work inside generics"
([#13524](https://github.com/nim-lang/Nim/issues/13524))
- Fixed "oswalkdir.walkDirRec wont return folders"
([#11458](https://github.com/nim-lang/Nim/issues/11458))
- Fixed "`echo 'echo 1' | nim c -r -` silently gives wrong results (nimBetterRun not updated for stdin)"
([#13412](https://github.com/nim-lang/Nim/issues/13412))
- Fixed "gc:arc destroys the global variable accidentally."
([#13691](https://github.com/nim-lang/Nim/issues/13691))
- Fixed "[minor] sigmatch errors should be sorted, for reproducible errors"
([#13538](https://github.com/nim-lang/Nim/issues/13538))
- Fixed "Exception when converting csize to clong"
([#13698](https://github.com/nim-lang/Nim/issues/13698))
- Fixed "ARC: variables are no copied on the thread spawn causing crashes"
([#13708](https://github.com/nim-lang/Nim/issues/13708))
- Fixed "Illegal distinct seq causes compiler crash"
([#13720](https://github.com/nim-lang/Nim/issues/13720))
- Fixed "cyclic seq definition crashes the compiler"
([#13715](https://github.com/nim-lang/Nim/issues/13715))
- Fixed "Iterator with openArray parameter make the argument evaluated many times"
([#13417](https://github.com/nim-lang/Nim/issues/13417))
- Fixed "net/asyncnet: Unable to access peer's certificate chain"
([#13299](https://github.com/nim-lang/Nim/issues/13299))
- Fixed "Accidentally "SIGSEGV: Illegal storage access" error after arc optimizations (#13325)"
([#13709](https://github.com/nim-lang/Nim/issues/13709))
- Fixed "Base64 Regression"
([#13722](https://github.com/nim-lang/Nim/issues/13722))
- Fixed "A regression (?) with --gc:arc and repr"
([#13731](https://github.com/nim-lang/Nim/issues/13731))
- Fixed "Internal compiler error when using the new variable pragmas"
([#13737](https://github.com/nim-lang/Nim/issues/13737))
- Fixed "bool conversion produces vcc 2019 warning at cpp compilation stage"
([#13744](https://github.com/nim-lang/Nim/issues/13744))
- Fixed "Compiler "does not detect" a type recursion error in the wrong code, remaining frozen"
([#13763](https://github.com/nim-lang/Nim/issues/13763))
- Fixed "[minor] regression: `Foo[0.0] is Foo[-0.0]` is now false"
([#13730](https://github.com/nim-lang/Nim/issues/13730))
- Fixed "`nim doc` - only whitespace on first line causes segfault"
([#13631](https://github.com/nim-lang/Nim/issues/13631))
- Fixed "hashset regression"
([#13794](https://github.com/nim-lang/Nim/issues/13794))
- Fixed "`os.getApplFreebsd` could return incorrect paths in the case of a long path"
([#13806](https://github.com/nim-lang/Nim/issues/13806))
- Fixed "Destructors are not inherited"
([#13810](https://github.com/nim-lang/Nim/issues/13810))
- Fixed "io.readLines AssertionError on devel"
([#13829](https://github.com/nim-lang/Nim/issues/13829))
- Fixed "exceptions:goto accidentally reset the variable during exception handling"
([#13782](https://github.com/nim-lang/Nim/issues/13782))

View File

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

View File

@@ -1,957 +0,0 @@
# v1.6.0 - 2021-10-14
# Major new features
With so many new features, pinpointing the most salient ones is a subjective exercise,
but here are a select few:
## `iterable[T]`
The `iterable[T]` type class was added to match called iterators,
which solves a number of long-standing issues related to iterators.
Example:
```nim
iterator iota(n: int): int =
for i in 0..<n: yield i
# previously, you'd need `untyped`, which caused other problems such as lack
# of type inference, overloading issues, and MCS.
template sumOld(a: untyped): untyped = # no type inference possible
var result: typeof(block:(for ai in a: ai))
for ai in a: result += ai
result
assert sumOld(iota(3)) == 0 + 1 + 2
# now, you can write:
template sum[T](a: iterable[T]): T =
# `template sum(a: iterable): auto =` would also be possible
var result: T
for ai in a: result += ai
result
assert sum(iota(3)) == 0 + 1 + 2 # or `iota(3).sum`
```
In particular iterable arguments can now be used with the method call syntax. For example:
```nim
import std/[sequtils, os]
echo walkFiles("*").toSeq # now works
```
See PR [#17196](https://github.com/nim-lang/Nim/pull/17196) for additional details.
## Strict effects
The effect system was refined and there is a new `.effectsOf` annotation that does
explicitly what was previously done implicitly. See the
[manual](https://nim-lang.github.io/Nim/manual.html#effect-system-effectsof-annotation)
for more details.
To write code that is portable with older Nim versions, use this idiom:
```nim
when defined(nimHasEffectsOf):
{.experimental: "strictEffects".}
else:
{.pragma: effectsOf.}
proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.}
```
To enable the new effect system, compile with `--experimental:strictEffects`.
See also [#18777](https://github.com/nim-lang/Nim/pull/18777) and RFC
[#408](https://github.com/nim-lang/RFCs/issues/408).
## Private imports and private field access
A new import syntax `import foo {.all.}` now allows importing all symbols
(public or private) from `foo`.
This can be useful for testing purposes or for more flexibility in project organization.
Example:
```nim
from system {.all.} as system2 import nil
echo system2.ThisIsSystem # ThisIsSystem is private in `system`
import os {.all.} # weirdTarget is private in `os`
echo weirdTarget # or `os.weirdTarget`
```
Added a new module `std/importutils`, and an API `privateAccess`, which allows access
to private fields for an object type in the current scope.
Example:
```nim
import times
from std/importutils import privateAccess
block:
let t = now()
# echo t.monthdayZero # Error: undeclared field: 'monthdayZero' for type times.DateTime
privateAccess(typeof(t)) # enables private access in this scope
echo t.monthdayZero # ok
```
See PR [#17706](https://github.com/nim-lang/Nim/pull/17706) for additional details.
## `nim --eval:cmd`
Added `nim --eval:cmd` to evaluate a command directly, e.g.: `nim --eval:"echo 1"`.
It defaults to `e` (nimscript) but can also work with other commands, e.g.:
```bash
find . | nim r --eval:'import strutils; for a in stdin.lines: echo a.toUpper'
```
```bash
# use as a calculator:
nim --eval:'echo 3.1 / (1.2+7)'
# explore a module's APIs, including private symbols:
nim --eval:'import os {.all.}; echo weirdTarget'
# use a custom backend:
nim r -b:js --eval:"import std/jsbigints; echo 2'big ** 64'big"
```
See PR [#15687](https://github.com/nim-lang/Nim/pull/15687) for more details.
## Round-trip float to string
`system.addFloat` and `system.$` now can produce string representations of
floating point numbers that are minimal in size and possess round-trip and correct
rounding guarantees (via the
[Dragonbox](https://raw.githubusercontent.com/jk-jeon/dragonbox/master/other_files/Dragonbox.pdf) algorithm).
This currently has to be enabled via `-d:nimPreviewFloatRoundtrip`.
It is expected that this behavior becomes the new default in upcoming versions,
as with other `nimPreviewX` define flags.
Example:
```nim
from math import round
let a = round(9.779999999999999, 2)
assert a == 9.78
echo a # with `-d:nimPreviewFloatRoundtrip`: 9.78, like in python3 (instead of 9.779999999999999)
```
## New `std/jsbigints` module
Provides arbitrary precision integers for the JS target. See PR
[#16409](https://github.com/nim-lang/Nim/pull/16409).
Example:
```nim
import std/jsbigints
assert 2'big ** 65'big == 36893488147419103232'big
echo 0xdeadbeef'big shl 4'big # 59774856944n
```
## New `std/sysrand` module
Cryptographically secure pseudorandom number generator,
allows generating random numbers from a secure source provided by the operating system.
Example:
```nim
import std/sysrand
assert urandom(1234) != urandom(1234) # unlikely to fail in practice
```
See PR [#16459](https://github.com/nim-lang/Nim/pull/16459).
## New module: `std/tempfiles`
Allows creating temporary files and directories, see PR
[#17361](https://github.com/nim-lang/Nim/pull/17361) and followups.
```nim
import std/tempfiles
let tmpPath = genTempPath("prefix", "suffix.log", "/tmp/")
# tmpPath looks like: /tmp/prefixpmW1P2KLsuffix.log
let dir = createTempDir("tmpprefix_", "_end")
# created dir looks like: getTempDir() / "tmpprefix_YEl9VuVj_end"
let (cfile, path) = createTempFile("tmpprefix_", "_end.tmp")
# path looks like: getTempDir() / "tmpprefix_FDCIRZA0_end.tmp"
cfile.write "foo"
cfile.setFilePos 0
assert readAll(cfile) == "foo"
close cfile
assert readFile(path) == "foo"
```
## User-defined literals
Custom numeric literals (e.g. `-128'bignum`) are now supported.
Additionally, the unary minus in `-1` is now part of the integer literal, i.e.
it is now parsed as a single token.
This implies that edge cases like `-128'i8` finally work correctly.
Example:
```nim
func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".}
assert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big
```
## Dot-like operators
With `-d:nimPreviewDotLikeOps`, dot-like operators (operators starting with `.`,
but not with `..`) now have the same precedence as `.`, so that `a.?b.c` is now
parsed as `(a.?b).c` instead of `a.?(b.c)`.
A warning is generated when a dot-like operator is used without `-d:nimPreviewDotLikeOps`.
An important use case is to enable dynamic fields without affecting the
built-in `.` operator, e.g. for `std/jsffi`, `std/json`, `pkg/nimpy`. Example:
```nim
import std/json
template `.?`(a: JsonNode, b: untyped{ident}): JsonNode =
a[astToStr(b)]
let j = %*{"a1": {"a2": 10}}
assert j.?a1.?a2.getInt == 10
```
## Block arguments now support optional parameters
This solves a major pain point for routines accepting block parameters,
see PR [#18631](https://github.com/nim-lang/Nim/pull/18631) for details:
```nim
template fn(a = 1, b = 2, body) = discard
fn(1, 2): # already works
bar
fn(a = 1): # now works
bar
```
Likewise with multiple block arguments via `do`:
```nim
template fn(a = 1, b = 2, body1, body2) = discard
fn(a = 1): # now works
bar1
do:
bar2
```
# Other new features
## New and deprecated modules
The following modules were added (they are discussed in the rest of the text):
- `std/enumutils`
- `std/genasts`
- `std/importutils`
- `std/jsbigints`
- `std/jsfetch`
- `std/jsformdata`
- `std/jsheaders`
- `std/packedsets`
- `std/setutils`
- `std/socketstreams`
- `std/strbasics`
- `std/sysrand`
- `std/tasks`
- `std/tempfiles`
- `std/vmutils`
- Deprecated `std/mersenne`.
- Removed deprecated `std/iup` module from stdlib; it has already moved to
[nimble](https://github.com/nim-lang/iup).
## New `std/jsfetch` module
Provides a wrapper for JS Fetch API.
Example:
```nim
# requires -d:nimExperimentalAsyncjsThen
import std/[jsfetch, asyncjs, jsconsole, jsffi, sugar]
proc fn {.async.} =
await fetch("https://api.github.com/users/torvalds".cstring)
.then((response: Response) => response.json())
.then((json: JsObject) => console.log(json))
.catch((err: Error) => console.log("Request Failed", err))
discard fn()
```
## New `std/tasks` module
Provides basic primitives for creating parallel programs.
Example:
```nim
import std/tasks
var num = 0
proc hello(a: int) = num+=a
let b = toTask hello(13) # arguments must be isolated, see `std/isolation`
b.invoke()
assert num == 13
b.invoke() # can be called again
assert num == 26
```
## New module: `std/genasts`
Provides an API `genAst` that avoids the problems inherent with `quote do` and can
be used as a replacement.
Example showing how this could be used for writing a simplified version of `unittest.check`:
```nim
import std/[genasts, macros, strutils]
macro check2(cond: bool): untyped =
assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind
result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]):
# each local symbol we access must be explicitly captured
if not cond:
doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs]
let a = 3
check2 a*2 == a+3
if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4'
```
See PR [#17426](https://github.com/nim-lang/Nim/pull/17426) for details.
## New module: `std/setutils`
- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`,
if the iterable yields a built-in settable type.
- Added `setutils.fullSet` which returns a full built-in `set` for a valid type.
- Added `setutils.complement` which returns the complement of a built-in `set`.
- Added `setutils.[]=`.
## New module: `std/enumutils`
- Added `genEnumCaseStmt` macro that generates
case statement to parse string to enum.
- Added `items` for enums with holes.
- Added `symbolName` to return the `enum` symbol name ignoring the human-readable name.
- Added `symbolRank` to return the index in which an `enum` member is listed in an enum.
## `system`
- Added `system.prepareMutation` for better support of low
level `moveMem`, `copyMem` operations for `gc:orc`'s copy-on-write string
implementation.
- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible
with most other languages.
- Added `cmpMem` to `system`.
- `doAssertRaises` now correctly handles foreign exceptions.
- `addInt` now supports unsigned integers.
Compatibility notes:
- `system.delete` had surprising behavior when the index passed to it was out of
bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so
that an index error is produced instead. Be aware however that your code might depend on
this quirky behavior so a review process is required on your part before you can
use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete`
switch, which pretends that `system.delete` is deprecated so that it is easier
to see where it was used in your code.
`-d:nimStrictDelete` will become the default in upcoming versions.
- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`.
Please use `char` or `uint8` instead.
- `repr` now doesn't insert trailing newlines; the previous behavior was very inconsistent,
see [#16034](https://github.com/nim-lang/Nim/pull/16034).
Use `-d:nimLegacyReprWithNewline` for the previous behavior.
`repr` now also renders ASTs correctly for user defined literals, setters, `do`, etc.
- Deprecated `any`. See RFC [#281](https://github.com/nim-lang/RFCs/issues/281).
- The unary slice `..b` was deprecated, use `0..b` instead.
## `std/math`
- Added `almostEqual` for comparing two float values using a machine epsilon.
- Added `clamp` which allows using a `Slice` to clamp to a value.
- Added `ceilDiv` for integer division that rounds up.
- Added `isNaN`.
- Added `copySign`.
- Added `euclDiv` and `euclMod`.
- Added `signbit`.
- Added `frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead.
Compatibility notes:
- `math.round` now rounds "away from zero" in the JS backend, which is consistent
with other backends. See [#9125](https://github.com/nim-lang/Nim/pull/9125).
Use `-d:nimLegacyJsRound` for the previous behavior.
## Random number generators: `std/random`, `std/sysrand`, `std/oids`
- Added `std/sysrand` module (see details above).
- Added `randState` template that exposes the default random number generator.
Useful for library authors.
- Added `initRand()` overload with no argument which uses the current time as a seed.
- `initRand(seed)` now allows `seed == 0`.
- Fixed overflow bugs.
- Fix `initRand` to avoid random number sequences overlapping, refs
[#18744](https://github.com/nim-lang/Nim/pull/18744).
- `std/oids` now uses `std/random`.
Compatibility notes:
- Deprecated `std/mersenne`.
- `random.initRand(seed)` now produces non-skewed values for the first call to
`rand()` after initialization with a small (< 30000) seed.
Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition
time, see PR [#17467](https://github.com/nim-lang/Nim/pull/17467).
## `std/json`, `std/jsonutils`
- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize
holey enums as regular enums (via `ord`) instead of as strings.
It is expected that this behavior becomes the new default in upcoming versions.
`toJson` now serializes `JsonNode` as is via reference (without a deep copy)
instead of treating `JsonNode` as a regular ref object,
this can be customized via `jsonNodeMode`.
- `std/json` and `std/jsonutils` now serialize `NaN`, `Inf`, `-Inf` as strings,
so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]`
which was invalid JSON.
- `std/json` can now handle integer literals and floating point literals of
arbitrary length and precision.
Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are
kept as string literals and one can use external BigNum libraries to handle these.
The `parseFloat` family of functions also has now optional `rawIntegers` and
`rawFloats` parameters that can be used to enforce that all integer or float
literals remain in the "raw" string form so that client code can easily treat
small and large numbers uniformly.
- Added `BackwardsIndex` overload for `JsonNode`.
- `json.%`,`json.to`, `jsonutils.fromJson`,`jsonutils.toJson` now work with `uint|uint64`
instead of raising (as in 1.4) or giving wrong results (as in 1.2).
- `std/jsonutils` now handles `cstring` (including as Table key), and `set`.
- Added `jsonutils.jsonTo` overload with `opt = Joptions()` param.
- `jsonutils.toJson` now supports customization via `ToJsonOptions`.
- `std/json`, `std/jsonutils` now support round-trip serialization when
`-d:nimPreviewFloatRoundtrip` is used.
## `std/typetraits`, `std/compilesettings`
- `distinctBase` now is identity instead of error for non distinct types.
- `distinctBase` now allows controlling whether to be recursive or not.
- Added `enumLen` to return the number of elements in an enum.
- Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes.
- Added `hasClosure`.
- Added `pointerBase` to return `T` for `ref T | ptr T`.
- Added `compilesettings.SingleValueSetting.libPath`.
## networking: `std/net`, `std/asyncnet`, `std/htmlgen`, `std/httpclient`, `std/asyncdispatch`, `std/asynchttpserver`, `std/httpcore`
- Fixed buffer overflow bugs in `std/net`.
- Exported `sslHandle` from `std/net` and `std/asyncnet`.
- Added `hasDataBuffered` to `std/asyncnet`.
- Various functions in `std/httpclient` now accept `url` of type `Uri`.
Moreover, the `request` function's `httpMethod` argument of type `string` was
deprecated in favor of `HttpMethod` `enum` type; see
[#15919](https://github.com/nim-lang/Nim/pull/15919).
- Added `asyncdispatch.activeDescriptors` that returns the number of currently
active async event handles/file descriptors.
- Added `getPort` to `std/asynchttpserver` to resolve OS-assigned `Port(0)`;
this is usually recommended instead of hardcoding ports which can lead to
"Address already in use" errors.
- Fixed premature garbage collection in `std/asyncdispatch`, when a stacktrace
override is in place.
- Added `httpcore.is1xx` and missing HTTP codes.
- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals).
Compatibility notes:
- On Windows, the SSL library now checks for valid certificates.
For this purpose it uses the `cacert.pem` file, which was extracted
from `https://curl.se/ca/cacert.pem`. Besides
the OpenSSL DLLs (e.g. `libssl-1_1-x64.dll`, `libcrypto-1_1-x64.dll`) you
now also need to ship `cacert.pem` with your `.exe` file.
## `std/hashes`
- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code),
if `-d:nimPreviewHashRef` is used. It is expected that this behavior
becomes the new default in upcoming versions.
- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`.
`hashes.hash(closure)` has also been improved.
## OS: `std/os`, `std/io`, `std/socketstream`, `std/linenoise`, `std/tempfiles`
- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`,
determining preferred I/O block size for this file object.
- Added `os.getCacheDir()` to return platform specific cache directory.
- Improved `os.getTempDir()`, see PR [#16914](https://github.com/nim-lang/Nim/pull/16914).
- Added `os.isAdmin` to tell whether the caller's process is a member of the
Administrators local group (on Windows) or a root (on POSIX).
- Added optional `options` argument to `copyFile`, `copyFileToDir`, and
`copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are
followed (copy files symlinks point to); on Windows, `options` argument is
ignored and symlinks are skipped.
- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as
symlinks (instead of skipping them as it was before); on Windows symlinks are
skipped.
- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks
(instead of skipping them sometimes as it was before).
- Added optional `followSymlinks` argument to `setFilePermissions`.
- Added a simpler to use `io.readChars` overload.
- Added `socketstream` module that wraps sockets in the stream interface.
- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C).
## Environment variable handling
- Empty environment variable values are now supported across OS's and backends.
- Environment variable APIs now work in multithreaded scenarios, by delegating to
direct OS calls instead of trying to keep track of the environment.
- `putEnv`, `delEnv` now work at compile time.
- NodeJS backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`.
Compatibility notes:
- `std/os`: `putEnv` now raises if the first argument contains a `=`.
## POSIX
- On POSIX systems, the default signal handlers used for Nim programs (it's
used for printing the stacktrace on fatal signals) will now re-raise the
signal for the OS default handlers to handle.
This lets the OS perform its default actions, which might include core
dumping (on select signals) and notifying the parent process about the cause
of termination.
- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler`
for previous behavior.
- Added `posix_utils.osReleaseFile` to get system identification from `os-release`
file on Linux and the BSDs.
([link](https://www.freedesktop.org/software/systemd/man/os-release.html))
- Removed undefined behavior for `posix.open`.
## `std/prelude`
- `std/strformat` is now part of `include std/prelude`.
- Added `std/sequtils` import to `std/prelude`.
- `std/prelude` now works with the JS target.
- `std/prelude` can now be used via `include std/prelude`, but `include prelude` still works.
## String manipulation: `std/strformat`, `std/strbasics`
- Added support for parenthesized expressions.
- Added support for const strings instead of just string literals.
- Added `std/strbasics` for high-performance string operations.
- Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`.
## `std/wrapnils`
- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding
issues like bug [#13063](https://github.com/nim-lang/Nim/issues/13063)
(which affected error messages) for modules importing `std/wrapnils`.
- Added `??.` macro which returns an `Option`.
- `std/wrapnils` can now be used to protect against `FieldDefect` errors in
case objects, generates optimal code (no overhead compared to manual
if-else branches), and preserves lvalue semantics which allows modifying
an expression.
## Containers: `std/algorithm`, `std/lists`, `std/sequtils`, `std/options`, `std/packedsets`
- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix`
iterators (it never worked reliably).
- Added `algorithm.merge`.
- In `std/lists`: renamed `append` to `add` and retained `append` as an alias;
added `prepend` and `prependMoved` analogously to `add` and `addMoved`;
added `remove` for `SinglyLinkedList`s.
- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList`
and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes
its argument, `addMoved`, is also supplied.
See PRs [#16362](https://github.com/nim-lang/Nim/pull/16362),
[#16536](https://github.com/nim-lang/Nim/pull/16536).
- New module: `std/packedsets`.
Generalizes `std/intsets`, see PR [#15564](https://github.com/nim-lang/Nim/pull/15564).
Compatibility notes:
- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises
a defect if the slice is out of bounds, likewise with `strutils.delete`.
- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]`
in `std/algorithm`.
- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
## `std/times`
- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time
zone offsets without colons, e.g. `UTC+7 -> +0700`.
- Added `dateTime` and deprecated `initDateTime`.
## `std/macros` and AST
- New module `std/genasts`, see description above.
- The required name of case statement macros for the experimental
`caseStmtMacros` feature has changed from `match` to `` `case` ``.
- Tuple expressions are now parsed consistently as
`nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`.
- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes
in a collapsed way.
Use `-d:nimLegacyMacrosCollapseSymChoice` to get the previous behavior.
- Made custom op in `macros.quote` work for all statements.
## `std/sugar`
- Added `sugar.dumpToString` which improves on `sugar.dump`.
- Added an overload for the `collect` macro that infers the container type based
on the syntax of the last expression. Works with std seqs, tables and sets.
Compatibility notes:
- Removed support for named procs in `sugar.=>`.
## Parsing: `std/parsecfg`, `std/strscans`, `std/uri`
- Added `sections` iterator in `parsecfg`.
- `strscans.scanf` now supports parsing single characters.
- Added `strscans.scanTuple` which uses `strscans.scanf` internally,
returning a tuple which can be unpacked for easier usage of `scanf`.
- Added `decodeQuery` to `std/uri`.
- `parseopt.initOptParser` has been made available and `parseopt` has been
added back to `std/prelude` for all backends. Previously `initOptParser` was
unavailable if the `std/os` module did not have `paramCount` or `paramStr`,
but the use of these in `initOptParser` were conditionally to the runtime
arguments passed to it, so `initOptParser` has been changed to raise
`ValueError` when the real command line is not available. `parseopt` was
previously excluded from `std/prelude` for JS, as it could not be imported.
Compatibility notes:
- Changed the behavior of `uri.decodeQuery` when there are unencoded `=`
characters in the decoded values. Prior versions would raise an error. This is
no longer the case to comply with the HTML spec and other languages'
implementations. Old behavior can be obtained with
`-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same
underlying code is also updated the same way.
## JS stdlib changes
- Added `std/jsbigints` module, which provides arbitrary precision integers for the JS target.
- Added `setCurrentException` for the JS backend.
- `writeStackTrace` is available in the JS backend now.
- Added `then`, `catch` to `std/asyncjs` for promise pipelining, for now hidden
behind `-d:nimExperimentalAsyncjsThen`.
- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API)
wrapper for the JS target.
- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
wrapper for the JS target.
- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
wrapper for the JS target.
- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger).
- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`.
- Added dollar `$` and `len` for `jsre.RegExp`.
- Added `jsconsole.jsAssert` for the JS target.
- Added `**` to `std/jsffi`.
- Added `copyWithin` [for `seq` and `array` for JS targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin).
- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`.
Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated.
- Added `dom.scrollIntoView` proc with options.
- Added `dom.setInterval`, `dom.clearInterval` overloads.
- Merged `std/dom_extensions` into the `std/dom` module,
as it was a module with a single line, see RFC [#413](https://github.com/nim-lang/RFCs/issues/413).
- `$` now gives more correct results on the JS backend.
## JS compiler changes
- `cstring` doesn't support the `[]=` operator anymore in the JS backend.
- Array literals now use JS typed arrays when the corresponding JS typed array exists,
for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`.
## VM and nimscript backend
- VM now supports `addr(mystring[ind])` (index + index assignment).
- `nimscript` now handles `except Exception as e`.
- `nil` dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time.
- `static[T]` now works better, refs [#17590](https://github.com/nim-lang/Nim/pull/17590),
[#15853](https://github.com/nim-lang/Nim/pull/15853).
- `distinct T` conversions now work in VM.
- `items(cstring)` now works in VM.
- Fix `addr`, `len`, `high` in VM ([#16002](https://github.com/nim-lang/Nim/pull/16002),
[#16610](https://github.com/nim-lang/Nim/pull/16610)).
- `std/cstrutils` now works in VM.
## OS/platform-specific notes
- Support for Apple silicon/M1.
- Support for 32-bit RISC-V, refs [#16231](https://github.com/nim-lang/Nim/pull/16231).
- Support for armv8l, refs [#18901](https://github.com/nim-lang/Nim/pull/18901).
- Support for CROSSOS, refs [#18889](https://github.com/nim-lang/Nim/pull/18889).
- The allocator for Nintendo Switch, which was nonfunctional because
of breaking changes in libnx, was removed, in favor of the new `-d:nimAllocPagesViaMalloc` option.
- Allow reading parameters when compiling for Nintendo Switch.
- `--nimcache` now correctly works in a cross-compilation setting.
- Cross compilation targeting Windows was improved.
- This now works from macOS/Linux: `nim r -d:mingw main`
## Performance / memory optimizations
- The comment field in PNode AST was moved to a side channel, reducing overall
memory usage during compilation by a factor 1.25x
- `std/jsonutils` deserialization is now up to 20x faster.
- `os.copyFile` is now 2.5x faster on macOS, by using `copyfile` from `copyfile.h`;
use `-d:nimLegacyCopyFile` for macOS < 10.5.
- Float to string conversion is now 10x faster thanks to the Dragonbox algorithm,
with `-d:nimPreviewFloatRoundtrip`.
- `newSeqWith` is 3x faster.
- CI now supports batching (making Windows CI 2.3X faster).
- Sets now uses the optimized `countSetBits` proc, see PR
[#17334](https://github.com/nim-lang/Nim/pull/17334).
## Debugging
- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`.
- `koch tools` now builds `bin/nim_dbg` which allows easy access to a debug version
of Nim without recompiling.
- Added new module `compiler/debugutils` to help with debugging Nim compiler.
- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints` and
used it in more contexts; this flag which works in tandem with `--stackTraceMsgs`
to show user code context in compiler stacktraces.
## Type system
- `typeof(voidStmt)` now works and returns `void`.
- `enum` values can now be overloaded. This needs to be enabled
via `{.experimental: "overloadableEnums".}`. We hope that this feature allows
for the development of more fluent (less ugly) APIs.
See RFC [#373](https://github.com/nim-lang/RFCs/issues/373) for more details.
- A type conversion from one `enum` type to another now produces an `[EnumConv]` warning.
You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead.
```nim
type A = enum a1, a2
type B = enum b1, b2
echo a1.B # produces a warning
echo a1.ord.B # produces no warning
```
- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning.
This warning will become an error in future versions! Use an explicit conversion
like `cstring(x)` in order to silence the warning.
- There is a new warning for *any* type conversion to `enum` that can be enabled via
`.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`.
- Reusing a type name in a different scope now works, refs [#17710](https://github.com/nim-lang/Nim/pull/17710).
- Fixed implicit and explicit generics in procedures, refs [#18808](https://github.com/nim-lang/Nim/pull/18808).
## New-style concepts
Example:
```nim
type
Comparable = concept # no T, an atom
proc cmp(a, b: Self): int
```
The new design does not rely on `system.compiles` and may compile faster.
See PR [#15251](https://github.com/nim-lang/Nim/pull/15251)
and RFC [#168](https://github.com/nim-lang/RFCs/issues/168) for details.
## Lexical / syntactic
- Nim now supports a small subset of Unicode operators as operator symbols.
The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ⊔".
To enable this feature, use `--experimental:unicodeOperators`. Note that due
to parser limitations you **cannot** enable this feature via a
pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable
it via the command line or in a configuration file.
- `var a {.foo.} = expr` now works inside templates (except when `foo` is overloaded).
## Compiler messages, error messages, hints, warnings
- Significant improvement to error messages involving effect mismatches,
see PRs [#18384](https://github.com/nim-lang/Nim/pull/18384),
[#18418](https://github.com/nim-lang/Nim/pull/18418).
- Added `--declaredLocs` to show symbol declaration location in error messages.
- Added `--spellSuggest` to show spelling suggestions on typos.
- Added `--processing:dots|filenames|off` which customizes `hintProcessing`;
`--processing:filenames` shows which include/import modules are being compiled as an import stack.
- `FieldDefect` messages now shows discriminant value + lineinfo, in all backends (C, JS, VM)
- Added `--hintAsError` with similar semantics as `--warningAsError`.
- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31`
before a newline for every generated message (potentially multiline),
so tooling can tell when messages start and end.
- Added `--filenames:abs|canonical|legacyRelProj` which replaces `--listFullPaths:on|off`
- `--hint:all:on|off` is now supported to select or deselect all hints; it
differs from `--hints:on|off` which acts as a (reversible) gate.
Likewise with `--warning:all:on|off`.
- The style checking of the compiler now supports a `--styleCheck:usages` switch.
This switch enforces that every symbol is written as it was declared, not enforcing
the official Nim style guide. To be enabled, this has to be combined either
with `--styleCheck:error` or `--styleCheck:hint`.
- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for
previous behavior.
- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages.
- `runnableExamples` now show originating location in stacktraces on failure.
- `SuccessX` message now shows more useful information.
- New `DuplicateModuleImport` warning; improved `UnusedImport` and
`XDeclaredButNotUsed` accuracy.
Compatibility notes:
- `--hint:CC` now prints to stderr (like all other hints) instead of stdout.
## Building and running Nim programs, configuration system
- JSON build instructions are now generated in `$nimcache/outFileBasename.json`
instead of `$nimcache/projectName.json`. This allows avoiding recompiling a
given project compiled with different options if the output file differs.
- `--usenimcache` (implied by `nim r main`) now generates an output file that includes
a hash of some of the compilation options, which allows caching generated binaries:
```bash
nim r main # recompiles
nim r -d:foo main # recompiles
nim r main # uses cached binary
nim r main arg1 arg2 # likewise (runtime arguments are irrelevant)
```
- `nim r` now supports cross compilation from unix to windows when specifying
`-d:mingw` by using Wine, e.g.:
`nim r --eval:'import os; echo "a" / "b"'` prints `a\b`.
- `nim` can compile version 1.4.0 as follows:
`nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`.
`-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel.
- `nim e` now accepts arbitrary file extensions for the nimscript file,
although `.nims` is still the preferred extension in general.
- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected.
The downside is that these defines now have custom logic that doesn't apply for
other defines.
## Multithreading
- TLS: macOS now uses native TLS (`--tlsEmulation:off`). TLS now works with
`importcpp` non-POD types; such types must use `.cppNonPod` and
`--tlsEmulation:off`should be used.
- Added `unsafeIsolate` and `extract` to `std/isolation`.
- Added `std/tasks`, see description above.
## Memory management
- `--gc:arc` now bootstraps (PR [#17342](https://github.com/nim-lang/Nim/pull/17342)).
- Lots of improvements to `gc:arc`, `gc:orc`, see PR
[#15697](https://github.com/nim-lang/Nim/pull/15697),
[#16849](https://github.com/nim-lang/Nim/pull/16849),
[#17993](https://github.com/nim-lang/Nim/pull/17993).
- `--gc:orc` is now 10% faster than previously for common workloads.
If you have trouble with its changed behavior, compile with `-d:nimOldOrc`.
- The `--gc:orc` algorithm was refined so that custom container types can participate in the
cycle collection process. See the documentation of `=trace` for more details.
- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`.
This is only supported for `--gc:orc` or `--gc:arc`.
Compatibility notes:
- `--newruntime` and `--refchecks` are deprecated,
use `--gc:arc`, `--gc:orc`, or `--gc:none` as appropriate instead.
## Docgen
- docgen: RST files can now use single backticks instead of double backticks and
correctly render in both `nim rst2html` (as before) as well as common tools rendering
RST directly (e.g. GitHub).
This is done by adding the `default-role:: code` directive inside the RST file
(which is now handled by `nim rst2html`).
- Source+Edit links now appear on top of every docgen'd page when
`nim doc --git.url:url ...` is given.
- Latex doc generation is revised: output `.tex` files should be compiled
by `xelatex` (not by `pdflatex` as before). Now default Latex settings
provide support for Unicode and better avoid margin overflows.
The minimum required version is TeXLive 2018 (or an equivalent MikTeX version).
- The RST parser now supports footnotes, citations, admonitions, and short style
references with symbols.
- The RST parser now supports Markdown table syntax.
Known limitations:
- cell alignment is not supported, i.e. alignment annotations in a delimiter
row (`:---`, `:--:`, `---:`) are ignored
- every table row must start with `|`, e.g. `| cell 1 | cell 2 |`.
- Implemented `doc2tex` compiler command which converts documentation in
`.nim` files to Latex.
- docgen now supports syntax highlighting for inline code.
- docgen now supports same-line doc comments:
```nim
func fn*(a: int): int = 42 ## Doc comment
```
- docgen now renders `deprecated` and other pragmas.
- `runnableExamples` now works with templates and nested templates.
- `runnableExamples: "-r:off"` now works for examples that should compile but not run.
- `runnableExamples` now renders code verbatim, and produces correct code in all cases.
- docgen now shows correct, canonical import paths in docs.
- docgen now shows all routines in sidebar, and the proc signature is now shown in sidebar.
## Effects and checks
- Significant improvement to error messages involving effect mismatches
- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some
compiler checks regarding `case objects`. This allows serialization libraries
to avoid ugly, non-portable solutions. See RFC
[#407](https://github.com/nim-lang/RFCs/issues/407) for more details.
Compatibility notes:
- Fixed effect tracking for borrowed procs (see [#18882](https://github.com/nim-lang/Nim/pull/18882)).
One consequence is that, under some circumstances, Nim could previously permit a procedure with side effects to be written with `func` - you may need to change some occurrences of `func` to `proc`.
To illustrate, Nim versions before 1.6.0 compile the below without error
```nim
proc print(s: string) =
echo s
type
MyString = distinct string
proc print(s: MyString) {.borrow.}
func foo(s: MyString) =
print(s)
```
but Nim 1.6.0 produces the error
```
Error: 'foo' can have side effects
```
similar to how we expect that
```nim
func print(s: string) =
echo s
```
produces
```
Error: 'print' can have side effects
```
## Tools
- Major improvements to `nimgrep`, see PR [#15612
](https://github.com/nim-lang/Nim/pull/15612).
- `fusion` is now un-bundled from Nim, `./koch fusion` will
install it via Nimble at a fixed hash.
- `testament`: added `nimoutFull: bool` spec to compare full output of compiler
instead of a subset; many bugfixes to testament.
## Misc/cleanups
- Deprecated `TaintedString` and `--taintmode`.
- Deprecated `--nilseqs` which is now a noop.
- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have
certain hints/warnings.
- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`.
- `[skip ci]` now works in azure and CI pipelines, see detail in PR
[#17561](https://github.com/nim-lang/Nim/pull/17561).

View File

@@ -1,330 +0,0 @@
# v2.0.0 - 2023-08-01
Version 2.0 is a big milestone with too many changes to list them all here.
For a full list see [details](changelog_2_0_0_details.html).
## New features
### Better tuple unpacking
Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
# Now nesting is supported!
let (x, (_, y), _, z) = returnsNestedTuple()
```
### Improved type inference
A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) has been implemented for a variety of basic cases.
For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
### Forbidden Tags
[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition
of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types.
For example:
```nim
type IO = object ## input/output effect
proc readLine(): string {.tags: [IO].} = discard
proc echoLine(): void = discard
proc no_IO_please() {.forbids: [IO].} =
# this is OK because it didn't define any tag:
echoLine()
# the compiler prevents this:
let y = readLine()
```
### New standard library modules
The famous `os` module got an overhaul. Several of its features are available
under a new interface that introduces a `Path` abstraction. A `Path` is
a `distinct string`, which improves the type safety when dealing with paths, files
and directories.
Use:
- `std/oserrors` for OS error reporting.
- `std/envvars` for environment variables handling.
- `std/paths` for path handling.
- `std/dirs` for directory creation/deletion/traversal.
- `std/files` for file existence checking, file deletions and moves.
- `std/symlinks` for symlink handling.
- `std/appdirs` for accessing configuration/home/temp directories.
- `std/cmdline` for reading command line parameters.
### Consistent underscore handling
The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
### JavaScript codegen improvement
The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
## Docgen improvements
`Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
* Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
* Added support for RST & Markdown quote blocks (blocks starting with `>`).
* Added a popular Markdown definition lists extension.
* Added Markdown indented code blocks (blocks indented by >= 4 spaces).
* Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## C++ interop enhancements
Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize
the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types.
It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces.
Consider the following example:
```cpp
struct Base {
int someValue;
Base(int inValue) {
someValue = inValue;
};
};
class IPrinter {
public:
virtual void print() = 0;
};
```
```nim
type
Base* {.importcpp, inheritable.} = object
someValue*: int32
IPrinter* {.importcpp.} = object
const objTemplate = """
struct $1 : public $3, public IPrinter {
$2
};
""";
type NimChild {.codegenDecl: objTemplate .} = object of Base
proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} =
echo "It calls the base constructor passing " & $this.someValue
this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`.
proc print*(self: NimChild) {.virtual.} =
echo "Some value is " & $self.someValue
let child = makeNimChild(10)
child.print()
```
It outputs:
```
It calls the base constructor passing 10
Some value is 20
```
## ARC/ORC refinements
With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete:
1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable.
2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations.
3. Destructors now take a parameter of the attached object type `T` directly and don't have to take a `var T` parameter.
With these important optimizations we improved the runtime of the compiler and important benchmarks by 0%! Wait ... what?
Yes, unfortunately it turns out that for a modern optimizer like in GCC or LLVM there is no difference.
But! This refined model is more efficient once separate compilation enters the picture. In other words, as we think of
providing a stable ABI it is important not to lose any efficiency in the calling conventions.
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep now offers the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also, the semantics are now consistent for such positive/negative filters.
- Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions.
## Porting guide
### Block and Break
Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. In other words, turn:
```nim
block:
a()
if cond:
break
b()
```
Into:
```nim
block maybePerformB:
a()
if cond:
break maybePerformB
b()
```
### Strict funcs
The definition of `"strictFuncs"` was changed.
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
The new definition is: "A store to a ref/ptr deref is forbidden."
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
accepted:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node()
result.s = s # store to result[]
```
Now it has to be rewritten to:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node(s: s)
```
### Standard library
Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `sums`

View File

@@ -1,560 +0,0 @@
# v2.0.0 - 2023-08-01
## Changes affecting backward compatibility
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- The `threads:on` option is now the default.
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `ValueError`.
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- Certain definitions from the default `system` module have been moved to
the following new modules:
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
In the future, these definitions will be removed from the `system` module,
and their respective modules will have to be imported to use them.
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
may be used.
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
symbols in the `system` module:
- Aliases with an `Error` suffix to exception types that have a `Defect` suffix
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
`DeadThreadError`, `NilAccessError`
- `addQuitProc`, replaced by `exitprocs.addExitProc`
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
- `TaintedString`, formerly a distinct alias to `string`
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`.
- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore.
- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to
`pointer` anymore. `cast` may be used instead.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/405))
are now opt-in via `experimental:flexibleOptionalParams`.
- Automatic dereferencing (experimental feature) is removed.
- The `Math.trunc` polyfill for targeting Internet Explorer was
previously included in most JavaScript output files.
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
If you are targeting Internet Explorer, you may choose to enable this option
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
Nim uses `Math.trunc` for the division and modulo operators for integers.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fulfill its promises.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
```nim
type Foo = distinct ptr int
# Before:
var x: Foo = nil
# After:
var x: Foo = Foo(nil)
```
- Removed two type pragma syntaxes deprecated since 0.20, namely
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. Instead,
use `type Foo[T] {.final.} = object`.
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
This decision was made with the assumption that the old syntax was used rarely;
if your code used the old syntax, please be aware of this change.
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
are no longer experimental.
- `macros.getImpl` for `const` symbols now returns the full definition node
(as `nnkConstDef`) rather than the AST of the constant value.
- Lock levels are deprecated, now a noop.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour, use `-d:nimLegacyGorgeErrors`.
- Pointer to `cstring` conversions now trigger a `[PtrToCstringConv]` warning.
This warning will become an error in future versions! Use a `cast` operation
like `cast[cstring](x)` instead.
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
- Redefining templates with the same signature was previously
allowed to support certain macro code. To do this explicitly, the
`{.redefine.}` pragma has been added. Note that this is only for templates.
Implicit redefinition of templates is now deprecated and will give an error in the future.
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
- Several Standard libraries have been moved to nimble packages, use `nimble` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `std/sums`
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning:
```nim
try:
discard
except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept]
discard
```
- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection.
- The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
- The `proc` and `iterator` type classes now respectively only match
procs and iterators. Previously both type classes matched any of
procs or iterators.
```nim
proc prc(): int =
123
iterator iter(): int {.closure.} =
yield 123
proc takesProc[T: proc](x: T) = discard
proc takesIter[T: iterator](x: T) = discard
# always compiled:
takesProc(prc)
takesIter(iter)
# no longer compiles:
takesProc(iter)
takesIter(prc)
```
- The `proc` and `iterator` type classes now accept a calling convention pragma
(i.e. `proc {.closure.}`) that must be shared by matching proc or iterator
types. Previously, pragmas were parsed but discarded if no parameter list
was given.
This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with
an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma
node in the same place as in a concrete `proc` or `iterator` type node. This
state of the AST may be unexpected to existing code, both due to the
replacement of the `nnkFormalParams` node as well as having child nodes
unlike other type class AST.
- Signed integer literals in `set` literals now default to a range type of
`0..255` instead of `0..65535` (the maximum size of sets).
- `case` statements with `else` branches put before `elif`/`of` branches in macros
are rejected with "invalid order of case branches".
- Destructors now default to `.raises: []` (i.e. destructors must not raise
unlisted exceptions) and explicitly raising destructors are implementation
defined behavior.
- The very old, undocumented `deprecated` pragma statement syntax for
deprecated aliases is now a no-op. The regular deprecated pragma syntax is
generally sufficient instead.
```nim
# now does nothing:
{.deprecated: [OldName: NewName].}
# instead use:
type OldName* {.deprecated: "use NewName instead".} = NewName
const oldName* {.deprecated: "use newName instead".} = newName
```
`defined(nimalias)` can be used to check for versions when this syntax was
available; however since code that used this syntax is usually very old,
these deprecated aliases are likely not used anymore and it may make sense
to simply remove these statements.
- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer
declared when they are not available on the backend. Previously it would call
`doAssert false` at runtime despite the condition being checkable at compile-time.
- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated.
- Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly.
## Standard library additions and changes
[//]: # "Changes:"
- OpenSSL 3 is now supported.
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
`filename` argument for more informative errors.
- The `colors` module is expanded with missing colors from the CSS color standard.
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
- The `md5` module now works at compile time and in JavaScript.
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef`, to support `const` tables.
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator.
- `random.rand` now works with `Ordinal`s.
- Undeprecated `os.isvalidfilename`.
- `std/oids` now uses `int64` to store time internally (before, it was int32).
- `std/uri.Uri` dollar (`$`) improved, precalculates the `string` result length from the `Uri`.
- `std/uri.Uri.isIpv6` is now exported.
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
- `std/jsfetch.newFetchOptions` now has default values for all parameters.
- `std/jsformdata` now accepts the `Blob` data type.
- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433).
- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the Linux `getrandom` syscall.
This compile flag only affects Linux builds and is necessary if either compiling on a Linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On Linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since Linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (`sysrand` in particular).
[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
- Added an `initDateTime` overload to create a `DateTime` from an ISO week date.
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
- Added new modules which were previously part of `std/os`:
- Added `std/oserrors` for OS error reporting.
- Added `std/envvars` for environment variables handling.
- Added `std/cmdline` for reading command line parameters.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `sep` parameter in `std/uri` to specify the query separator.
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
- Added `complex.sgn` for obtaining the phase of complex numbers.
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
`toggleAttribute`, and `matches` to `std/dom`.
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices).
- Added `capacity` for `string` and `seq` to return the current capacity, see [RFC #460](https://github.com/nim-lang/RFCs/issues/460).
- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse.
- Added a `safe` parameter to `base64.encodeMime`.
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences.
- `std/jscore` for the JavaScript target:
+ Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask).
+ Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`.
- Added `BackwardsIndex` overload for `CacheSeq`.
- Added support for nested `with` blocks in `std/with`.
- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
Now only `byte` and `char` are supported.
[//]: # "Removals:"
- Removed deprecated module `parseopt2`.
- Removed deprecated module `sharedstrings`.
- Removed deprecated module `dom_extensions`.
- Removed deprecated module `LockFreeHash`.
- Removed deprecated module `events`.
- Removed deprecated `oids.oidToString`.
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
- Removed deprecated `jsre.test` and `jsre.toString`.
- Removed deprecated `math.c_frexp`.
- Removed deprecated `` httpcore.`==` ``.
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that take wrong argument types.
- Removed deprecated `osproc.poDemon`, symbol with typo.
- Removed deprecated `tables.rightSize`.
- Removed deprecated `posix.CLONE_STOPPED`.
## Language changes
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma
which can be used to disable certain effects in proc types.
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
for the right-hand side of type definitions in type sections. Previously
they would error with "invalid indentation".
- Compile-time define changes:
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
In the command line, this is defined as `-d:a.b.c`. Older versions can
use backticks as in ``defined(`a.b.c`)`` to access such defines.
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
now support a string argument for qualified define names.
```nim
# -d:package.FooBar=42
const FooBar {.intdefine: "package.FooBar".}: int = 5
echo FooBar # 42
```
This was added to help disambiguate similar define names for different packages.
In older versions, this could only be achieved with something like the following:
```nim
const FooBar = block:
const `package.FooBar` {.intdefine.}: int = 5
`package.FooBar`
```
- A generic `define` pragma for constants has been added that interprets
the value of the define based on the type of the constant value.
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-nimdefine-pragma)
for a list of supported types.
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
- Templates now accept macro pragmas.
- Macro pragmas for var/let/const sections have been redesigned in a way that works
similarly to routine macro pragmas. The new behavior is documented in the
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
has been implemented for a variety of basic cases. For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- `cstring` is now accepted as a selector in `case` statements, removing the
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
- IBM Z architecture and macOS m1 arm64 architecture are supported.
- `=wasMoved` can now be overridden by users.
- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code
generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care.
- Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
let (x, (_, y), _, z) = returnsNestedTuple()
# roughly becomes
let
tmpTup1 = returnsNestedTuple()
x = tmpTup1[0]
tmpTup2 = tmpTup1[1]
y = tmpTup2[1]
z = tmpTup1[3]
```
As a result `nnkVarTuple` nodes in variable sections will no longer be
reflected in `typed` AST.
- C++ interoperability:
- New [`virtual`](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma added.
- Improvements to [`constructor`](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
without requiring `-d:nimVersion140` which is now a noop.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
related functions produced on the backend. This prevents conflicts with other Nim
static libraries.
- When compiling for release, the flag `-fno-math-errno` is used for GCC.
- Removed deprecated `LineTooLong` hint.
- Line numbers and file names of source files work correctly inside templates for JavaScript targets.
- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers.
## Docgen
- `Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
- Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
- Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
- Added support for RST & Markdown quote blocks (blocks starting with `>`).
- Added a popular Markdown definition lists extension.
- Added Markdown indented code blocks (blocks indented by >= 4 spaces).
- Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep added the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also the semantics are now consistent for such positive/negative filters.
- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice.

View File

@@ -1,248 +0,0 @@
# v2.2.0 - 2024-10-02
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` is out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backward compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from the `system` module, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- The JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- The JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
Previously; in templates they would error immediately at the template definition,
and in generic procs a type symbol would arbitrarily be captured, losing the
information of the other symbols. This means that generic code can now give
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
- Partial generic instantiation of routines is no longer allowed. Previously
it compiled in niche situations due to bugs in the compiler.
```nim
proc foo[T, U](x: T, y: U) = echo (x, y)
proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
proc bar[T]() =
foo[float](1, "abc")
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
- The following POSIX wrappers have had their types changed from signed to
unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
- `Gid` (was `int32`, is now `uint32`)
- `Uid` (was `int32`, is now `uint32`)
- `Dev` (was `int32`, is now `uint32` on FreeBSD)
- `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
- `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
(were `int32`, are now `uint32`)
- `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
- The `Atomic[T]` type on C++ now uses C11 primitives by default instead of
`std::atomic`. To use `std::atomic` instead, `-d:nimUseCppAtomics` can be defined.
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
- Changed `std/os.copyDir` and `copyDirWithPermissions` to allow skipping special "file" objects like FIFOs, device files, etc on Unix by specifying a `skipSpecial` parameter.
[//]: # "Additions:"
- Added `newStringUninit` to the `system` module, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to the `system` module, which doesn't initialize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
convert a value with a range type to its base type.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
on Google's Farm Hash) which is also often faster than the present one. Define
`nimStringHash2` to get the old values back. `--jsbigint=off` mode always only
produces the old values. This may impact your automated tests if they depend
on hash order in some obvious or indirect way. Using `sorted` or `OrderedTable`
is often an easy workaround.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- Inside a C++ constructor, `result` can be used to access the created object rather than `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package.

View File

@@ -1,23 +1,27 @@
# v2.xx.x - yyyy-mm-dd
## v0.XX.0 - XX/XX/2018
This is an example file.
The changes should go to changelog.md!
### Changes affecting backwards compatibility
## Changes affecting backward compatibility
- Example item: ``Foo`` changed to ``Bar``.
- `foo` now behaves differently, use `-d:nimLegacyFoo` for previous behavior.
## Standard library additions and changes
- Added `example.exampleProc`.
- Changed `example.foo` to take additional `bar` parameter.
## Language changes
#### Breaking changes in the standard library
## Compiler changes
#### Breaking changes in the compiler
### Library additions
### Library changes
## Tool changes
### Language additions
### Language changes
### Tool changes
### Compiler changes
### Bugfixes

View File

@@ -1,26 +0,0 @@
import std/[strutils, os, osproc, parseutils, strformat]
proc main() =
var msg = ""
const cmd = "./koch boot --mm:orc -d:release"
let (output, exitCode) = execCmdEx(cmd)
doAssert exitCode == 0, output
let start = rfind(output, "Hint: mm")
doAssert parseUntil(output, msg, "; proj", start) > 0, output
let (commitHash, _) = execCmdEx("""git log --format="%H" -n 1""")
let welcomeMessage = fmt"""Thanks for your hard work on this PR!
The lines below are statistics of the Nim compiler built from {commitHash}
{msg}
"""
createDir "ci/nimcache"
writeFile "ci/nimcache/results.txt", welcomeMessage
when isMainModule:
main()

14
ci/build.bat Normal file
View File

@@ -0,0 +1,14 @@
REM Some debug info
echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%."
gcc -v
git clone --depth 1 https://github.com/nim-lang/csources.git
cd csources
call build64.bat
cd ..
set PATH=%CD%\bin;%PATH%
nim -v
nim c koch
koch.exe boot
copy bin/nim bin/nimd
koch.exe boot -d:release

15
ci/build.sh Normal file
View File

@@ -0,0 +1,15 @@
sh ci/deps.sh
# Build from C sources.
git clone --depth 1 https://github.com/nim-lang/csources.git
cd csources
sh build.sh
cd ..
# Add Nim to the PATH
export PATH=$(pwd)/bin${PATH:+:$PATH}
# Bootstrap.
nim -v
nim c koch
./koch boot
cp bin/nim bin/nimd
./koch boot -d:release

View File

@@ -1,26 +0,0 @@
@echo off
rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim`
rem Build development version of the compiler; can be rerun safely
rem bare bones version of ci/funs.sh adapted for windows.
rem Read in some common shared variables (shared with other tools),
rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file
for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H
SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe
echo "building from csources: %nim_csources%"
if not exist %nim_csourcesDir% (
git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir%
)
if not exist %nim_csources% (
cd %nim_csourcesDir%
git checkout %nim_csourcesHash%
echo "%PROCESSOR_ARCHITECTURE%"
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" (
SET ARCH=64
)
CALL build.bat
cd ..
copy /y bin\nim.exe %nim_csources%
)

4
ci/deps.bat Normal file
View File

@@ -0,0 +1,4 @@
nim e install_nimble.nims
nim e tests/test_nimscript.nims
nimble update
nimble install -y zip opengl sdl1 jester@#head niminst

16
ci/deps.sh Normal file
View File

@@ -0,0 +1,16 @@
# Some debug info
echo "Running on $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) with tags $CI_RUNNER_TAGS."
# Packages
apt-get update -qq
apt-get install -y -qq build-essential git libcurl4-openssl-dev libsdl1.2-dev libgc-dev nodejs
gcc -v
export PATH=$(pwd)/bin${PATH:+:$PATH}
# Nimble deps
nim e install_nimble.nims
nim e tests/test_nimscript.nims
nimble update
nimble install zip opengl sdl1 jester@#head niminst

View File

@@ -1,147 +0,0 @@
# Utilities used in CI pipelines and tooling to avoid duplication.
# Avoid top-level statements.
# Prefer nim scripts whenever possible.
# functions starting with `_` are considered internal, less stable.
echo_run () {
# echo's a command before running it, which helps understanding logs
echo ""
echo "cmd: $@" # in azure we could also use this: echo '##[section]"$@"'
"$@"
}
nimGetLastCommit() {
git log --no-merges -1 --pretty=format:"%s"
}
nimIsCiSkip(){
# D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944
# `--no-merges` is needed to avoid merge commits which occur for PR's.
# $(Build.SourceVersionMessage) is not helpful
# nor is `github.event.head_commit.message` for github actions.
# Note: `[skip ci]` is now handled automatically for github actions, see https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/
commitMsg=$(nimGetLastCommit)
echo commitMsg: "$commitMsg"
if [[ $commitMsg == *"[skip ci]"* ]]; then
echo "skipci: true"
return 0
else
echo "skipci: false"
return 1
fi
}
nimInternalInstallDepsWindows(){
echo_run mkdir dist
echo_run curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z
echo_run curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
echo_run 7z x dist/mingw64.7z -odist
echo_run 7z x dist/dlls.zip -obin
}
nimInternalBuildKochAndRunCI(){
echo_run nim c koch
if ! echo_run ./koch runCI; then
echo_run echo "runCI failed"
echo_run nim r tools/ci_testresults.nim
return 1
fi
}
nimDefineVars(){
. config/build_config.txt
nim_csources=bin/nim_csources_$nim_csourcesHash
}
_nimNumCpu(){
# linux: $(nproc)
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
# OpenBSD: $(sysctl -n hw.ncpuonline)
# windows: $NUMBER_OF_PROCESSORS ?
if env | grep -q '^NIMCORES='; then
echo $NIMCORES
else
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
fi
}
_nimBuildCsourcesIfNeeded(){
# if some systems cannot use make or gmake, we could add support for calling `build.sh`
# but this is slower (not parallel jobs) and would require making build.sh
# understand the arguments passed to the makefile (e.g. `CC=gcc ucpu=amd64 uos=darwin`),
# instead of `--cpu amd64 --os darwin`.
unamestr=$(uname)
# uname values: https://en.wikipedia.org/wiki/Uname
if [ "$unamestr" = 'FreeBSD' ]; then
makeX=gmake
elif [ "$unamestr" = 'OpenBSD' ]; then
makeX=gmake
elif [ "$unamestr" = 'NetBSD' ]; then
makeX=gmake
elif [ "$unamestr" = 'CROSSOS' ]; then
makeX=gmake
elif [ "$unamestr" = 'SunOS' ]; then
makeX=gmake
else
makeX=make
fi
nCPU=$(_nimNumCpu)
echo_run which $makeX
# parallel jobs (5X faster on 16 cores: 10s instead of 50s)
echo_run $makeX -C $nim_csourcesDir -j $((nCPU + 2)) -l $nCPU "$@"
# keep $nim_csources in case needed to investigate bootstrap issues
# without having to rebuild
echo_run cp bin/nim $nim_csources
}
nimCiSystemInfo(){
nimDefineVars
echo_run eval echo '$'nim_csources
echo_run pwd
echo_run date
echo_run uname -a
echo_run git log --no-merges -1 --pretty=oneline
echo_run eval echo '$'PATH
echo_run gcc -v
echo_run node -v
echo_run make -v
}
nimCsourcesHash(){
nimDefineVars
echo $nim_csourcesHash
}
nimBuildCsourcesIfNeeded(){
# goal: allow cachine each tagged version independently
# to avoid rebuilding, so that tools like `git bisect`
# can grab a cached past version without rebuilding.
nimDefineVars
(
set -e
# avoid polluting caller scope with internal variable definitions.
if test -f "$nim_csources"; then
echo "$nim_csources exists."
else
if test -d "$nim_csourcesDir"; then
echo "$nim_csourcesDir exists."
else
# Note: using git tags would allow fetching just what's needed, unlike git hashes, e.g.
# via `git clone -q --depth 1 --branch $tag $nim_csourcesUrl`.
echo_run git clone -q --depth 1 -b $nim_csourcesBranch \
$nim_csourcesUrl "$nim_csourcesDir"
# old `git` versions don't support -C option, using `cd` explicitly:
echo_run cd "$nim_csourcesDir"
echo_run git checkout $nim_csourcesHash
echo_run cd "$OLDPWD"
# if needed we could also add: `git reset --hard $nim_csourcesHash`
fi
_nimBuildCsourcesIfNeeded "$@"
fi
echo_run rm -f bin/nim
# fixes bug #17913, but it's unclear why it's needed, maybe specific to MacOS Big Sur 11.3 on M1 arch?
echo_run cp $nim_csources bin/nim
echo_run $nim_csources -v
)
}

59
ci/nsis_build.bat Normal file
View File

@@ -0,0 +1,59 @@
REM - Run the full testsuite; testament\tester all
REM - Uncomment the list of changes in news.txt
REM - write a news ticker entry
REM - Update the version
REM - Generate the full docs; koch web0
REM - Generate the installers;
REM - Update the version in system.nim
REM - Test the installers
REM - Tag the release
REM - Merge devel into master
REM - Update csources
set NIMVER=%1
Rem Build -docs file:
koch web0
cd web\upload
7z a -tzip docs-%NIMVER%.zip *.html
move /y docs-%NIMVER%.zip download
cd ..\..
Rem Build csources
koch csources -d:release || exit /b
rem Grab C sources and nimsuggest
git clone --depth 1 https://github.com/nim-lang/csources.git
set PATH=%CD%\bin;%PATH%
ReM Build Win32 version:
set PATH=C:\Users\araq\projects\mingw32\bin;%PATH%
cd csources
call build.bat
cd ..
ReM Rebuilding koch is necessary because it uses its pointer size to determine
ReM which mingw link to put in the NSIS installer.
nim c --out:koch_temp koch || exit /b
koch_temp boot -d:release || exit /b
koch_temp nsis -d:release || exit /b
koch_temp zip -d:release || exit /b
dir build
move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x32.exe || exit /b
move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x32.zip || exit /b
ReM Build Win64 version:
set PATH=C:\Users\araq\projects\mingw64\bin;%PATH%
cd csources
call build64.bat
cd ..
nim c --out:koch_temp koch || exit /b
koch_temp boot -d:release || exit /b
koch_temp nsis -d:release || exit /b
koch_temp zip -d:release || exit /b
move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x64.exe || exit /b
move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x64.zip || exit /b

9
compiler.nimble Normal file
View File

@@ -0,0 +1,9 @@
version = system.NimVersion
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
installDirs = @["compiler", "nimsuggest"]
requires "nim >= 0.14.0"

View File

@@ -1,128 +0,0 @@
import ast
import std / assertions
const
PathKinds0* = {nkDotExpr, nkCheckedFieldExpr,
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
nkAddr, nkHiddenAddr,
nkObjDownConv, nkObjUpConv}
PathKinds1* = {nkHiddenStdConv, nkHiddenSubConv}
proc skipConvDfa*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkObjDownConv, nkObjUpConv:
result = result[0]
of PathKinds1:
result = result[1]
else: break
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
var n = orig
while true:
case n.kind
of PathKinds0 - {nkHiddenDeref, nkDerefExpr}:
n = n[0]
of PathKinds1:
n = n[1]
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
(n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned})
else: break
# XXX Allow closure deref operations here if we know
# the owner controlled the closure allocation?
result = n.kind == nkSym and n.sym.owner == owner and
{sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and
(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
#
# let splited = split(move self.root, x)
# self.root = merge(splited.lower, splited.greater)
#
# could be written without the ``move self.root``. However, this would be
# wrong! Then the write barrier for the ``self.root`` assignment would
# free the old data and all is lost! Lesson: Don't be too smart, trust the
# lower level C++ optimizer to specialize this code.
type AliasKind* = enum
yes, no, maybe
proc aliases*(obj, field: PNode): AliasKind =
# obj -> field:
# x -> x: true
# x -> x.f: true
# x.f -> x: false
# x.f -> x.f: true
# x.f -> x.v: false
# x -> x[]: true
# x[] -> x: false
# x -> x[0]: true
# x[0] -> x: false
# x[0] -> x[0]: true
# x[0] -> x[1]: false
# x -> x[i]: true
# x[i] -> x: false
# x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant
# x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant
template collectImportantNodes(result, n) =
var result: seq[PNode] = @[]
var n = n
while true:
case n.kind
of PathKinds0 - {nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref}:
n = n[0]
of PathKinds1:
n = n[1]
of nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref:
result.add n
n = n[0]
of nkSym:
result.add n
break
else: return no
collectImportantNodes(objImportantNodes, obj)
collectImportantNodes(fieldImportantNodes, field)
# If field is less nested than obj, then it cannot be part of/aliased by obj
if fieldImportantNodes.len < objImportantNodes.len: return no
result = yes
for i in 1..objImportantNodes.len:
# We compare the nodes leading to the location of obj and field
# with each other.
# We continue until they diverge, in which case we return no, or
# until we reach the location of obj, in which case we do not need
# to look further, since field must be part of/aliased by obj now.
# If we encounter an element access using an index which is a runtime value,
# we simply return maybe instead of yes; should further nodes not diverge.
let currFieldPath = fieldImportantNodes[^i]
let currObjPath = objImportantNodes[^i]
if currFieldPath.kind != currObjPath.kind:
return no
case currFieldPath.kind
of nkSym:
if currFieldPath.sym != currObjPath.sym: return no
of nkDotExpr:
if currFieldPath[1].sym != currObjPath[1].sym: return no
of nkDerefExpr, nkHiddenDeref:
discard
of nkBracketExpr:
if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals:
if currFieldPath[1].intVal != currObjPath[1].intVal:
return no
else:
result = maybe
else: assert false # unreachable

View File

@@ -10,12 +10,7 @@
## Simple alias analysis for the HLO and the code generators.
import
ast, astalgo, types, trees
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
ast, astalgo, types, trees, intsets, msgs
type
TAnalysisResult* = enum
@@ -27,17 +22,17 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo
case n.kind
of nkRecList:
for i in 0..<n.len:
result = isPartOfAux(n[i], b, marker)
for i in 0 ..< sonsLen(n):
result = isPartOfAux(n.sons[i], b, marker)
if result == arYes: return
of nkRecCase:
assert(n[0].kind == nkSym)
result = isPartOfAux(n[0], b, marker)
assert(n.sons[0].kind == nkSym)
result = isPartOfAux(n.sons[0], b, marker)
if result == arYes: return
for i in 1..<n.len:
case n[i].kind
for i in 1 ..< sonsLen(n):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = isPartOfAux(lastSon(n[i]), b, marker)
result = isPartOfAux(lastSon(n.sons[i]), b, marker)
if result == arYes: return
else: discard "isPartOfAux(record case branch)"
of nkSym:
@@ -51,16 +46,14 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind
of tyObject:
if a.baseClass != nil:
result = isPartOfAux(a.baseClass.skipTypes(skipPtrs), b, marker)
if a.sons[0] != nil:
result = isPartOfAux(a.sons[0].skipTypes(skipPtrs), b, marker)
if result == arNo: result = isPartOfAux(a.n, b, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
result = isPartOfAux(skipModifier(a), b, marker)
of tySet, tyArray:
result = isPartOfAux(a.elementType, b, marker)
of tyTuple:
for aa in a.kids:
result = isPartOfAux(aa, b, marker)
result = isPartOfAux(lastSon(a), b, marker)
of tyArray, tySet, tyTuple:
for i in 0 ..< sonsLen(a):
result = isPartOfAux(a.sons[i], b, marker)
if result == arYes: return
else: discard
@@ -81,29 +74,24 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
## cases:
##
## YES-cases:
## ```
## x <| x # for general trees
## x[] <| x
## x[i] <| x
## x.f <| x
## ```
##
## NO-cases:
## ```
## x !<| y # depending on type and symbol kind
## x[constA] !<| x[constB]
## x.f !<| x.g
## x.f !<| y.f iff x !<= y
## ```
##
## MAYBE-cases:
##
## ```
## x[] ?<| y[] iff compatible type
##
##
## x[] ?<| y depending on type
## ```
##
if a.kind == b.kind:
case a.kind
of nkSym:
@@ -118,11 +106,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
# use expensive type check:
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
result = arMaybe
else:
result = arNo
of nkBracketExpr:
result = isPartOf(a[0], b[0])
if a.len >= 2 and b.len >= 2:
if len(a) >= 2 and len(b) >= 2:
# array accesses:
if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
# we know it's the same array and we have 2 constant indexes;
@@ -155,7 +141,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: result = arNo
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -171,7 +157,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of DerefKinds:
# a* !<| b[] iff
result = arNo
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a, b[0])
if result == arNo: result = arMaybe
@@ -193,26 +178,19 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else:
result = arNo
else: result = arNo
else: discard
of nkObjConstr:
result = arNo
for i in 1..<b.len:
for i in 1 ..< b.len:
let res = isPartOf(a, b[i][1])
if res != arNo:
result = res
if res == arYes: break
of nkCallKinds:
result = arNo
for i in 1..<b.len:
for i in 1 ..< b.len:
let res = isPartOf(a, b[i])
if res != arNo:
result = res
if res == arYes: break
of nkBracket:
if b.len > 0:
result = isPartOf(a, b[0])
else:
result = arNo
else: result = arNo
else: discard

View File

@@ -1,6 +1,6 @@
#[
move to std/asciitables.nim once stable, or to a fusion package
once compiler can depend on fusion
move to std/asciitables.nim once stable, or to a nimble paackage
once compiler can depend on nimble
]#
type Cell* = object
@@ -8,7 +8,7 @@ type Cell* = object
width*, row*, col*, ncols*, nrows*: int
iterator parseTableCells*(s: string, delim = '\t'): Cell =
## Iterates over all cells in a `delim`-delimited `s`, after a 1st
## iterates over all cells in a `delim`-delimited `s`, after a 1st
## pass that computes number of rows, columns, and width of each column.
var widths: seq[int]
var cell: Cell
@@ -69,9 +69,9 @@ iterator parseTableCells*(s: string, delim = '\t'): Cell =
finishRow()
proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string =
## Formats a `delim`-delimited `s` representing a table; each cell is aligned
## formats a `delim`-delimited `s` representing a table; each cell is aligned
## to a width that's computed for each column; consecutive columns are
## delimited by `sep`, and alignment space is filled using `fill`.
## delimted by `sep`, and alignment space is filled using `fill`.
## More customized formatting can be done by calling `parseTableCells` directly.
for cell in parseTableCells(s, delim):
result.add cell.text

File diff suppressed because it is too large Load Diff

View File

@@ -12,61 +12,72 @@
# the data structures here are used in various places of the compiler.
import
ast, astyaml, options, lineinfos, idents, rodutils,
ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils,
msgs
import std/[hashes, intsets]
import std/strutils except addf
export astyaml.treeToYaml, astyaml.typeToYaml, astyaml.symToYaml, astyaml.lineInfoToStr
when defined(nimPreviewSlimSystem):
import std/assertions
proc hashNode*(p: RootRef): Hash
proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph.
proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope
# these are for debugging only: They are not really deprecated, but I want
# the warning so that release versions do not contain debugging statements:
proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.}
proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
when declared(echo):
# these are for debugging only: They are not really deprecated, but I want
# the warning so that release versions do not contain debugging statements:
proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.}
proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
template debug*(x: PSym|PType|PNode) {.deprecated.} =
when compiles(c.config):
debug(c.config, x)
elif compiles(c.graph.config):
debug(c.graph.config, x)
else:
error()
template debug*(x: auto) {.deprecated.} =
echo x
template mdbg*: bool {.deprecated.} =
when compiles(c.graph):
c.module.fileIdx == c.graph.config.projectMainIdx
elif compiles(c.module):
c.module.fileIdx == c.config.projectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx == c.c.config.projectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx == m.c.config.projectMainIdx
elif compiles(cl.c.module):
cl.c.module.fileIdx == cl.c.config.projectMainIdx
elif compiles(p):
when compiles(p.lex):
p.lex.fileIdx == p.lex.config.projectMainIdx
template debug*(x: PSym|PType|PNode) {.deprecated.} =
when compiles(c.config):
debug(c.config, x)
elif compiles(c.graph.config):
debug(c.graph.config, x)
else:
p.module.module.fileIdx == p.config.projectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx == m.config.projectMainIdx
elif compiles(L.fileIdx):
L.fileIdx == L.config.projectMainIdx
else:
error()
error()
template debug*(x: auto) {.deprecated.} =
echo x
template mdbg*: bool {.deprecated.} =
when compiles(c.graph):
c.module.fileIdx == c.graph.config.projectMainIdx
elif compiles(c.module):
c.module.fileIdx == c.config.projectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx == c.c.config.projectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx == m.c.config.projectMainIdx
elif compiles(cl.c.module):
cl.c.module.fileIdx == cl.c.config.projectMainIdx
elif compiles(p):
when compiles(p.lex):
p.lex.fileIdx == p.lex.config.projectMainIdx
else:
p.module.module.fileIdx == p.config.projectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx == m.config.projectMainIdx
elif compiles(L.fileIdx):
L.fileIdx == L.config.projectMainIdx
else:
error()
# --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
proc idTableGet*(t: TIdTable, key: int): RootRef
proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id)
proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
# ---------------------------------------------------------------------------
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
@@ -85,28 +96,28 @@ type
data*: TIIPairSeq
proc initIITable*(x: var TIITable)
proc initIiTable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
# implementation
proc skipConvCastAndClosure*(n: PNode): PNode =
proc skipConvAndClosure*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
nkClosure:
result = result[0]
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
result = result[1]
result = result.sons[0]
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = result.sons[1]
else: break
proc sameValue*(a, b: PNode): bool =
result = false
case a.kind
of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) == getInt(b)
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit:
@@ -120,8 +131,8 @@ proc leValue*(a, b: PNode): bool =
# a <= b?
result = false
case a.kind
of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) <= getInt(b)
of nkCharLit..nkUInt32Lit:
if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
of nkStrLit..nkTripleStrLit:
@@ -141,17 +152,17 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = nil
case n.kind
of nkRecList:
for i in 0..<n.len:
result = lookupInRecord(n[i], field)
for i in 0 ..< sonsLen(n):
result = lookupInRecord(n.sons[i], field)
if result != nil: return
of nkRecCase:
if (n[0].kind != nkSym): return nil
result = lookupInRecord(n[0], field)
if (n.sons[0].kind != nkSym): return nil
result = lookupInRecord(n.sons[0], field)
if result != nil: return
for i in 1..<n.len:
case n[i].kind
for i in 1 ..< sonsLen(n):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = lookupInRecord(lastSon(n[i]), field)
result = lookupInRecord(lastSon(n.sons[i]), field)
if result != nil: return
else: return nil
of nkSym:
@@ -163,56 +174,14 @@ proc getModule*(s: PSym): PSym =
assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner
proc fromSystem*(op: PSym): bool {.inline.} = sfSystemModule in getModule(op).flags
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in start..<list.len:
if list[i].kind == nkSym:
result = list[i].sym
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in start ..< sonsLen(list):
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
if result.name.id == ident.id: return
else: return nil
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
result = false
if a[0] != b[0]: return false
var alen = a.len - 1
while alen > 0 and a[alen] != '`': dec(alen)
if alen <= 0: alen = a.len
var i = 1
var j = 1
while true:
while i < alen and a[i] == '_': inc i
while j < b.len and b[j] == '_': inc j
var aa = if i < alen: toLowerAscii(a[i]) else: '\0'
var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
if aa != bb: return false
# the characters are identical:
if i >= alen:
# both cursors at the end:
if j >= b.len: return true
# not yet at the end of 'b':
return false
elif j >= b.len:
return false
inc i
inc j
proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '\`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
## ```nim
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
## ```
result = nil
for i in 1..<list.len:
let it = list[i].sym
if it.name.id == ident.id or
sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
proc hashNode(p: RootRef): Hash =
result = hash(cast[pointer](p))
@@ -220,7 +189,169 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
import std/tables
proc rspaces(x: int): Rope =
# returns x spaces
result = rope(spaces(x))
proc toYamlChar(c: char): string =
case c
of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c
else: result = $c
proc makeYamlString*(s: string): Rope =
# We have to split long strings into many ropes. Otherwise
# this could trigger InternalError(111). See the ropes module for
# further information.
const MaxLineLength = 64
result = nil
var res = "\""
for i in 0 ..< s.len:
if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, "\n")
add(result, rope(res))
res = "\"" # reset
add(res, toYamlChar(s[i]))
add(res, '\"')
add(result, rope(res))
proc flagsToStr[T](flags: set[T]): Rope =
if flags == {}:
result = rope("[]")
else:
result = nil
for x in items(flags):
if result != nil: add(result, ", ")
add(result, makeYamlString($x))
result = "[" & result & "]"
proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
result = "[$1, $2, $3]" % [makeYamlString(toFilename(conf, info)),
rope(toLinenumber(info)),
rope(toColumn(info))]
proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
if n == nil:
result = rope("null")
elif containsOrIncl(marker, n.id):
result = "\"$1\"" % [rope(n.name.s)]
else:
var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
#rope("typ"), typeToYamlAux(conf, n.typ, marker,
# indent + 2, maxRecDepth - 1),
let istr = rspaces(indent + 2)
result = rope("{")
addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
addf(result, "$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
addf(result, "$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
if conf != nil:
# if we don't pass the config, we probably don't care about the line info
addf(result, "$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
if card(n.flags) > 0:
addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
addf(result, "$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
addf(result, "$N$1\"ast\": $2", [istr, ast])
addf(result, "$N$1\"options\": $2", [istr, flagsToStr(n.options)])
addf(result, "$N$1\"position\": $2", [istr, rope(n.position)])
addf(result, "$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
addf(result, "$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
if card(n.loc.flags) > 0:
addf(result, "$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
addf(result, "$N$1\"r\": $2", [istr, n.loc.r])
addf(result, "$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
addf(result, "$N$1}", [rspaces(indent)])
proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
else:
if sonsLen(n) > 0:
sonsRope = rope("[")
for i in 0 ..< sonsLen(n):
if i > 0: add(sonsRope, ",")
addf(sonsRope, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
marker, indent + 4, maxRecDepth - 1)])
addf(sonsRope, "$N$1]", [rspaces(indent + 2)])
else:
sonsRope = rope("null")
let istr = rspaces(indent + 2)
result = rope("{")
addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
addf(result, "$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
addf(result, "$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
if card(n.flags) > 0:
addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
addf(result, "$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
addf(result, "$N$1\"size\": $2", [istr, rope(n.size)])
addf(result, "$N$1\"align\": $2", [istr, rope(n.align)])
addf(result, "$N$1\"sons\": $2", [istr, sonsRope])
proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
if n == nil:
result = rope("null")
else:
var istr = rspaces(indent + 2)
result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
if maxRecDepth != 0:
if conf != nil:
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit..nkInt64Lit:
addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
addf(result, ",$N$1\"floatVal\": $2",
[istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
addf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent:
if n.ident != nil:
addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else:
addf(result, ",$N$1\"ident\": null", [istr])
else:
if sonsLen(n) > 0:
addf(result, ",$N$1\"sons\": [", [istr])
for i in 0 ..< sonsLen(n):
if i > 0: add(result, ",")
addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
marker, indent + 4, maxRecDepth - 1)])
addf(result, "$N$1]", [istr])
addf(result, ",$N$1\"typ\": $2",
[istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
addf(result, "$N$1}", [rspaces(indent)])
proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
import tables
const backrefStyle = "\e[90m"
const enumStyle = "\e[34m"
@@ -248,7 +379,7 @@ proc indentLess(this: var DebugPrinter) =
proc newlineAndIndent(this: var DebugPrinter) =
this.res.add "\n"
this.currentLine += 1
for i in 0..<this.indent:
for i in 0 ..< this.indent:
this.res.add ' '
proc openCurly(this: var DebugPrinter) =
@@ -384,12 +515,14 @@ proc value(this: var DebugPrinter; value: PType) =
this.key "n"
this.value value.n
this.key "sons"
this.openBracket
for i, a in value.ikids:
if i > 0: this.comma
this.value a
this.closeBracket
if sonsLen(value) > 0:
this.key "sons"
this.openBracket
for i in 0 ..< sonsLen(value):
this.value value.sons[i]
if i != sonsLen(value) - 1:
this.comma
this.closeBracket
if value.n != nil:
this.key "n"
@@ -403,26 +536,16 @@ proc value(this: var DebugPrinter; value: PNode) =
this.openCurly
this.key "kind"
this.value value.kind
if value.comment.len > 0:
this.key "comment"
this.value value.comment
when defined(useNodeIds):
this.key "id"
this.value value.id
if this.conf != nil:
this.key "info"
this.value $lineInfoToStr(this.conf, value.info)
if value.flags != {}:
if card(value.flags) > 0:
this.key "flags"
this.value value.flags
if value.typ != nil:
this.key "typ"
this.value value.typ.kind
else:
this.key "typ"
this.value "nil"
case value.kind
of nkCharLit..nkUInt64Lit:
this.key "intVal"
@@ -445,46 +568,43 @@ proc value(this: var DebugPrinter; value: PNode) =
if this.renderSymType and value.typ != nil:
this.key "typ"
this.value value.typ
if value.len > 0:
if sonsLen(value) > 0:
this.key "sons"
this.openBracket
for i in 0..<value.len:
this.value value[i]
if i != value.len - 1:
for i in 0 ..< sonsLen(value):
this.value value.sons[i]
if i != sonsLen(value) - 1:
this.comma
this.closeBracket
this.closeCurly
when declared(echo):
proc debug(n: PSym; conf: ConfigRef) =
var this: DebugPrinter
this.visited = initTable[pointer, int]()
this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc debug(n: PSym; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: true,
useColor: not defined(windows)
)
this.value(n)
echo($this.res)
proc debug(n: PType; conf: ConfigRef) =
var this: DebugPrinter
this.visited = initTable[pointer, int]()
this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc debug(n: PType; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: true,
useColor: not defined(windows)
)
this.value(n)
echo($this.res)
proc debug(n: PNode; conf: ConfigRef) =
var this: DebugPrinter
this.visited = initTable[pointer, int]()
#this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc debug(n: PNode; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: false,
useColor: not defined(windows)
)
this.value(n)
echo($this.res)
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash =
result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
@@ -509,13 +629,13 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
proc objectSetEnlarge(t: var TObjectSet) =
var n: TObjectSeq
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
newSeq(n, len(t.data) * GrowthFactor)
for i in 0 .. high(t.data):
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n)
proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
if mustRehash(t.data.len, t.counter): objectSetEnlarge(t)
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj)
inc(t.counter)
@@ -528,7 +648,7 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
if it == obj:
return true # found it
h = nextTry(h, high(t.data))
if mustRehash(t.data.len, t.counter):
if mustRehash(len(t.data), t.counter):
objectSetEnlarge(t)
objectSetRawInsert(t.data, obj)
else:
@@ -571,21 +691,21 @@ proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
proc strTableEnlarge(t: var TStrTable) =
var n: seq[PSym]
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
newSeq(n, len(t.data) * GrowthFactor)
for i in 0 .. high(t.data):
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n)
proc strTableAdd*(t: var TStrTable, n: PSym) =
if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n)
inc(t.counter)
proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
onConflictKeepOld = false): PSym =
# if `t` has a conflicting symbol (same identifier as `n`), return it
# otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true`
# and a conflict was found.
# returns true if n is already in the string table:
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
assert n.name != nil
var h: Hash = n.name.h and high(t.data)
var replaceSlot = -1
@@ -601,11 +721,10 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
replaceSlot = h
h = nextTry(h, high(t.data))
if replaceSlot >= 0:
result = t.data[replaceSlot] # found it
if not onConflictKeepOld:
t.data[replaceSlot] = n # overwrite it with newer definition!
return result # but return the old one
elif mustRehash(t.data.len, t.counter):
return t.data[replaceSlot] # found it
elif mustRehash(len(t.data), t.counter):
strTableEnlarge(t)
strTableRawInsert(t.data, n)
else:
@@ -633,21 +752,16 @@ type
name*: PIdent
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
# hot spots
var h = ti.h and high(tab.data)
var start = h
var p {.cursor.} = tab.data[h]
while p != nil:
if p.name.id == ti.name.id: break
result = tab.data[h]
while result != nil:
if result.name.id == ti.name.id: break
h = nextTry(h, high(tab.data))
if h == start:
p = nil
result = nil
break
p = tab.data[h]
if p != nil:
result = p # increase the count
else:
result = nil
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
@@ -707,16 +821,129 @@ proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
result = nextIter(ti, tab)
iterator items*(tab: TStrTable): PSym =
var it: TTabIter = default(TTabIter)
var it: TTabIter
var s = initTabIter(it, tab)
while s != nil:
yield s
s = nextIter(it, tab)
proc hasEmptySlot(data: TIdPairSeq): bool =
for h in 0 .. high(data):
if data[h].key == nil:
return true
result = false
proc idTableRawGet(t: TIdTable, key: int): int =
var h: Hash
h = key and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key:
return h
h = nextTry(h, high(t.data))
result = - 1
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key
else: result = false
proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
for i in 0..high(t.data):
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
var
index: int
n: TIdPairSeq
index = idTableRawGet(t, key.id)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
newSeq(n, len(t.data) * GrowthFactor)
for i in 0 .. high(t.data):
if t.data[i].key != nil:
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
idTableRawInsert(t.data, key, val)
inc(t.counter)
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: Hash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key.id:
return h
h = nextTry(h, high(t.data))
result = - 1
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int
index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
var n: TIdNodePairSeq
newSeq(n, len(t.data) * GrowthFactor)
for i in 0 .. high(t.data):
if t.data[i].key != nil:
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
idNodeTableRawInsert(t.data, key, val)
inc(t.counter)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, StartSize)
for i in 0..<StartSize: x.data[i].key = InvalidKey
for i in 0 ..< StartSize: x.data[i].key = InvalidKey
proc iiTableRawGet(t: TIITable, key: int): int =
var h: Hash
@@ -747,25 +974,21 @@ proc iiTablePut(t: var TIITable, key, val: int) =
assert(t.data[index].key != InvalidKey)
t.data[index].val = val
else:
if mustRehash(t.data.len, t.counter):
if mustRehash(len(t.data), t.counter):
var n: TIIPairSeq
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(n): n[i].key = InvalidKey
for i in 0..high(t.data):
newSeq(n, len(t.data) * GrowthFactor)
for i in 0 .. high(n): n[i].key = InvalidKey
for i in 0 .. high(t.data):
if t.data[i].key != InvalidKey:
iiTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
iiTableRawInsert(t.data, key, val)
inc(t.counter)
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:
if result.len > 0:
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
proc isAddrNode*(n: PNode): bool =
case n.kind
of nkAddr, nkHiddenAddr: true
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
else: false
else: false

View File

@@ -1,45 +0,0 @@
# this module avoids ast depending on msgs or vice versa
import std/strutils
import options, ast, msgs
proc typSym*(t: PType): PSym =
result = t.sym
if result == nil and t.kind == tyGenericInst: # this might need to be refined
result = t.genericHead.sym
proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) =
result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)]
proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) =
if optDeclaredLocs in conf.globalOptions and sym != nil:
addDeclaredLoc(result, conf, sym)
proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
# xxx figure out how to resolve `tyGenericParam`, e.g. for
# proc fn[T](a: T, b: T) = discard
# fn(1.1, "a")
let typ = typ.skipTypes(abstractInst + {tyStatic, tySequence, tyArray, tySet, tyUserTypeClassInst, tyVar, tyRef, tyPtr} - {tyRange})
result.add " [$1" % typ.kind.toHumanStr
if typ.sym != nil:
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addTypeNodeDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
result.add " [$1" % typ.kind.toHumanStr
if typ.sym != nil:
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) =
if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ)
template quoteExpr*(a: string): untyped =
## can be used for quoting expressions in error msgs.
"'" & a & "'"
proc genFieldDefect*(conf: ConfigRef, field: string, disc: PSym): string =
let obj = disc.owner.name.s # `types.typeToString` might be better, eg for generics
result = "field '$#' is not accessible for type '$#'" % [field, obj]
if optDeclaredLocs in conf.globalOptions:
result.add " [discriminant declared in $#]" % toFileLineCol(conf, disc.info)
result.add " using '$# = " % disc.name.s

View File

@@ -1,154 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# AST YAML printing
import "."/[ast, lineinfos, msgs, options, rodutils]
import std/[intsets, strutils]
proc addYamlString*(res: var string; s: string) =
res.add "\""
for c in s:
case c
of '\0' .. '\x1F', '\x7F' .. '\xFF':
res.add("\\u" & strutils.toHex(ord(c), 4))
of '\"', '\\':
res.add '\\' & c
else:
res.add c
res.add('\"')
proc makeYamlString(s: string): string =
result = ""
result.addYamlString(s)
proc flagsToStr[T](flags: set[T]): string =
if flags == {}:
result = "[]"
else:
result = ""
for x in items(flags):
if result != "":
result.add(", ")
result.addYamlString($x)
result = "[" & result & "]"
proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): string =
result = "["
result.addYamlString(toFilename(conf, info))
result.addf ", $1, $2]", [toLinenumber(info), toColumn(info)]
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent, maxRecDepth: int)
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
res.addYamlString(n.name.s)
else:
let istr = spaces(indent * 4)
res.addf("kind: $1", [makeYamlString($n.kind)])
res.addf("\n$1name: $2", [istr, makeYamlString(n.name.s)])
res.addf("\n$1typ: ", [istr])
res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth - 1)
if conf != nil:
# if we don't pass the config, we probably don't care about the line info
res.addf("\n$1info: $2", [istr, lineInfoToStr(conf, n.info)])
if card(n.flags) > 0:
res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)])
res.addf("\n$1magic: $2", [istr, makeYamlString($n.magic)])
res.addf("\n$1ast: ", [istr])
res.treeToYamlAux(conf, n.ast, marker, indent + 1, maxRecDepth - 1)
res.addf("\n$1options: $2", [istr, flagsToStr(n.options)])
res.addf("\n$1position: $2", [istr, $n.position])
res.addf("\n$1k: $2", [istr, makeYamlString($n.loc.k)])
res.addf("\n$1storage: $2", [istr, makeYamlString($n.loc.storage)])
if card(n.loc.flags) > 0:
res.addf("\n$1flags: $2", [istr, makeYamlString($n.loc.flags)])
res.addf("\n$1snippet: $2", [istr, n.loc.snippet])
res.addf("\n$1lode: $2", [istr])
res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1)
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
res.addf "\"$1 @$2\"" % [$n.kind, strutils.toHex(cast[uint](n), sizeof(n) * 2)]
else:
let istr = spaces(indent * 4)
res.addf("kind: $2", [istr, makeYamlString($n.kind)])
res.addf("\n$1sym: ")
res.symToYamlAux(conf, n.sym, marker, indent + 1, maxRecDepth - 1)
res.addf("\n$1n: ")
res.treeToYamlAux(conf, n.n, marker, indent + 1, maxRecDepth - 1)
if card(n.flags) > 0:
res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)])
res.addf("\n$1callconv: $2", [istr, makeYamlString($n.callConv)])
res.addf("\n$1size: $2", [istr, $(n.size)])
res.addf("\n$1align: $2", [istr, $(n.align)])
if n.hasElementType:
res.addf("\n$1sons:")
for a in n.kids:
res.addf("\n - ")
res.typeToYamlAux(conf, a, marker, indent + 1, maxRecDepth - 1)
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent: int;
maxRecDepth: int) =
if n == nil:
res.add("null")
else:
var istr = spaces(indent * 4)
res.addf("kind: $1" % [makeYamlString($n.kind)])
if maxRecDepth != 0:
if conf != nil:
res.addf("\n$1info: $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit .. nkInt64Lit:
res.addf("\n$1intVal: $2", [istr, $(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
res.addf("\n$1floatVal: $2", [istr, n.floatVal.toStrMaxPrecision])
of nkStrLit .. nkTripleStrLit:
res.addf("\n$1strVal: $2", [istr, makeYamlString(n.strVal)])
of nkSym:
res.addf("\n$1sym: ", [istr])
res.symToYamlAux(conf, n.sym, marker, indent + 1, maxRecDepth)
of nkIdent:
if n.ident != nil:
res.addf("\n$1ident: $2", [istr, makeYamlString(n.ident.s)])
else:
res.addf("\n$1ident: null", [istr])
else:
if n.len > 0:
res.addf("\n$1sons: ", [istr])
for i in 0 ..< n.len:
res.addf("\n$1 - ", [istr])
res.treeToYamlAux(conf, n[i], marker, indent + 1, maxRecDepth - 1)
if n.typ != nil:
res.addf("\n$1typ: ", [istr])
res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth)
proc treeToYaml*(conf: ConfigRef; n: PNode; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml*(conf: ConfigRef; n: PType; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml*(conf: ConfigRef; n: PSym; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.symToYamlAux(conf, n, marker, indent, maxRecDepth)

View File

@@ -10,9 +10,6 @@
# this unit handles Nim sets; it implements bit sets
# the code here should be reused in the Nim standard library
when defined(nimPreviewSlimSystem):
import std/assertions
type
ElemType = byte
TBitSet* = seq[ElemType] # we use byte here to avoid issues with
@@ -26,41 +23,54 @@ const
template modElemSize(arg: untyped): untyped = arg and 7
template divElemSize(arg: untyped): untyped = arg shr 3
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool =
proc bitSetInit*(b: var TBitSet, length: int)
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
proc bitSetDiff*(x: var TBitSet, y: TBitSet)
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
proc bitSetEquals*(x, y: TBitSet): bool
proc bitSetContains*(x, y: TBitSet): bool
proc bitSetCard*(x: TBitSet): BiggestInt
# implementation
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
result = (x[int(e.divElemSize)] and (One shl e.modElemSize)) != Zero
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt) =
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
assert(elem >= 0)
x[int(elem.divElemSize)] = x[int(elem.divElemSize)] or
(One shl elem.modElemSize)
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt) =
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
x[int(elem.divElemSize)] = x[int(elem.divElemSize)] and
not(One shl elem.modElemSize)
proc bitSetInit*(b: var TBitSet, length: int) =
proc bitSetInit(b: var TBitSet, length: int) =
newSeq(b, length)
proc bitSetUnion*(x: var TBitSet, y: TBitSet) =
for i in 0..high(x): x[i] = x[i] or y[i]
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
for i in 0 .. high(x): x[i] = x[i] or y[i]
proc bitSetDiff*(x: var TBitSet, y: TBitSet) =
for i in 0..high(x): x[i] = x[i] and not y[i]
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
for i in 0 .. high(x): x[i] = x[i] and not y[i]
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet) =
for i in 0..high(x): x[i] = x[i] xor y[i]
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
for i in 0 .. high(x): x[i] = x[i] xor y[i]
proc bitSetIntersect*(x: var TBitSet, y: TBitSet) =
for i in 0..high(x): x[i] = x[i] and y[i]
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
for i in 0 .. high(x): x[i] = x[i] and y[i]
proc bitSetEquals*(x, y: TBitSet): bool =
for i in 0..high(x):
proc bitSetEquals(x, y: TBitSet): bool =
for i in 0 .. high(x):
if x[i] != y[i]:
return false
result = true
proc bitSetContains*(x, y: TBitSet): bool =
for i in 0..high(x):
proc bitSetContains(x, y: TBitSet): bool =
for i in 0 .. high(x):
if (x[i] and not y[i]) != Zero:
return false
result = true
@@ -86,12 +96,6 @@ const populationCount: array[uint8, uint8] = block:
arr
proc bitSetCard*(x: TBitSet): BiggestInt =
result = 0
proc bitSetCard(x: TBitSet): BiggestInt =
for it in x:
result.inc int(populationCount[it])
proc bitSetToWord*(s: TBitSet; size: int): BiggestUInt =
result = 0
for j in 0..<size:
if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))

View File

@@ -10,16 +10,13 @@
## BTree implementation with few features, but good enough for the
## Nim compiler's needs.
when defined(nimPreviewSlimSystem):
import std/assertions
const
M = 512 # max children per B-tree node = M-1
# (must be even and greater than 2)
Mhalf = M div 2
type
Node[Key, Val] {.acyclic.} = ref object
Node[Key, Val] = ref object
entries: int
keys: array[M, Key]
case isInternal: bool
@@ -38,41 +35,37 @@ template less(a, b): bool = cmp(a, b) < 0
template eq(a, b): bool = cmp(a, b) == 0
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
result = default(Val)
var x = b.root
while x.isInternal:
for j in 0..<x.entries:
for j in 0 ..< x.entries:
if j+1 == x.entries or less(key, x.keys[j+1]):
x = x.links[j]
break
assert(not x.isInternal)
for j in 0..<x.entries:
for j in 0 ..< x.entries:
if eq(key, x.keys[j]): return x.vals[j]
proc contains*[Key, Val](b: BTree[Key, Val], key: Key): bool =
var x = b.root
while x.isInternal:
for j in 0..<x.entries:
for j in 0 ..< x.entries:
if j+1 == x.entries or less(key, x.keys[j+1]):
x = x.links[j]
break
assert(not x.isInternal)
for j in 0..<x.entries:
for j in 0 ..< x.entries:
if eq(key, x.keys[j]): return true
return false
proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
for j in 0..<Mhalf:
for j in 0 ..< Mhalf:
result.keys[j] = h.keys[Mhalf + j]
if h.isInternal:
for j in 0..<Mhalf:
for j in 0 ..< Mhalf:
result.links[j] = h.links[Mhalf + j]
else:
for j in 0..<Mhalf:
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result.vals[j] = move h.vals[Mhalf + j]
else:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
for j in 0 ..< Mhalf:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
proc split[Key, Val](h: Node[Key, Val]): Node[Key, Val] =
## split node in half
@@ -86,16 +79,10 @@ 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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
h.vals[i] = move h.vals[i-1]
else:
shallowCopy(h.vals[i], h.vals[i-1])
shallowCopy(h.vals[i], h.vals[i-1])
h.vals[j] = val
else:
var newLink: Node[Key, Val] = nil
@@ -145,7 +132,8 @@ proc `$`[Key, Val](b: BTree[Key, Val]): string =
result = ""
toString(b.root, "", result)
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = index < b.entries
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool =
result = index < b.entries
proc countSubTree[Key, Val](it: Node[Key, Val]): int =
if it.isInternal:
@@ -178,3 +166,68 @@ iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) =
yield (k, v)
proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries
when isMainModule:
import random, tables
proc main =
var st = initBTree[string, string]()
st.add("www.cs.princeton.edu", "abc")
st.add("www.princeton.edu", "128.112.128.15")
st.add("www.yale.edu", "130.132.143.21")
st.add("www.simpsons.com", "209.052.165.60")
st.add("www.apple.com", "17.112.152.32")
st.add("www.amazon.com", "207.171.182.16")
st.add("www.ebay.com", "66.135.192.87")
st.add("www.cnn.com", "64.236.16.20")
st.add("www.google.com", "216.239.41.99")
st.add("www.nytimes.com", "199.239.136.200")
st.add("www.microsoft.com", "207.126.99.140")
st.add("www.dell.com", "143.166.224.230")
st.add("www.slashdot.org", "66.35.250.151")
st.add("www.espn.com", "199.181.135.201")
st.add("www.weather.com", "63.111.66.11")
st.add("www.yahoo.com", "216.109.118.65")
assert st.getOrDefault("www.cs.princeton.edu") == "abc"
assert st.getOrDefault("www.harvardsucks.com") == nil
assert st.getOrDefault("www.simpsons.com") == "209.052.165.60"
assert st.getOrDefault("www.apple.com") == "17.112.152.32"
assert st.getOrDefault("www.ebay.com") == "66.135.192.87"
assert st.getOrDefault("www.dell.com") == "143.166.224.230"
assert(st.entries == 16)
for k, v in st:
echo k, ": ", v
when false:
var b2 = initBTree[string, string]()
const iters = 10_000
for i in 1..iters:
b2.add($i, $(iters - i))
for i in 1..iters:
let x = b2.getOrDefault($i)
if x != $(iters - i):
echo "got ", x, ", but expected ", iters - i
echo b2.entries
when true:
var b2 = initBTree[int, string]()
var t2 = initTable[int, string]()
const iters = 100_000
for i in 1..iters:
let x = rand(high(int))
if not t2.hasKey(x):
doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x
t2[x] = $x
b2.add(x, $x)
doAssert b2.entries == t2.len
echo "unique entries ", b2.entries
for k, v in t2:
doAssert $k == v
doAssert b2.getOrDefault(k) == $k
main()

421
compiler/canonicalizer.nim Normal file
View File

@@ -0,0 +1,421 @@
#
#
# 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 the canonalization for the various caching mechanisms.
import strutils, db_sqlite, md5
var db: DbConn
# We *hash* the relevant information into 128 bit hashes. This should be good
# enough to prevent any collisions.
type
TUid = distinct MD5Digest
# For name mangling we encode these hashes via a variant of base64 (called
# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
# So a signature like:
#
# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
#
# is mangled into:
# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
#
# This is a good compromise between correctness and brevity. ;-)
const
cb64 = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"_A", "_B"]
proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
result = newStringOfCap(((len + 2) div 3) * 4)
var i = 0
while i < s.len - 2:
let a = ord(s[i])
let b = ord(s[i+1])
let c = ord(s[i+2])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result.add cb64[c and 0x3F]
inc(i, 3)
if i < s.len-1:
let a = ord(s[i])
let b = ord(s[i+1])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2)]
elif i < s.len:
let a = ord(s[i])
result.add cb64[a shr 2]
result.add cb64[(a and 3) shl 4]
proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
var it = s.owner
while it != nil:
hashSym(c, it)
c &= "."
it = s.owner
c &= s.name.s
proc hashTree(c: var MD5Context, n: PNode) =
if n == nil:
c &= "\255"
return
var k = n.kind
md5Update(c, cast[cstring](addr(k)), 1)
# we really must not hash line information. 'n.typ' is debatable but
# shouldn't be necessary for now and avoids potential infinite recursions.
case n.kind
of nkEmpty, nkNilLit, nkType: discard
of nkIdent:
c &= n.ident.s
of nkSym:
hashSym(c, n.sym)
of nkCharLit..nkUInt64Lit:
var v = n.intVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkFloatLit..nkFloat64Lit:
var v = n.floatVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkStrLit..nkTripleStrLit:
c &= n.strVal
else:
for i in 0..<n.len: hashTree(c, n.sons[i])
proc hashType(c: var MD5Context, t: PType) =
# modelled after 'typeToString'
if t == nil:
c &= "\254"
return
var k = t.kind
md5Update(c, cast[cstring](addr(k)), 1)
if t.sym != nil and sfAnon notin t.sym.flags:
# t.n for literals, but not for e.g. objects!
if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
c.hashSym(t.sym)
case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvocation:
for i in 0 ..< sonsLen(t)-ord(t.kind != tyGenericInvocation):
c.hashType t.sons[i]
of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil
c &= t.sym.owner.name.s
of tyUserTypeClassInst:
let body = t.base
c.hashSym body.sym
for i in 1 .. sonsLen(t) - 2:
c.hashType t.sons[i]
of tyFromExpr:
c.hashTree(t.n)
of tyArray:
c.hashTree(t.sons[0].n)
c.hashType(t.sons[1])
of tyTuple:
if t.n != nil:
assert(sonsLen(t.n) == sonsLen(t))
for i in 0 ..< sonsLen(t.n):
assert(t.n.sons[i].kind == nkSym)
c &= t.n.sons[i].sym.name.s
c &= ":"
c.hashType(t.sons[i])
c &= ","
else:
for i in 0 ..< sonsLen(t): c.hashType t.sons[i]
of tyRange:
c.hashTree(t.n)
c.hashType(t.sons[0])
of tyProc:
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
for i in 0..<t.len: c.hashType(t.sons[i])
md5Update(c, cast[cstring](addr(t.callConv)), 1)
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
else:
for i in 0..<t.len: c.hashType(t.sons[i])
if tfNotNil in t.flags: c &= "not nil"
proc canonConst(n: PNode): TUid =
var c: MD5Context
md5Init(c)
c.hashTree(n)
c.hashType(n.typ)
md5Final(c, MD5Digest(result))
proc canonSym(s: PSym): TUid =
var c: MD5Context
md5Init(c)
c.hashSym(s)
md5Final(c, MD5Digest(result))
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) =
if n == nil:
# nil nodes have to be stored too:
result.add("()")
return
result.add('(')
encodeVInt(ord(n.kind), result)
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(n.info)), result)
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
var f = n.flags * PersistentNodeFlags
if f != {}:
result.add('$')
encodeVInt(cast[int32](f), result)
if n.typ != nil:
result.add('^')
encodeVInt(n.typ.id, result)
pushType(w, n.typ)
case n.kind
of nkCharLit..nkInt64Lit:
if n.intVal != 0:
result.add('!')
encodeVBiggestInt(n.intVal, result)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
result.add('!')
encodeStr($n.floatVal, result)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
result.add('!')
encodeStr(n.strVal, result)
of nkIdent:
result.add('!')
encodeStr(n.ident.s, result)
of nkSym:
result.add('!')
encodeVInt(n.sym.id, result)
pushSym(w, n.sym)
else:
for i in 0 ..< sonsLen(n):
encodeNode(w, n.info, n.sons[i], result)
add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.s != low(loc.s):
add(result, '*')
encodeVInt(ord(loc.s), result)
if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil:
add(result, '^')
encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
encodeStr($loc.r, result)
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t == nil:
# nil nodes have to be stored too:
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
if t.callConv != low(t.callConv):
add(result, '?')
encodeVInt(ord(t.callConv), result)
if t.owner != nil:
add(result, '*')
encodeVInt(t.owner.id, result)
pushSym(w, t.owner)
if t.sym != nil:
add(result, '&')
encodeVInt(t.sym.id, result)
pushSym(w, t.sym)
if t.size != - 1:
add(result, '/')
encodeVBiggestInt(t.size, result)
if t.align != - 1:
add(result, '=')
encodeVInt(t.align, result)
encodeLoc(w, t.loc, result)
for i in 0 ..< sonsLen(t):
if t.sons[i] == nil:
add(result, "^()")
else:
add(result, '^')
encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
encodeStr($lib.name, result)
add(result, '|')
encodeNode(w, info, lib.path, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s == nil:
# nil nodes have to be stored too:
result.add("{}")
return
# we need no surrounding {} here because the symbol is in a line of its own
encodeVInt(ord(s.kind), result)
result.add('+')
encodeVInt(s.id, result)
result.add('&')
encodeStr(s.name.s, result)
if s.typ != nil:
result.add('^')
encodeVInt(s.typ.id, result)
pushType(w, s.typ)
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(s.info)), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
pushSym(w, s.owner)
if s.flags != {}:
result.add('$')
encodeVInt(cast[int32](s.flags), result)
if s.magic != mNone:
result.add('@')
encodeVInt(ord(s.magic), result)
if s.options != w.options:
result.add('!')
encodeVInt(cast[int32](s.options), result)
if s.position != 0:
result.add('%')
encodeVInt(s.position, result)
if s.offset != - 1:
result.add('`')
encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nim's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)
proc createDb() =
db.exec(sql"""
create table if not exists Module(
id integer primary key,
name varchar(256) not null,
fullpath varchar(256) not null,
interfHash varchar(256) not null,
fullHash varchar(256) not null,
created timestamp not null default (DATETIME('now'))
);""")
db.exec(sql"""
create table if not exists Backend(
id integer primary key,
strongdeps varchar(max) not null,
weakdeps varchar(max) not null,
header varchar(max) not null,
code varchar(max) not null
)
create table if not exists Symbol(
id integer primary key,
module integer not null,
backend integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references Module(id),
foreign key (backend) references Backend(id)
);""")
db.exec(sql"""
create table if not exists Type(
id integer primary key,
module integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references module(id)
);""")

View File

@@ -1,6 +0,0 @@
type
Snippet = string
Builder = string
template newBuilder(s: string): Builder =
s

View File

@@ -1,338 +0,0 @@
type VarKind = enum
Local
Global
Threadvar
Const
AlwaysConst ## const even on C++
proc addVarHeader(builder: var Builder, kind: VarKind) =
## adds modifiers for given var kind:
## Local has no modifier
## Global has `static` modifier
## Const has `static NIM_CONST` modifier
## AlwaysConst has `static const` modifier (NIM_CONST is no-op on C++)
## Threadvar is unimplemented
case kind
of Local: discard
of Global:
builder.add("static ")
of Const:
builder.add("static NIM_CONST ")
of AlwaysConst:
builder.add("static const ")
of Threadvar:
doAssert false, "unimplemented"
proc addVar(builder: var Builder, kind: VarKind = Local, name: string, typ: Snippet, initializer: Snippet = "") =
## adds a variable declaration to the builder
builder.addVarHeader(kind)
builder.add(typ)
builder.add(" ")
builder.add(name)
if initializer.len != 0:
builder.add(" = ")
builder.add(initializer)
builder.add(";\n")
template addVarWithType(builder: var Builder, kind: VarKind = Local, name: string, body: typed) =
## adds a variable declaration to the builder, with the `body` building the type
builder.addVarHeader(kind)
body
builder.add(" ")
builder.add(name)
builder.add(";\n")
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
typeBody, initializerBody: typed) =
## adds a variable declaration to the builder, with `typeBody` building the type, and
## `initializerBody` building the initializer. initializer must be provided
builder.addVarHeader(kind)
typeBody
builder.add(" ")
builder.add(name)
builder.add(" = ")
initializerBody
builder.add(";\n")
proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, initializer: Snippet = "") =
## adds an array variable declaration to the builder
builder.addVarHeader(kind)
builder.add(elementType)
builder.add(" ")
builder.add(name)
builder.add("[")
builder.addInt(len)
builder.add("]")
if initializer.len != 0:
builder.add(" = ")
builder.add(initializer)
builder.add(";\n")
template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, body: typed) =
## adds an array variable declaration to the builder with the initializer built according to `body`
builder.addVarHeader(kind)
builder.add(elementType)
builder.add(" ")
builder.add(name)
builder.add("[")
builder.addInt(len)
builder.add("] = ")
body
builder.add(";\n")
template addTypedef(builder: var Builder, name: string, typeBody: typed) =
## adds a typedef declaration to the builder with name `name` and type as
## built in `typeBody`
builder.add("typedef ")
typeBody
builder.add(" ")
builder.add(name)
builder.add(";\n")
type
StructInitializerKind = enum
siOrderedStruct ## struct constructor, but without named fields on C
siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer
siArray ## array constructor
siWrapper ## wrapper for a single field, generates it verbatim
StructInitializer = object
## context for building struct initializers, i.e. `{ field1, field2 }`
kind: StructInitializerKind
## if true, fields will not be named, instead values are placed in order
needsComma: bool
proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer =
## starts building a struct initializer, i.e. braced initializer list
result = StructInitializer(kind: kind, needsComma: false)
if kind != siWrapper:
builder.add("{")
template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) =
## adds a field to a struct initializer, with the value built in `valueBody`
if constr.needsComma:
assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields"
builder.add(", ")
else:
constr.needsComma = true
case constr.kind
of siArray, siWrapper:
# no name, can just add value
valueBody
of siOrderedStruct:
# no name, can just add value on C
assert name.len != 0, "name has to be given for struct initializer field"
valueBody
of siNamedStruct:
assert name.len != 0, "name has to be given for struct initializer field"
builder.add(".")
builder.add(name)
builder.add(" = ")
valueBody
proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =
## finishes building a struct initializer
if constr.kind != siWrapper:
builder.add("}")
template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) =
## builds a struct initializer, i.e. `{ field1, field2 }`
## a `var StructInitializer` must be declared and passed as a parameter so
## that it can be used with `addField`
constr = builder.initStructInitializer(kind)
body
builder.finishStructInitializer(constr)
proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
## adds a field inside a struct/union type
obj.add('\t')
obj.add(typ)
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initializer: Snippet = "") =
## adds an array field inside a struct/union type
obj.add('\t')
obj.add(elementType)
obj.add(" ")
obj.add(name)
obj.add("[")
obj.addInt(len)
obj.add("]")
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
## adds an field inside a struct/union type, based on an `skField` symbol
obj.add('\t')
if field.alignment > 0:
obj.add("NIM_ALIGN(")
obj.addInt(field.alignment)
obj.add(") ")
obj.add(typ)
if sfNoalias in field.flags:
obj.add(" NIM_NOALIAS")
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if field.bitsize != 0:
obj.add(":")
obj.addInt(field.bitsize)
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
type
BaseClassKind = enum
## denotes how and whether or not the base class/RTTI should be stored
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
StructBuilderInfo = object
## context for building `struct` types
baseKind: BaseClassKind
named: bool
preFieldsLen: int
proc structOrUnion(t: PType): Snippet =
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
obj.add("struct")
if result.named:
obj.add(" ")
obj.add(name)
if baseType.len != 0:
if m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
if result.baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.len
if result.baseKind == bcSupField:
obj.addField(name = "Sup", typ = baseType)
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.len:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")
if info.named:
obj.add("};\n")
else:
obj.add("}")
template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
## builds a struct type not based on a Nim type with fields according to `body`,
## `name` can be empty to build as a type expression and not a statement
let info = startSimpleStruct(obj, m, name, baseType)
body
finishSimpleStruct(obj, m, info)
proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
if tfPacked in t.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add(structOrUnion(t))
obj.add(" __attribute__((__packed__))")
else:
obj.add("#pragma pack(push, 1)\n")
obj.add(structOrUnion(t))
else:
obj.add(structOrUnion(t))
if result.named:
obj.add(" ")
obj.add(name)
if t.kind == tyObject:
if t.baseClass == nil:
if lacksMTypeField(t):
result.baseKind = bcNone
elif optTinyRtti in m.config.globalOptions:
result.baseKind = bcNoneTinyRtti
else:
result.baseKind = bcNoneRtti
elif m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
elif baseType.len != 0:
if m.compileToCpp:
result.baseKind = bcCppInherit
else:
result.baseKind = bcSupField
if result.baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.len
case result.baseKind
of bcNone:
# rest of the options add a field or don't need it due to inheritance,
# we need to add the dummy field for uncheckedarray ahead of time
# so that it remains trailing
if t.itemId notin m.g.graph.memberProcsPerType and
t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
# only consists of flexible array field, add *initial* dummy field
obj.addField(name = "dummy", typ = "char")
of bcCppInherit: discard
of bcNoneRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
of bcNoneTinyRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
of bcSupField:
obj.addField(name = "Sup", typ = baseType)
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.len and
t.itemId notin m.g.graph.memberProcsPerType:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")
if info.named:
obj.add("};\n")
else:
obj.add("}")
if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
obj.add("#pragma pack(pop)\n")
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
## builds a struct type directly based on `typ` with fields according to `body`,
## `name` can be empty to build as a type expression and not a statement
let info = startStruct(obj, m, typ, name, baseType)
body
finishStruct(obj, m, typ, info)
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
## adds a field with a `struct { ... }` type, building the fields according to `body`
obj.add('\t')
if tfPacked in parentTyp.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add("struct __attribute__((__packed__)) {\n")
else:
obj.add("#pragma pack(push, 1)\nstruct {")
else:
obj.add("struct {\n")
body
obj.add("} ")
obj.add(fieldName)
obj.add(";\n")
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add("#pragma pack(pop)\n")
template addAnonUnion(obj: var Builder; body: typed) =
## adds an anonymous union i.e. `union { ... };` with fields according to `body`
obj.add "union{\n"
body
obj.add("};\n")

View File

@@ -1,25 +0,0 @@
# XXX make complex ones like bitOr use builder instead
proc ptrType(t: Snippet): Snippet =
t & "*"
const
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
"N_STDCALL", "N_CDECL", "N_SAFECALL",
"N_SYSCALL", # this is probably not correct for all platforms,
# but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
"N_NOCONV" #ccMember is N_NOCONV
]
proc procPtrType(conv: TCallingConvention, rettype: Snippet, name: string): Snippet =
CallingConvToStr[conv] & "_PTR(" & rettype & ", " & name & ")"
proc cCast(typ, value: Snippet): Snippet =
"((" & typ & ") " & value & ")"
proc cAddr(value: Snippet): Snippet =
"&" & value
proc bitOr(a, b: Snippet): Snippet =
"(" & a & " | " & b & ")"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,6 @@
# distribution, for details about the copyright.
#
# included from cgen.nim
## This include file contains the logic to produce constant string
## and seq literals. The code here is responsible that
## ``const x = ["a", "b"]`` works without hidden runtime creation code.
@@ -21,7 +19,7 @@ template detectVersion(field, corename) =
if core == nil or core.kind != skConst:
m.g.field = 1
else:
m.g.field = toInt(ast.getInt(core.astdef))
m.g.field = int ast.getInt(core.ast)
result = m.g.field
proc detectStrVersion(m: BModule): int =
@@ -32,125 +30,79 @@ proc detectSeqVersion(m: BModule): int =
# ----- Version 1: GC'ed strings and seqs --------------------------------
proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
cgsym(m, "TGenericSeq")
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithTypeAndInitializer(AlwaysConst, name = tmp):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "Sup", typ = "TGenericSeq")
res.addArrayField(name = "data", elementType = "NIM_CHAR", len = s.len + 1)
do:
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "Sup"):
var seqInit: StructInitializer
res.addStructInitializer(seqInit, kind = siOrderedStruct):
res.addField(seqInit, name = "len"):
res.add(rope(s.len))
res.addField(seqInit, name = "reserved"):
res.add(cCast("NI", bitOr(cCast("NU", rope(s.len)), "NIM_STRLIT_FLAG")))
res.addField(strInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(res)
proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq")
result = getTempName(m)
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), rope(len(s))])
proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
proc genStringLiteralV1(m: BModule; n: PNode): Rope =
if s.isNil:
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
else:
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var name: string = ""
if id == m.labels:
# string literal not found in the cache:
genStringLiteralDataOnlyV1(m, n.strVal, name)
result = ropecg(m, "((#NimStringDesc*) &$1)",
[genStringLiteralDataOnlyV1(m, n.strVal)])
else:
name = m.tmpBase & $id
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), cAddr(name)))
result = ropecg(m, "((#NimStringDesc*) &$1$2)",
[m.tmpBase, id])
# ------ Version 2: destructor based strings and seqs -----------------------
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
var res = newBuilder("")
res.addVarWithTypeAndInitializer(
if isConst: AlwaysConst else: Global,
name = result):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "cap", typ = "NI")
res.addArrayField(name = "data", elementType = "NIM_CHAR", len = s.len + 1)
do:
var structInit: StructInitializer
res.addStructInitializer(structInit, kind = siOrderedStruct):
res.addField(structInit, name = "cap"):
res.add(bitOr(rope(s.len), "NIM_STRLIT_FLAG"))
res.addField(structInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(res)
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope) =
addf(m.s[cfsData], "static const struct {$n" &
" NI cap; void* allocator; NIM_CHAR data[$2+1];$n" &
"} $1 = { $2, NIM_NIL, $3 };$n",
[result, rope(len(s)), makeCString(s)])
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
proc genStringLiteralV2(m: BModule; n: PNode): Rope =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var litName: string
if id == m.labels:
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
let pureLit = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, pureLit)
result = getTempName(m)
discard cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2")
# string literal not found in the cache:
litName = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, litName, isConst)
addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[result, rope(len(n.strVal)), pureLit])
else:
litName = m.tmpBase & $id
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithTypeAndInitializer(
if isConst: AlwaysConst else: Global,
name = tmp):
res.add("NimStringV2")
do:
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "len"):
res.add(rope(n.strVal.len))
res.addField(strInit, name = "p"):
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
m.s[cfsStrData].add(res)
result = getTempName(m)
addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[result, rope(len(n.strVal)), m.tmpBase & rope(id)])
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
pureLit = getTempName(m)
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
discard cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2")
# string literal not found in the cache:
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
genStringLiteralDataOnlyV2(m, n.strVal, pureLit)
else:
pureLit = m.tmpBase & rope(id)
var strInit: StructInitializer
result.addStructInitializer(strInit, kind = siOrderedStruct):
result.addField(strInit, name = "len"):
result.add(rope(n.strVal.len))
result.addField(strInit, name = "p"):
result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit]
# ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
isConst: bool; result: var Rope) =
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
case detectStrVersion(m)
of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
of 0, 1: result = genStringLiteralDataOnlyV1(m, s)
of 2:
let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
result = getTempName(m)
genStringLiteralDataOnlyV2(m, s, result)
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope =
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
proc genStringLiteral(m: BModule; n: PNode): Rope =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)
of 0, 1: result = genStringLiteralV1(m, n)
of 2: result = genStringLiteralV2(m, n)
else:
localError(m.config, n.info, "cannot determine how to produce code for string literal")

294
compiler/ccgmerge.nim Normal file
View File

@@ -0,0 +1,294 @@
#
#
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the merge operation of 2 different C files. This
## is needed for incremental compilation.
import
ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
intsets, platform, llstream, tables, sighashes, modulegraphs, pathutils
# Careful! Section marks need to contain a tabulator so that they cannot
# be part of C string literals.
const
CFileSectionNames: array[TCFileSection, string] = [
cfsMergeInfo: "",
cfsHeaders: "NIM_merge_HEADERS",
cfsFrameDefines: "NIM_merge_FRAME_DEFINES",
cfsForwardTypes: "NIM_merge_FORWARD_TYPES",
cfsTypes: "NIM_merge_TYPES",
cfsSeqTypes: "NIM_merge_SEQ_TYPES",
cfsFieldInfo: "NIM_merge_FIELD_INFO",
cfsTypeInfo: "NIM_merge_TYPE_INFO",
cfsProcHeaders: "NIM_merge_PROC_HEADERS",
cfsVars: "NIM_merge_VARS",
cfsData: "NIM_merge_DATA",
cfsProcs: "NIM_merge_PROCS",
cfsInitProc: "NIM_merge_INIT_PROC",
cfsDatInitProc: "NIM_merge_DATINIT_PROC",
cfsTypeInit1: "NIM_merge_TYPE_INIT1",
cfsTypeInit2: "NIM_merge_TYPE_INIT2",
cfsTypeInit3: "NIM_merge_TYPE_INIT3",
cfsDebugInit: "NIM_merge_DEBUG_INIT",
cfsDynLibInit: "NIM_merge_DYNLIB_INIT",
cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT",
]
CProcSectionNames: array[TCProcSection, string] = [
cpsLocals: "NIM_merge_PROC_LOCALS",
cpsInit: "NIM_merge_PROC_INIT",
cpsStmts: "NIM_merge_PROC_BODY"
]
NimMergeEndMark = "/*\tNIM_merge_END:*/"
proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = nil
add(result, "\n/*\t")
add(result, CFileSectionNames[fs])
add(result, ":*/\n")
proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & "\n")
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope("")
add(result, "\n/*\t")
add(result, CProcSectionNames[ps])
add(result, ":*/\n")
proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & "\n")
proc writeTypeCache(a: TypeCache, s: var string) =
var i = 0
for id, value in pairs(a):
if i == 10:
i = 0
s.add('\L')
else:
s.add(' ')
encodeStr($id, s)
s.add(':')
encodeStr($value, s)
inc i
s.add('}')
proc writeIntSet(a: IntSet, s: var string) =
var i = 0
for x in items(a):
if i == 10:
i = 0
s.add('\L')
else:
s.add(' ')
encodeVInt(x, s)
inc i
s.add('}')
proc genMergeInfo*(m: BModule): Rope =
if not compilationCachePresent(m.config): return nil
var s = "/*\tNIM_merge_INFO:\n"
s.add("typeCache:{")
writeTypeCache(m.typeCache, s)
s.add("declared:{")
writeIntSet(m.declaredThings, s)
when false:
s.add("typeInfo:{")
writeIntSet(m.typeInfoMarker, s)
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" flags:")
encodeVInt(cast[int](m.flags), s)
s.add("\n*/")
result = s.rope
template `^`(pos: int): untyped = L.buf[pos]
proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
inc pos, 3
break
inc pos
else: inc pos
L.bufpos = pos
proc atEndMark(buf: cstring, pos: int): bool =
var s = 0
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len
proc readVerbatimSection(L: var TBaseLexer): Rope =
var pos = L.bufpos
var r = newStringOfCap(30_000)
while true:
case L.buf[pos]
of CR:
pos = nimlexbase.handleCR(L, pos)
r.add('\L')
of LF:
pos = nimlexbase.handleLF(L, pos)
r.add('\L')
of '\0':
doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(L.buf, pos):
inc pos, NimMergeEndMark.len
break
r.add(L.buf[pos])
inc pos
L.bufpos = pos
result = r.rope
proc readKey(L: var TBaseLexer, result: var string) =
var pos = L.bufpos
setLen(result, 0)
while L.buf[pos] in IdentChars:
result.add(L.buf[pos])
inc pos
if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'
proc newFakeType(id: int): PType =
new(result)
result.id = id
proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
var key = decodeStr(L.buf, L.bufpos)
if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected")
inc L.bufpos
var value = decodeStr(L.buf, L.bufpos)
# XXX implement me
when false:
idTablePut(result, newFakeType(key), value.rope)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
var key = decodeVInt(L.buf, L.bufpos)
result.incl(key)
inc L.bufpos
proc processMergeInfo(L: var TBaseLexer, m: BModule) =
var k = newStringOfCap("typeCache".len)
while true:
skipWhite(L)
if ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
break
readKey(L, k)
case k
of "typeCache": readTypeCache(L, m.typeCache)
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo":
when false: readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "flags":
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
else: doAssert(false, "ccgmerge: unknown key: " & k)
when not defined(nimhygiene):
{.pragma: inject.}
template withCFile(cfilename: AbsoluteFile, body: untyped) =
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer
openBaseLexer(L, s)
var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
while true:
skipUntilCmd(L)
if ^L.bufpos == '\0': break
body
closeBaseLexer(L)
proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) =
## reads the merge meta information into `m`.
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
processMergeInfo(L, m)
break
type
TMergeSections = object
f: TCFileSections
p: TCProcSections
proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) =
## reads the merge sections into `m`.
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
discard
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
# read back into section
skipWhite(L)
var verbatim = readVerbatimSection(L)
skipWhite(L)
var sectionA = CFileSectionNames.find(k)
if sectionA > 0 and sectionA <= high(TCFileSection).int:
m.f[TCFileSection(sectionA)] = verbatim
else:
var sectionB = CProcSectionNames.find(k)
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
doAssert(false, "ccgmerge: unknown section: " & k)
else:
doAssert(false, "ccgmerge: '*/' expected")
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
if m.s[i] != nil:
#echo "not empty: ", i, " ", m.s[i]
return true
for i in low(TCProcSection)..high(TCProcSection):
if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", m.initProc.s[i]
return true
proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
## merges the C file with the old version on hard disc.
var old: TMergeSections
readMergeSections(cfilename, old)
# do the merge; old section before new section:
for i in low(TCFileSection)..high(TCFileSection):
m.s[i] = old.f[i] & m.s[i]
for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = old.p[i] & m.initProc.s(i)

View File

@@ -1,283 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the merge operation of 2 different C files. This
## is needed for incremental compilation.
import
ast, ropes, options, strutils, nimlexbase, cgendata, rodutils,
intsets, llstream, tables, modulegraphs, pathutils
# Careful! Section marks need to contain a tabulator so that they cannot
# be part of C string literals.
const
CFileSectionNames: array[TCFileSection, string] = [
cfsHeaders: "NIM_merge_HEADERS",
cfsFrameDefines: "NIM_merge_FRAME_DEFINES",
cfsForwardTypes: "NIM_merge_FORWARD_TYPES",
cfsTypes: "NIM_merge_TYPES",
cfsSeqTypes: "NIM_merge_SEQ_TYPES",
cfsTypeInfo: "NIM_merge_TYPE_INFO",
cfsProcHeaders: "NIM_merge_PROC_HEADERS",
cfsData: "NIM_merge_DATA",
cfsVars: "NIM_merge_VARS",
cfsProcs: "NIM_merge_PROCS",
cfsInitProc: "NIM_merge_INIT_PROC",
cfsDatInitProc: "NIM_merge_DATINIT_PROC",
cfsTypeInit1: "NIM_merge_TYPE_INIT1",
cfsTypeInit3: "NIM_merge_TYPE_INIT3",
cfsDynLibInit: "NIM_merge_DYNLIB_INIT"
]
CProcSectionNames: array[TCProcSection, string] = [
cpsLocals: "NIM_merge_PROC_LOCALS",
cpsInit: "NIM_merge_PROC_INIT",
cpsStmts: "NIM_merge_PROC_BODY"
]
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")
result.add(CFileSectionNames[fs])
result.add(":*/\n")
proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & "\n")
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope("")
result.add("\n/*\t")
result.add(CProcSectionNames[ps])
result.add(":*/\n")
proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & "\n")
proc writeTypeCache(a: TypeCache, s: var string) =
var i = 0
for id, value in pairs(a):
if i == 10:
i = 0
s.add('\L')
else:
s.add(' ')
encodeStr($id, s)
s.add(':')
encodeStr($value, s)
inc i
s.add('}')
proc writeIntSet(a: IntSet, s: var string) =
var i = 0
for x in items(a):
if i == 10:
i = 0
s.add('\L')
else:
s.add(' ')
encodeVInt(x, s)
inc i
s.add('}')
proc genMergeInfo*(m: BModule): Rope =
if not compilationCachePresent(m.config): return nil
var s = "/*\tNIM_merge_INFO:\n"
s.add("typeCache:{")
writeTypeCache(m.typeCache, s)
s.add("declared:{")
writeIntSet(m.declaredThings, s)
when false:
s.add("typeInfo:{")
writeIntSet(m.typeInfoMarker, s)
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" flags:")
encodeVInt(cast[int](m.flags), s)
s.add("\n*/")
result = s.rope
template `^`(pos: int): untyped = L.buf[pos]
proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
inc pos, 3
break
inc pos
else: inc pos
L.bufpos = pos
proc atEndMark(buf: cstring, pos: int): bool =
var s = 0
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len
proc readVerbatimSection(L: var TBaseLexer): Rope =
var pos = L.bufpos
var r = newStringOfCap(30_000)
while true:
case L.buf[pos]
of CR:
pos = nimlexbase.handleCR(L, pos)
r.add('\L')
of LF:
pos = nimlexbase.handleLF(L, pos)
r.add('\L')
of '\0':
doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(L.buf, pos):
inc pos, NimMergeEndMark.len
break
r.add(L.buf[pos])
inc pos
L.bufpos = pos
result = r.rope
proc readKey(L: var TBaseLexer, result: var string) =
var pos = L.bufpos
setLen(result, 0)
while L.buf[pos] in IdentChars:
result.add(L.buf[pos])
inc pos
if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'
proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
var key = decodeStr(L.buf, L.bufpos)
if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected")
inc L.bufpos
discard decodeStr(L.buf, L.bufpos)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
var key = decodeVInt(L.buf, L.bufpos)
result.incl(key)
inc L.bufpos
proc processMergeInfo(L: var TBaseLexer, m: BModule) =
var k = newStringOfCap("typeCache".len)
while true:
skipWhite(L)
if ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
break
readKey(L, k)
case k
of "typeCache": readTypeCache(L, m.typeCache)
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo":
when false: readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "flags":
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
else: doAssert(false, "ccgmerge: unknown key: " & k)
template withCFile(cfilename: AbsoluteFile, body: untyped) =
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer
openBaseLexer(L, s)
var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
while true:
skipUntilCmd(L)
if ^L.bufpos == '\0': break
body
closeBaseLexer(L)
proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) =
## reads the merge meta information into `m`.
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
processMergeInfo(L, m)
break
type
TMergeSections = object
f: TCFileSections
p: TCProcSections
proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) =
## reads the merge sections into `m`.
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
discard
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
# read back into section
skipWhite(L)
var verbatim = readVerbatimSection(L)
skipWhite(L)
var sectionA = CFileSectionNames.find(k)
if sectionA > 0 and sectionA <= high(TCFileSection).int:
m.f[TCFileSection(sectionA)] = verbatim
else:
var sectionB = CProcSectionNames.find(k)
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
doAssert(false, "ccgmerge: unknown section: " & k)
else:
doAssert(false, "ccgmerge: '*/' expected")
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
if m.s[i] != nil:
#echo "not empty: ", i, " ", m.s[i]
return true
for i in TCProcSection:
if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", m.initProc.s[i]
return true
proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
## merges the C file with the old version on hard disc.
var old: TMergeSections
readMergeSections(cfilename, old)
# do the merge; old section before new section:
for i in TCFileSection:
m.s[i] = old.f[i] & m.s[i]
for i in TCProcSection:
m.initProc.s(i) = old.p[i] & m.initProc.s(i)

View File

@@ -1,105 +0,0 @@
#
#
# 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.snippet == "": 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.snippet])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
specializeResetN(p, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
specializeResetT(p, "$1.$2" % [accessor, disc.loc.snippet], disc.loc.t)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.snippet == "": fillObjectFields(p.module, typ)
if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, "$1.$2" % [accessor, field.loc.snippet], 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, skipModifier(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
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, a in typ.ikids:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), a)
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, tyRange, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tySet:
case mapSetType(p.config, typ)
of ctArray:
lineCg(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n",
[accessor, getTypeDesc(p.module, typ)])
of ctInt8, ctInt16, ctInt32, ctInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
else:
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyError, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
discard
proc specializeReset(p: BProc, a: TLoc) =
specializeResetT(p, rdLoc(a), a.t)

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@
# distribution, for details about the copyright.
#
## Thread var support for architectures that lack native support for
## thread local storage.
## Thread var support for crappy architectures that lack native support for
## thread local storage. (**Thank you Mac OS X!**)
# included from cgen.nim
@@ -16,11 +16,11 @@ proc emulatedThreadVars(conf: ConfigRef): bool =
result = {optThreads, optTlsEmulation} <= conf.globalOptions
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars(p.config) and threadVarAccessed notin p.flags:
p.flags.incl threadVarAccessed
if emulatedThreadVars(p.config) and not p.threadVarAccessed:
p.threadVarAccessed = true
incl p.module.flags, usesThreadVars
p.procSec(cpsLocals).addf("\tNimThreadVars* NimTV_;$n", [])
p.procSec(cpsInit).add(
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n", []))
proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
@@ -30,34 +30,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
# allocator for it :-(
if not containsOrIncl(m.g.nimtvDeclared, s.id):
m.g.nimtvDeps.add(s.loc.t)
m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.snippet])
addf(m.g.nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else:
if isExtern: m.s[cfsVars].add("extern ")
elif lfExportLib in s.loc.flags: m.s[cfsVars].add("N_LIB_EXPORT_VAR ")
else: m.s[cfsVars].add("N_LIB_PRIVATE ")
if optThreads in m.config.globalOptions:
let sym = s.typ.sym
if sym != nil and sfCppNonPod in sym.flags:
m.s[cfsVars].add("NIM_THREAD_LOCAL ")
else: m.s[cfsVars].add("NIM_THREADVAR ")
m.s[cfsVars].add(getTypeDesc(m, s.loc.t))
m.s[cfsVars].addf(" $1;$n", [s.loc.snippet])
if isExtern: add(m.s[cfsVars], "extern ")
if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
addf(m.s[cfsVars], " $1;$n", [s.loc.r])
proc generateThreadLocalStorage(m: BModule) =
if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
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)
var typedef = newBuilder("")
typedef.addTypedef(name = "NimThreadVars"):
typedef.addSimpleStruct(m, name = "", baseType = ""):
typedef.add(m.g.nimtv)
m.s[cfsSeqTypes].add(typedef)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) =
if m.g.nimtv != "":
let externc = if m.config.backend == backendCpp or
if m.g.nimtv != nil:
let externc = if m.config.cmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" "
else: ""
m.s[cfsProcs].addf(
addf(m.s[cfsProcs],
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
[externc.rope])

View File

@@ -17,29 +17,29 @@ type
visitorFrmt: string
const
visitorFrmt = "#nimGCvisit((void*)$1, $2);$n"
visitorFrmt = "#nimGCvisit((void*)$1, $2);$n"
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
typ: PType) =
if n == nil: return
case n.kind
of nkRecList:
for i in 0..<n.len:
genTraverseProc(c, accessor, n[i], typ)
for i in 0 ..< sonsLen(n):
genTraverseProc(c, accessor, n.sons[i], typ)
of nkRecCase:
if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
var p = c.p
let disc = n[0].sym
if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
let disc = n.sons[0].sym
if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
if disc.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
for i in 1..<n.len:
let branch = n[i]
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in 1 ..< sonsLen(n):
let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch)
@@ -51,10 +51,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
if field.loc.r == nil: fillObjectFields(c.p.module, typ)
if field.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()")
genTraverseProc(c, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(c.p.config, n.info, "genTraverseProc()")
proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
@@ -71,40 +71,40 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
case typ.kind
of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
tySink, tyOwned:
genTraverseProc(c, accessor, skipModifier(typ))
genTraverseProc(c, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(c.p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
let arraySize = lengthOrd(c.p.config, typ.sons[0])
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
[i.r, arraySize])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ.sons[1])
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
genTraverseProc(c, accessor.parentObj(c.p.module), x)
for i in 0 ..< sonsLen(typ):
var x = typ.sons[i]
if x != nil: x = x.skipTypes(skipPtrs)
genTraverseProc(c, accessor.parentObj(c.p.module), x)
if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), a)
for i in 0 ..< sonsLen(typ):
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), typ.sons[i])
of tyRef:
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
of tySequence:
if optSeqDestructors notin c.p.module.config.globalOptions:
if tfHasAsgn notin typ.flags:
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
elif containsGarbageCollectedRef(typ.elementType):
elif containsGarbageCollectedRef(typ.lastSon):
# destructor based seqs are themselves not traced but their data is, if
# they contain a GC'ed type:
lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
#genTraverseProcSeq(c, accessor, typ)
genTraverseProcSeq(c, accessor, typ)
of tyString:
if tfHasAsgn notin typ.flags:
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
@@ -117,15 +117,16 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
var a = TLoc(snippet: accessor)
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts)
var a: TLoc
a.r = accessor
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, lenExpr(c.p, a)])
[i.r, lenExpr(c.p, a)])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
@@ -133,6 +134,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
lineF(p, cpsStmts, "}$n", [])
proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = "Marker_" & getTypeName(m, origTyp, sig)
let
@@ -145,19 +147,18 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
lineF(p, cpsLocals, "$1 a;$n", [t])
lineF(p, cpsInit, "a = ($1)p;$n", [t])
var c = TTraversalClosure(p: p,
visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
)
c.p = p
c.visitorFrmt = "op" # "#nimGCvisit((void*)$1, op);$n"
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".rope, typ)
else:
if skipTypes(typ.elementType, typedescInst+{tyOwned}).kind == tyArray:
if skipTypes(typ.sons[0], typedescInst+{tyOwned}).kind == tyArray:
# C's arrays are broken beyond repair:
genTraverseProc(c, "a".rope, typ.elementType)
genTraverseProc(c, "a".rope, typ.sons[0])
else:
genTraverseProc(c, "(*a)".rope, typ.elementType)
genTraverseProc(c, "(*a)".rope, typ.sons[0])
let generatedProc = "$1 {$n$2$3$4}\n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
@@ -166,13 +167,14 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
m.s[cfsProcs].add(generatedProc)
if hcrOn:
m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
addf(m.s[cfsProcHeaders], "N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
addf(m.s[cfsDynLibInit], "\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
[result, markerName, getModuleDllPath(m)])
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfoV1(m, s.loc.t, info)
discard genTypeInfo(m, s.loc.t, info)
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = rdLoc(s.loc)
result = getTempName(m)
@@ -181,10 +183,8 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
accessThreadLocalVar(p, s)
sLoc = "NimTV_->" & sLoc
var c = TTraversalClosure(p: p,
visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n"
)
c.visitorFrmt = "0" # "#nimGCvisit((void*)$1, 0);$n"
c.p = p
let header = "static N_NIMCALL(void, $1)(void)" % [result]
genTraverseProc(c, sLoc, s.loc.t)

File diff suppressed because it is too large Load Diff

View File

@@ -10,27 +10,19 @@
# This module declares some helpers for the C code generator.
import
ast, types, msgs, wordrecg,
platform, trees, options, cgendata, mangleutils
import std/[hashes, strutils, formatfloat]
when defined(nimPreviewSlimSystem):
import std/assertions
ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
platform, trees, options
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
result = nil
for i in 0..<n.len:
for i in 0 ..< n.len:
result = getPragmaStmt(n[i], w)
if result != nil: break
of nkPragma:
result = nil
for i in 0..<n.len:
for i in 0 ..< n.len:
if whichPragma(n[i]) == w: return n[i]
else:
result = nil
else: discard
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
@@ -41,7 +33,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
# we have to use the same bitwidth
# as the target CPU
var b = 0'u64
for i in 0..<s.len:
for i in 0 ..< len(s):
b = b + uint(s[i])
b = b + (b shl 10)
b = b xor (b shr 6)
@@ -51,14 +43,14 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
result = cast[Hash](b)
else:
var a = 0'u32
for i in 0..<s.len:
for i in 0 ..< len(s):
a = a + uint32(s[i])
a = a + (a shl 10)
a = a xor (a shr 6)
a = a + (a shl 3)
a = a xor (a shr 11)
a = a + (a shl 15)
result = cast[Hash](uint(a))
result = cast[Hash](a)
template getUniqueType*(key: PType): PType = key
@@ -68,103 +60,49 @@ proc makeSingleLineCString*(s: string): string =
c.toCChar(result)
result.add('\"')
proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
case int(getSize(conf, typ))
of 1: result = ctInt8
of 2: result = ctInt16
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctArray
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
#note precedence: params override types
if optByRef in s.options: return true
elif sfByCopy in s.flags: return false
elif tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.kind
of tyObject:
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
# forwarded objects are *always* passed by pointers for consistency!
result = true
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
# bug #23354:
result = false
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
result = true # requested anyway
elif (tfFinal in pt.flags) and (pt[0] == nil):
result = false # no need, because no subtyping possible
proc mangle*(name: string): string =
result = newStringOfCap(name.len)
var start = 0
if name[0] in Digits:
result.add("X" & name[0])
start = 1
var requiresUnderscore = false
template special(x) =
result.add x
requiresUnderscore = true
for i in start..(name.len-1):
let c = name[i]
case c
of 'a'..'z', '0'..'9', 'A'..'Z':
add(result, c)
of '_':
# we generate names like 'foo_9' for scope disambiguations and so
# disallow this here:
if i > 0 and i < name.len-1 and name[i+1] in Digits:
discard
else:
add(result, c)
of '$': special "dollar"
of '%': special "percent"
of '&': special "amp"
of '^': special "roof"
of '!': special "emark"
of '?': special "qmark"
of '*': special "star"
of '+': special "plus"
of '-': special "minus"
of '/': special "slash"
of '\\': special "backslash"
of '=': special "eq"
of '<': special "lt"
of '>': special "gt"
of '~': special "tilde"
of ':': special "colon"
of '.': special "dot"
of '@': special "at"
of '|': special "bar"
else:
result = true # ordinary objects are always passed by reference,
# otherwise casting doesn't work
of tyTuple:
result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
else:
result = false
# first parameter and return type is 'lent T'? --> use pass by pointer
if s.position == 0 and retType != nil and retType.kind == tyLent:
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind
add(result, "X" & toHex(ord(c), 2))
requiresUnderscore = true
if requiresUnderscore:
result.add "_"

File diff suppressed because it is too large Load Diff

View File

@@ -10,14 +10,13 @@
## This module contains the data structures for the C code generation phase.
import
ast, ropes, options,
ndi, lineinfos, pathutils, modulegraphs
import std/[intsets, tables, sets]
ast, astalgo, ropes, passes, options, intsets, platform, sighashes,
tables, ndi, lineinfos, pathutils, modulegraphs
type
TLabel* = Rope # for the C generator a label is just a rope
TCFileSection* = enum # the sections a generated C file consists of
cfsMergeInfo, # section containing merge information
cfsHeaders, # section for C include file headers
cfsFrameDefines # section for nim frame macros
cfsForwardTypes, # section for C forward typedefs
@@ -25,17 +24,21 @@ type
cfsSeqTypes, # section for sequence types only
# this is needed for strange type generation
# reasons
cfsTypeInfo, # section for type information (ag ABI checks)
cfsFieldInfo, # section for field information
cfsTypeInfo, # section for type information
cfsProcHeaders, # section for C procs prototypes
cfsStrData, # section for constant string literals
cfsData, # section for C constant data
cfsVars, # section for C variable declarations
cfsData, # section for C constant data
cfsProcs, # section for C procs that are not inline
cfsInitProc, # section for the C init proc
cfsDatInitProc, # section for the C datInit proc
cfsTypeInit1, # section 1 for declarations of type information
cfsTypeInit2, # section 2 for init of type information
cfsTypeInit3, # section 3 for init of type information
cfsDebugInit, # section for init of debug information
cfsDynLibInit, # section for init of dynamic library binding
cfsDynLibDeinit # section for deinitialization of dynamic
# libraries
TCTypeKind* = enum # describes the type kind of a C type
ctVoid, ctChar, ctBool,
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
@@ -55,27 +58,22 @@ type
id*: int # the ID of the label; positive means that it
label*: Rope # generated text for the label
# nil if label is not used
sections*: TCProcSections # the code belonging
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16
TCProcFlag* = enum
beforeRetNeeded,
threadVarAccessed,
hasCurFramePointer,
noSafePoints,
nimErrorFlagAccessed,
nimErrorFlagDeclared,
nimErrorFlagDisabled
TCProc = object # represents C proc that is currently generated
prc*: PSym # the Nim proc that this C proc belongs to
flags*: set[TCProcFlag]
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after
# exception is generated
noSafePoints*: bool # the proc doesn't use safe points in exception handling
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
currLineInfo*: TLineInfo # AST codegen will make this superfluous
nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool, label: Natural]]
nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
# in how many nested try statements we are
# (the vars must be volatile then)
# bool is true when are in the except part of a try block
@@ -88,20 +86,19 @@ type
options*: TOptions # options that should be used for code
# generation; this is the same as prc.options
# unless prc == nil
optionsStack*: seq[(TOptions, TNoteKinds)]
maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
splitDecls*: int # > 0 if we are in some context for C++ that
# 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
gcFrameId*: Natural # for the GC stack marking
gcFrameType*: Rope # the struct {} we put the GC markers into
sigConflicts*: CountTable[string]
inUncheckedAssignSection*: int
TTypeSeq* = seq[PType]
TypeCache* = Table[SigHash, Rope]
TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]]
TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: PSym]]
CodegenFlag* = enum
preventStackTrace, # true if stack traces need to be prevented
@@ -111,8 +108,7 @@ type
isHeaderFile, # C source file is the header file
includesStringh, # C source file already includes ``<string.h>``
objHasKidsValid # whether we can rely on tfObjHasKids
useAliveDataFromDce # use the `alive: IntSet` field instead of
# computing alive data on our own.
BModuleList* = ref object of RootObj
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
@@ -121,8 +117,9 @@ type
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
generatedHeader*: BModule
breakPointId*: int
breakpoints*: Rope # later the breakpoints are inserted into the main proc
typeInfoMarker*: TypeCacheWithOwner
typeInfoMarkerV2*: TypeCacheWithOwner
config*: ConfigRef
graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use
@@ -137,7 +134,6 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -148,21 +144,15 @@ 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 occurrence 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
alive*: IntSet # symbol IDs of alive data as computed by `dce.nim`
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
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
inHcrInitGuard*: bool # We are currently withing a HCR reloading guard.
typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable
typeNodes*, nimTypes*: int # used for type info generation
@@ -170,13 +160,13 @@ type
labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', Rope] # special procs for the
# OpenGL wrapper
injectStmt*: Rope
sigConflicts*: CountTable[SigHash]
g*: BModuleList
ndi*: NdiFile
template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
@@ -184,32 +174,25 @@ proc includeHeader*(this: BModule; header: string) =
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block
result = p.blocks[^1].sections[s]
result = p.blocks[p.blocks.len-1].sections[s]
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections
result = p.blocks[0].sections[s]
proc initBlock*(): TBlock =
result = TBlock()
for i in low(result.sections)..high(result.sections):
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(
prc: prc,
module: module,
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: if prc != nil: prc.options
else: module.config.options,
blocks: @[initBlock()],
sigConflicts: initCountTable[string]())
if optQuirky in result.options:
result.flags = {nimErrorFlagDisabled}
new(result)
result.prc = prc
result.module = module
if prc != nil: result.options = prc.options
else: result.options = module.config.options
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]()
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: PSym]](),
config: g.config, graph: g, nimtvDeclared: initIntSet())
iterator cgenModules*(g: BModuleList): BModule =

View File

@@ -7,18 +7,11 @@
# distribution, for details about the copyright.
#
## This module implements code generation for methods.
## This module implements code generation for multi methods.
import
options, ast, msgs, idents, renderer, types, magicsys,
sempass2, modulegraphs, lineinfos, astalgo
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[tables]
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
sempass2, strutils, modulegraphs, lineinfos
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
var dest = skipTypes(d, abstractPtrs)
@@ -30,11 +23,11 @@ proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
result = n
elif diff < 0:
result = newNodeIT(nkObjUpConv, n.info, d)
result.add n
addSon(result, n)
if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed")
elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, d)
result.add n
addSon(result, n)
if not downcast:
internalError(conf, n.info, "cgmeth.genConv: no downcast allowed")
else:
@@ -47,45 +40,39 @@ proc getDispatcher*(s: PSym): PSym =
if dispatcherPos < s.ast.len:
result = s.ast[dispatcherPos].sym
doAssert sfDispatcher in result.flags
else:
result = nil
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
# replace ordinary method by dispatcher method:
let disp = getDispatcher(result[0].sym)
let disp = getDispatcher(result.sons[0].sym)
if disp != nil:
result[0].typ() = disp.typ
result[0].sym = disp
result.sons[0].sym = disp
# change the arguments to up/downcasts to fit the dispatcher's parameters:
for i in 1..<result.len:
result[i] = genConv(result[i], disp.typ[i], true, conf)
for i in 1 ..< sonsLen(result):
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
else:
localError(conf, n.info, "'" & $result[0] & "' lacks a dispatcher")
localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
type
MethodResult = enum No, Invalid, Yes
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.signatureLen != b.typ.signatureLen:
if sonsLen(a.typ) != sonsLen(b.typ):
return
var i = 0
for x, y in paramTypePairs(a.typ, b.typ):
inc i
var aa = x
var bb = y
for i in 1 ..< sonsLen(a.typ):
var aa = a.typ.sons[i]
var bb = b.typ.sons[i]
while true:
aa = skipTypes(aa, {tyGenericInst, tyAlias})
bb = skipTypes(bb, {tyGenericInst, tyAlias})
if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent, tySink}:
aa = aa.elementType
bb = bb.elementType
if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}:
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(x, y):
if sameType(a.typ.sons[i], b.typ.sons[i]):
if aa.kind == tyObject and result != Invalid:
result = Yes
elif aa.kind == tyObject and bb.kind == tyObject and (i == 1 or multiMethods):
@@ -103,45 +90,41 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
return No
if result == Yes:
# check for return type:
# ignore flags of return types; # bug #22673
if not sameTypeOrNil(a.typ.returnType, b.typ.returnType, {IgnoreFlags}):
if b.typ.returnType != nil and b.typ.returnType.kind == tyUntyped:
if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]):
if b.typ.sons[0] != nil and b.typ.sons[0].kind == tyUntyped:
# infer 'auto' from the base to make it consistent:
b.typ.setReturnType a.typ.returnType
b.typ.sons[0] = a.typ.sons[0]
else:
return No
proc attachDispatcher(s: PSym, dispatcher: PNode) =
if dispatcherPos < s.ast.len:
# we've added a dispatcher already, so overwrite it
s.ast[dispatcherPos] = dispatcher
s.ast.sons[dispatcherPos] = dispatcher
else:
setLen(s.ast.sons, dispatcherPos+1)
if s.ast[resultPos] == nil:
s.ast[resultPos] = newNodeI(nkEmpty, s.info)
s.ast[dispatcherPos] = dispatcher
s.ast.sons[dispatcherPos] = dispatcher
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
var disp = copySym(s, idgen)
proc createDispatcher(s: PSym): PSym =
var disp = copySym(s)
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
copyTypeProps(g, idgen.module, disp.typ, old)
disp.typ = copyType(disp.typ, disp.typ.owner, false)
# we can't inline the dispatcher itself (for now):
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.snippet = ""
if s.typ.returnType != nil:
if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil
if s.typ.sons[0] != nil:
if disp.ast.sonsLen > resultPos:
disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym)
else:
# We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will
# be updated in fixupDispatcher().
disp.ast.add newNodeI(nkEmpty, s.info)
disp.ast.addSon(newNodeI(nkEmpty, s.info))
attachDispatcher(s, newSymNode(disp))
# attach to itself to prevent bugs:
attachDispatcher(disp, newSymNode(disp))
@@ -153,25 +136,35 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
# from later definitions, particularly the resultPos slot. Also,
# the lock level of the dispatcher needs to be updated/checked
# against that of the method.
if disp.ast.len > resultPos and meth.ast.len > resultPos and
disp.ast[resultPos].kind == nkEmpty:
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and
disp.ast.sons[resultPos].kind == nkEmpty:
disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos])
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym = nil
if s.typ.firstParamType.owner.getModule != s.getModule and vtables in g.config.features and not
g.config.isDefined("nimInternalNonVtablesTesting"):
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` can be defined only in the same module with its type (" & s.typ.firstParamType.typeToString() & ")")
if sfImportc in s.flags:
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` is not allowed to have 'importc' pragmas")
# The following code works only with lock levels, so we disable
# it when they're not available.
when declared(TLockLevel):
proc `<`(a, b: TLockLevel): bool {.borrow.}
proc `==`(a, b: TLockLevel): bool {.borrow.}
if disp.typ.lockLevel == UnspecifiedLockLevel:
disp.typ.lockLevel = meth.typ.lockLevel
elif meth.typ.lockLevel != UnspecifiedLockLevel and
meth.typ.lockLevel != disp.typ.lockLevel:
message(conf, meth.info, warnLockLevel,
"method has lock level $1, but another method has $2" %
[$meth.typ.lockLevel, $disp.typ.lockLevel])
# XXX The following code silences a duplicate warning in
# checkMethodeffects() in sempass2.nim for now.
if disp.typ.lockLevel < meth.typ.lockLevel:
disp.typ.lockLevel = meth.typ.lockLevel
for i in 0..<g.methods.len:
proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
let L = len(g.methods)
var witness: PSym
for i in 0 ..< L:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
of Yes:
g.methods[i].methods.add(s)
add(g.methods[i].methods, s)
attachDispatcher(s, disp.ast[dispatcherPos])
fixupDispatcher(s, disp, g.config)
#echo "fixup ", disp.name.s, " ", disp.id
@@ -185,49 +178,44 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
of Invalid:
if witness.isNil: witness = g.methods[i].methods[0]
# create a new dispatcher:
# stores the id and the position
if s.typ.firstParamType.skipTypes(skipPtrs).itemId notin g.bucketTable:
g.bucketTable[s.typ.firstParamType.skipTypes(skipPtrs).itemId] = 1
else:
g.bucketTable.inc(s.typ.firstParamType.skipTypes(skipPtrs).itemId)
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
add(g.methods, (methods: @[s], dispatcher: createDispatcher(s)))
#echo "adding ", s.info
#if fromCache:
# internalError(s.info, "no method dispatcher found")
if witness != nil:
localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
"' to method defined here: " & g.config$witness.info)
elif sfBase notin s.flags:
message(g.config, s.info, warnUseBase)
proc relevantCol*(methods: seq[PSym], col: int): bool =
proc relevantCol(methods: seq[PSym], col: int): bool =
# returns true iff the position is relevant
result = false
var t = methods[0].typ[col].skipTypes(skipPtrs)
var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in 1..high(methods):
let t2 = skipTypes(methods[i].typ[col], skipPtrs)
for i in 1 .. high(methods):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not sameType(t2, t):
return true
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in FirstParamAt..<a.typ.signatureLen:
for col in 1 ..< sonsLen(a.typ):
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
var bb = skipTypes(b.typ[col], skipPtrs)
var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb)
if (d != high(int)) and d != 0:
return d
proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
# we use shellsort here; fast and simple
var n = a.len
var n = len(a)
var h = 1
while true:
h = 3 * h + 1
if h > n: break
while true:
h = h div 3
for i in h..<n:
for i in h ..< n:
var v = a[i]
var j = i
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
@@ -237,72 +225,74 @@ proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.signatureLen
var paramLen = sonsLen(base.typ)
var nilchecks = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)
var ands = getSysMagic(g, unknownLineInfo, "and", mAnd)
var iss = getSysMagic(g, unknownLineInfo, "of", mOf)
let boolType = getSysType(g, unknownLineInfo, tyBool)
for col in FirstParamAt..<paramLen:
var ands = getSysMagic(g, unknownLineInfo(), "and", mAnd)
var iss = getSysMagic(g, unknownLineInfo(), "of", mOf)
let boolType = getSysType(g, unknownLineInfo(), tyBool)
for col in 1 ..< paramLen:
if contains(relevantCols, col):
let param = base.typ.n[col].sym
let param = base.typ.n.sons[col].sym
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
nilchecks.add newTree(nkCall,
newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param))
for meth in 0..high(methods):
addSon(nilchecks, newTree(nkCall,
newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param)))
for meth in 0 .. high(methods):
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in FirstParamAt..<paramLen:
for col in 1 ..< paramLen:
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, boolType)
isn.add newSymNode(iss)
let param = base.typ.n[col].sym
isn.add newSymNode(param)
isn.add newNodeIT(nkType, base.info, curr.typ[col])
addSon(isn, newSymNode(iss))
let param = base.typ.n.sons[col].sym
addSon(isn, newSymNode(param))
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
if cond != nil:
var a = newNodeIT(nkCall, base.info, boolType)
a.add newSymNode(ands)
a.add cond
a.add isn
addSon(a, newSymNode(ands))
addSon(a, cond)
addSon(a, isn)
cond = a
else:
cond = isn
let retTyp = base.typ.returnType
let retTyp = base.typ.sons[0]
let call = newNodeIT(nkCall, base.info, retTyp)
call.add newSymNode(curr)
for col in 1..<paramLen:
call.add genConv(newSymNode(base.typ.n[col].sym),
curr.typ[col], false, g.config)
addSon(call, newSymNode(curr))
for col in 1 ..< paramLen:
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
curr.typ.sons[col], false, g.config))
var ret: PNode
if retTyp != nil:
var a = newNodeI(nkFastAsgn, base.info)
a.add newSymNode(base.ast[resultPos].sym)
a.add call
addSon(a, newSymNode(base.ast.sons[resultPos].sym))
addSon(a, call)
ret = newNodeI(nkReturnStmt, base.info)
ret.add a
addSon(ret, a)
else:
ret = call
if cond != nil:
var a = newNodeI(nkElifBranch, base.info)
a.add cond
a.add ret
disp.add a
addSon(a, cond)
addSon(a, ret)
addSon(disp, a)
else:
disp = ret
nilchecks.add disp
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
result.ast.sons[bodyPos] = nilchecks
proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
for bucket in 0..<g.methods.len:
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
result = newNode(nkStmtList)
for bucket in 0 ..< len(g.methods):
var relevantCols = initIntSet()
for col in FirstParamAt..<g.methods[bucket].methods[0].typ.signatureLen:
for col in 1 ..< sonsLen(g.methods[bucket].methods[0].typ):
if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
if optMultiMethods notin g.config.globalOptions:
# if multi-methods are not enabled, we are interested only in the first field
break
sortBucket(g.methods[bucket].methods, relevantCols)
g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, idgen)
addSon(result,
newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols)))

File diff suppressed because it is too large Load Diff

View File

@@ -7,33 +7,18 @@
# distribution, for details about the copyright.
#
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix
import
options, idents, nimconf, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, pathutils
import std/[os, parseopt]
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
options, idents, nimconf, scriptconfig, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, os, pathutils
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)
@@ -41,45 +26,68 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
self.processCmdLine(passCmd1, "", conf)
if conf.projectIsCmd and conf.projectName in ["-", ""]:
handleCmdInput(conf)
elif self.supportsStdinFile and conf.projectName == "-":
handleStdinInput(conf)
if self.supportsStdinFile and conf.projectName == "-":
conf.projectName = "stdinfile"
conf.projectFull = AbsoluteFile "stdinfile"
conf.projectPath = AbsoluteDir getCurrentDir()
conf.projectIsStdin = true
elif conf.projectName != "":
setFromProjectName(conf, conf.projectName)
try:
conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName)
except OSError:
conf.projectFull = AbsoluteFile conf.projectName
let p = splitFile(conf.projectFull)
let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir)
conf.projectName = p.name
else:
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir())
proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: ConfigRef;
graph: ModuleGraph): bool =
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
loadConfigs(DefaultConfig, cache, conf) # load all config files
if self.suggestMode:
conf.setCmd cmdIdeTools
if conf.cmd == cmdNimscript:
incl(conf.globalOptions, optWasNimscript)
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
# restores `conf.notes` after loading config files
# because it has overwrites the notes when compiling the system module which
# is a foreign module compared to the project
if conf.cmd in cmdBackends:
conf.notes = conf.mainPackageNotes
conf.command = "nimsuggest"
if not self.suggestMode:
template runNimScriptIfExists(path: AbsoluteFile) =
let p = path # eval once
if fileExists(p):
runNimScript(cache, p, freshDefines = false, conf)
# Caution: make sure this stays in sync with `loadConfigs`
if optSkipSystemConfigFile notin conf.globalOptions:
runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims))
if optSkipUserConfigFile notin conf.globalOptions:
runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(conf.projectPath.string, fromRoot = true, inclusive = false):
runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims)
if optSkipProjConfigFile notin conf.globalOptions:
runNimScriptIfExists(conf.projectPath / DefaultConfigNims)
block:
let scriptFile = conf.projectFull.changeFileExt("nims")
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile == conf.projectFull:
if conf.cmd == cmdNone: conf.setCmd cmdNimscript
if conf.cmd == cmdNimscript: return false
if not self.suggestMode:
runNimScriptIfExists(scriptFile)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile == conf.projectFull:
return false
else:
if scriptFile != conf.projectFull:
runNimScriptIfExists(scriptFile)
else:
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file
discard
# now process command line arguments again, because some options in the
# command line can overwrite the config file's settings
if conf.backend != backendJs: # bug #19059
extccomp.initVars(conf)
# command line can overwite the config file's settings
extccomp.initVars(conf)
self.processCmdLine(passCmd2, "", conf)
if conf.cmd == cmdNone:
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
let graph = newModuleGraph(cache, conf)
graph.suggestMode = self.suggestMode
self.mainCommand(graph)
return true
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef; graph: ModuleGraph): bool =
## Alias for loadConfigsAndProcessCmdLine, here for backwards compatibility
loadConfigsAndProcessCmdLine(self, cache, conf, graph)

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
include "../lib/system/compilation.nim"
version = $NimMajor & "." & $NimMinor & "." & $NimPatch
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
skipDirs = @["."]
installDirs = @["compiler"]
import os
var compilerDir = ""
before install:
rmDir("compiler")
let
files = listFiles(".")
dirs = listDirs(".")
mkDir("compiler")
for f in files:
cpFile(f, "compiler" / f)
for d in dirs:
cpDir(d, "compiler" / d)
requires "nim"

View File

@@ -1,343 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## New styled concepts for Nim. See https://github.com/nim-lang/RFCs/issues/168
## for details. Note this is a first implementation and only the "Concept matching"
## section has been implemented.
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
const
logBindings = false
## Code dealing with Concept declarations
## --------------------------------------
proc declareSelf(c: PContext; info: TLineInfo) =
## Adds the magical 'Self' symbols to the current scope.
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
s.typ = newType(tyTypeDesc, c.idgen, ow)
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, c.idgen, ow)
addDecl(c, s, info)
proc semConceptDecl(c: PContext; n: PNode): PNode =
## Recursive helper for semantic checking for the concept declaration.
## Currently we only support (possibly empty) lists of statements
## containing 'proc' declarations and the like.
case n.kind
of nkStmtList, nkStmtListExpr:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = semConceptDecl(c, n[i])
of nkProcDef..nkIteratorDef, nkFuncDef:
result = c.semExpr(c, n, {efWantStmt})
of nkTypeClassTy:
result = shallowCopy(n)
for i in 0..<n.len-1:
result[i] = n[i]
result[^1] = semConceptDecl(c, n[^1])
of nkCommentStmt:
result = n
else:
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
result = n
proc semConceptDeclaration*(c: PContext; n: PNode): PNode =
## Semantic checking for the concept declaration. Runs
## when we process the concept itself, not its matching process.
assert n.kind == nkTypeClassTy
inc c.inConceptDecl
openScope(c)
declareSelf(c, n.info)
result = semConceptDecl(c, n)
rawCloseScope(c)
dec c.inConceptDecl
## Concept matching
## ----------------
type
MatchCon = object ## Context we pass around during concept matching.
inferred: seq[(PType, PType)] ## we need a seq here so that we can easily undo inferences \
## that turned out to be wrong.
marker: IntSet ## Some protection against wild runaway recursions.
potentialImplementation: PType ## the concrete type that might match the concept we try to match.
magic: TMagic ## mArrGet and mArrPut is wrong in system.nim and
## cannot be fixed that easily.
## Thus we special case it here.
proc existingBinding(m: MatchCon; key: PType): PType =
## checks if we bound the type variable 'key' already to some
## concrete type.
for i in 0..<m.inferred.len:
if m.inferred[i][0] == key: return m.inferred[i][1]
return nil
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool
proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
## The heart of the concept matching process. 'f' is the formal parameter of some
## routine inside the concept that we're looking for. 'a' is the formal parameter
## of a routine that might match.
const
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyGenericInst, tyAlias, tyInferred}
case f.kind
of tyAlias:
result = matchType(c, f.skipModifier, a, m)
of tyTypeDesc:
if isSelf(f):
#let oldLen = m.inferred.len
result = matchType(c, a, m.potentialImplementation, m)
#echo "self is? ", result, " ", a.kind, " ", a, " ", m.potentialImplementation, " ", m.potentialImplementation.kind
#m.inferred.setLen oldLen
#echo "A for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
else:
if a.kind == tyTypeDesc and f.hasElementType == a.hasElementType:
if f.hasElementType:
result = matchType(c, f.elementType, a.elementType, m)
else:
result = true # both lack it
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a.genericHead.kind == tyGenericBody:
if sameType(f.genericHead, a.genericHead) and f.kidsLen == a.kidsLen-1:
for i in FirstGenericParamAt ..< f.kidsLen:
if not matchType(c, f[i], a[i], m): return false
return true
of tyGenericParam:
let ak = a.skipTypes({tyVar, tySink, tyLent, tyOwned})
if ak.kind in {tyTypeDesc, tyStatic} and not isSelf(ak):
result = false
else:
let old = existingBinding(m, f)
if old == nil:
if f.hasElementType and f.elementType.kind != tyNone:
# also check the generic's constraints:
let oldLen = m.inferred.len
result = matchType(c, f.elementType, a, m)
m.inferred.setLen oldLen
if result:
when logBindings: echo "A adding ", f, " ", ak
m.inferred.add((f, ak))
elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}:
when logBindings: echo "B adding ", f, " ", lastSon ak
m.inferred.add((f, last ak))
result = true
else:
when logBindings: echo "C adding ", f, " ", ak
m.inferred.add((f, ak))
#echo "binding ", typeToString(ak), " to ", typeToString(f)
result = true
elif not m.marker.containsOrIncl(old.id):
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f.elementType, a.elementType, m)
elif m.magic == mArrPut:
result = matchType(c, f.elementType, a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
result = sameType(f, a)
of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid:
result = a.skipTypes(ignorableForArgType).kind == f.kind
of tyBool, tyChar, tyInt..tyUInt64:
let ak = a.skipTypes(ignorableForArgType)
result = ak.kind == f.kind or ak.kind == tyOrdinal or
(ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal)
of tyConcept:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
if not result:
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
# ^ XXX Rewrite this logic, it's more complex than it needs to be.
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
for i in 0..<ak.kidsLen:
if not matchType(c, f[i], ak[i], m): return false
return true
of tyOr:
let oldLen = m.inferred.len
if a.kind == tyOr:
# say the concept requires 'int|float|string' if the potentialImplementation
# says 'int|string' that is good enough.
var covered = 0
for ff in f.kids:
for aa in a.kids:
let oldLenB = m.inferred.len
let r = matchType(c, ff, aa, m)
if r:
inc covered
break
m.inferred.setLen oldLenB
result = covered >= a.kidsLen
if not result:
m.inferred.setLen oldLen
else:
result = false
for ff in f.kids:
result = matchType(c, ff, a, m)
if result: break # and remember the binding!
m.inferred.setLen oldLen
of tyNot:
if a.kind == tyNot:
result = matchType(c, f.elementType, a.elementType, m)
else:
let oldLen = m.inferred.len
result = not matchType(c, f.elementType, a, m)
m.inferred.setLen oldLen
of tyAnything:
result = true
of tyOrdinal:
result = isOrdinalType(a, allowEnumWithHoles = false) or a.kind == tyGenericParam
else:
result = false
proc matchReturnType(c: PContext; f, a: PType; m: var MatchCon): bool =
## Like 'matchType' but with extra logic dealing with proc return types
## which can be nil or the 'void' type.
if f.isEmptyType:
result = a.isEmptyType
elif a == nil:
result = false
else:
result = matchType(c, f, a, m)
proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
## Checks if 'candidate' matches 'n' from the concept body. 'n' is a nkProcDef
## or similar.
# watch out: only add bindings after a completely successful match.
let oldLen = m.inferred.len
let can = candidate.typ.n
let con = n[0].sym.typ.n
if can.len < con.len:
# too few arguments, cannot be a match:
return false
let common = min(can.len, con.len)
for i in 1 ..< common:
if not matchType(c, con[i].typ, can[i].typ, m):
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ.returnType, candidate.typ.returnType, m):
m.inferred.setLen oldLen
return false
# all other parameters have to be optional parameters:
for i in common ..< can.len:
assert can[i].kind == nkSym
if can[i].sym.ast == nil:
# has too many arguments one of which is not optional:
m.inferred.setLen oldLen
return false
return true
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
## 'n' is the nkProcDef or similar from the concept that we try to match.
let candidates = searchInScopesAllCandidatesFilterBy(c, n[namePos].sym.name, kinds)
for candidate in candidates:
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
m.magic = candidate.magic
if matchSym(c, candidate, n, m): return true
result = false
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
## Traverse the concept's AST ('n') and see if every declaration inside 'n'
## can be matched with the current scope.
case n.kind
of nkStmtList, nkStmtListExpr:
for i in 0..<n.len:
if not conceptMatchNode(c, n[i], m):
return false
return true
of nkProcDef, nkFuncDef:
# procs match any of: proc, template, macro, func, method, converter.
# The others are more specific.
# XXX: Enforce .noSideEffect for 'nkFuncDef'? But then what are the use cases...
const filter = {skProc, skTemplate, skMacro, skFunc, skMethod, skConverter}
result = matchSyms(c, n, filter, m)
of nkTemplateDef:
result = matchSyms(c, n, {skTemplate}, m)
of nkMacroDef:
result = matchSyms(c, n, {skMacro}, m)
of nkConverterDef:
result = matchSyms(c, n, {skConverter}, m)
of nkMethodDef:
result = matchSyms(c, n, {skMethod}, m)
of nkIteratorDef:
result = matchSyms(c, n, {skIterator}, m)
of nkCommentStmt:
result = true
else:
# error was reported earlier.
result = false
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType): bool =
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
## (typeVar, instance) pairs. ('typeVar' is usually simply written as a generic 'T'.)
## 'invocation' can be nil for atomic concepts. For non-atomic concepts, it contains the
## `C[S, T]` parent type that we look for. We need this because we need to store bindings
## for 'S' and 'T' inside 'bindings' on a successful match. It is very important that
## we do not add any bindings at all on an unsuccessful match!
var m = MatchCon(inferred: @[], potentialImplementation: arg)
result = conceptMatchNode(c, concpt.n.lastSon, m)
if result:
for (a, b) in m.inferred:
if b.kind == tyGenericParam:
var dest = b
while true:
dest = existingBinding(m, dest)
if dest == nil or dest.kind != tyGenericParam: break
if dest != nil:
bindings.put(a, dest)
when logBindings: echo "A bind ", a, " ", dest
else:
bindings.put(a, b)
when logBindings: echo "B bind ", a, " ", b
# we have a match, so bind 'arg' itself to 'concpt':
bindings.put(concpt, arg)
# invocation != nil means we have a non-atomic concept:
if invocation != nil and arg.kind == tyGenericInst and invocation.kidsLen == arg.kidsLen-1:
# bind even more generic parameters
assert invocation.kind == tyGenericInvocation
for i in FirstGenericParamAt ..< invocation.kidsLen:
bindings.put(invocation[i], arg[i])

View File

@@ -10,10 +10,10 @@
# This module handles the conditional symbols.
import
std/strtabs
strtabs, platform, strutils, idents
from options import Feature
from lineinfos import hintMin, hintMax, warnMin, warnMax
from lineinfos import HintsToStr, WarningsToStr
proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
symbols[symbol] = value
@@ -25,7 +25,7 @@ proc undefSymbol*(symbols: StringTableRef; symbol: string) =
# result = if isDefined(symbol): gSymbols[symbol] else: nil
iterator definedSymbolNames*(symbols: StringTableRef): string =
for key in keys(symbols):
for key, val in pairs(symbols):
yield key
proc countDefinedSymbols*(symbols: StringTableRef): int =
@@ -34,139 +34,66 @@ proc countDefinedSymbols*(symbols: StringTableRef): int =
proc initDefines*(symbols: StringTableRef) =
# for bootstrapping purposes and old code:
template defineSymbol(s) = symbols.defineSymbol(s)
defineSymbol("nimhygiene") # deadcode
defineSymbol("niminheritable") # deadcode
defineSymbol("nimmixin") # deadcode
defineSymbol("nimeffects") # deadcode
defineSymbol("nimbabel") # deadcode
defineSymbol("nimcomputedgoto") # deadcode
defineSymbol("nimunion") # deadcode
defineSymbol("nimnewshared") # deadcode
defineSymbol("nimNewTypedesc") # deadcode
defineSymbol("nimrequiresnimframe") # deadcode
defineSymbol("nimparsebiggestfloatmagic") # deadcode
defineSymbol("nimlocks") # deadcode
defineSymbol("nimnode") # deadcode
defineSymbol("nimvarargstyped") # deadcode
defineSymbol("nimtypedescfixed") # deadcode
defineSymbol("nimKnowsNimvm") # deadcode
defineSymbol("nimArrIdx") # deadcode
defineSymbol("nimHasalignOf") # deadcode
defineSymbol("nimDistros") # deadcode
defineSymbol("nimHasCppDefine") # deadcode
defineSymbol("nimGenericInOutFlags") # deadcode
when false: defineSymbol("nimHasOpt") # deadcode
defineSymbol("nimNoArrayToCstringConversion") # deadcode
defineSymbol("nimHasRunnableExamples") # deadcode
defineSymbol("nimNewDot") # deadcode
defineSymbol("nimHasNilChecks") # deadcode
defineSymbol("nimSymKind") # deadcode
defineSymbol("nimVmEqIdent") # deadcode
defineSymbol("nimNoNil") # deadcode
defineSymbol("nimNoZeroTerminator") # deadcode
defineSymbol("nimNotNil") # deadcode
defineSymbol("nimVmExportFixed") # deadcode
defineSymbol("nimHasSymOwnerInMacro") # deadcode
defineSymbol("nimNewRuntime") # deadcode
defineSymbol("nimIncrSeqV3") # deadcode
defineSymbol("nimAshr") # deadcode
defineSymbol("nimNoNilSeqs") # deadcode
defineSymbol("nimNoNilSeqs2") # deadcode
defineSymbol("nimHasUserErrors") # deadcode
defineSymbol("nimUncheckedArrayTyp") # deadcode
defineSymbol("nimHasTypeof") # deadcode
defineSymbol("nimErrorProcCanHaveBody") # deadcode
defineSymbol("nimHasInstantiationOfInMacro") # deadcode
defineSymbol("nimHasHotCodeReloading") # deadcode
defineSymbol("nimHasNilSeqs") # deadcode
defineSymbol("nimHasSignatureHashInMacro") # deadcode
defineSymbol("nimHasDefault") # deadcode
defineSymbol("nimMacrosSizealignof") # deadcode
defineSymbol("nimNoZeroExtendMagic") # deadcode
defineSymbol("nimMacrosGetNodeId") # deadcode
defineSymbol("nimFixedForwardGeneric") # deadcode
defineSymbol("nimToOpenArrayCString") # deadcode
defineSymbol("nimHasUsed") # deadcode
defineSymbol("nimnomagic64") # deadcode
defineSymbol("nimNewShiftOps") # deadcode
defineSymbol("nimHasCursor") # deadcode
defineSymbol("nimAlignPragma") # deadcode
defineSymbol("nimHasExceptionsQuery") # deadcode
defineSymbol("nimHasIsNamedTuple") # deadcode
defineSymbol("nimHashOrdinalFixed") # deadcode
defineSymbol("nimHasSinkInference") # deadcode
defineSymbol("nimNewIntegerOps") # deadcode
defineSymbol("nimHasInvariant") # deadcode
for f in Feature:
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
defineSymbol("nimmixin")
defineSymbol("nimeffects")
defineSymbol("nimbabel")
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
defineSymbol("nimnewshared")
defineSymbol("nimNewTypedesc")
defineSymbol("nimrequiresnimframe")
defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias")
defineSymbol("nimlocks")
defineSymbol("nimnode")
defineSymbol("nimnomagic64")
defineSymbol("nimvarargstyped")
defineSymbol("nimtypedescfixed")
defineSymbol("nimKnowsNimvm")
defineSymbol("nimArrIdx")
defineSymbol("nimHasalignOf")
defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags")
when false: defineSymbol("nimHasOpt")
defineSymbol("nimNoArrayToCstringConversion")
defineSymbol("nimNewRoof")
defineSymbol("nimHasRunnableExamples")
defineSymbol("nimNewDot")
defineSymbol("nimHasNilChecks")
defineSymbol("nimSymKind")
defineSymbol("nimVmEqIdent")
defineSymbol("nimNoNil")
defineSymbol("nimNoZeroTerminator")
defineSymbol("nimNotNil")
defineSymbol("nimVmExportFixed")
defineSymbol("nimHasSymOwnerInMacro")
defineSymbol("nimNewRuntime")
defineSymbol("nimIncrSeqV3")
defineSymbol("nimAshr")
defineSymbol("nimNoNilSeqs")
defineSymbol("nimNoNilSeqs2")
defineSymbol("nimHasUserErrors")
defineSymbol("nimUncheckedArrayTyp")
defineSymbol("nimHasTypeof")
defineSymbol("nimErrorProcCanHaveBody")
defineSymbol("nimHasInstantiationOfInMacro")
defineSymbol("nimHasHotCodeReloading")
defineSymbol("nimHasNilSeqs")
defineSymbol("nimHasSignatureHashInMacro")
defineSymbol("nimHasDefault")
defineSymbol("nimMacrosSizealignof")
defineSymbol("nimNoZeroExtendMagic")
for f in low(Feature)..high(Feature):
defineSymbol("nimHas" & $f)
for s in warnMin..warnMax:
defineSymbol("nimHasWarning" & $s)
for s in hintMin..hintMax:
defineSymbol("nimHasHint" & $s)
for s in WarningsToStr:
defineSymbol("nimHasWarning" & s)
for s in HintsToStr:
defineSymbol("nimHasHint" & s)
defineSymbol("nimFixedOwned")
defineSymbol("nimHasStyleChecks")
when defined(nimHasLibFFI):
# Renaming as we can't conflate input vs output define flags; e.g. this
# will report the right thing regardless of whether user adds
# `-d:nimHasLibFFI` in his user config.
defineSymbol("nimHasLibFFIEnabled") # deadcode
defineSymbol("nimHasStacktraceMsgs") # deadcode
defineSymbol("nimDoesntTrackDefects")
defineSymbol("nimHasLentIterators") # deadcode
defineSymbol("nimHasDeclaredMagic") # deadcode
defineSymbol("nimHasStacktracesModule") # deadcode
defineSymbol("nimHasEffectTraitsModule")
defineSymbol("nimHasCastPragmaBlocks")
defineSymbol("nimHasDeclaredLocs")
defineSymbol("nimHasJsBigIntBackend")
defineSymbol("nimHasWarningAsError")
defineSymbol("nimHasHintAsError")
defineSymbol("nimHasSpellSuggest")
defineSymbol("nimHasCustomLiterals")
defineSymbol("nimHasUnifiedTuple")
defineSymbol("nimHasIterable")
defineSymbol("nimHasTypeofVoid") # deadcode
defineSymbol("nimHasDragonBox") # deadcode
defineSymbol("nimHasHintAll")
defineSymbol("nimHasTrace")
defineSymbol("nimHasEffectsOf")
defineSymbol("nimHasEnforceNoRaises")
defineSymbol("nimHasTopDownInference")
defineSymbol("nimHasTemplateRedefinitionPragma")
defineSymbol("nimHasCstringCase")
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasWarnCastSizes") # deadcode
defineSymbol("nimHasOutParams")
defineSymbol("nimHasSystemRaisesDefect")
defineSymbol("nimHasWarnUnnamedBreak")
defineSymbol("nimHasGenericDefine")
defineSymbol("nimHasDefineAliases")
defineSymbol("nimHasWarnBareExcept")
defineSymbol("nimHasDup")
defineSymbol("nimHasChecksums")
defineSymbol("nimHasSendable")
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasCastExtendedVm")
defineSymbol("nimHasWarnStdPrefix")
defineSymbol("nimHasVtables")
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasGenericsOpenSym3")
defineSymbol("nimHasJsNoLambdaLifting")
defineSymbol("nimHasDefaultFloatRoundtrip")

View File

@@ -0,0 +1,6 @@
## Use the module 'lineinfos' instead!
{.deprecated.}
import lineinfos
export lineinfos

72
compiler/cursors.nim Normal file
View File

@@ -0,0 +1,72 @@
#
#
# The Nim Compiler
# (c) Copyright 2019 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
lineinfos, parampatterns
##[
This module implements "cursor" detection. A cursor is a local variable
that is used for navigation in a datastructure, it does not "own" the
data it aliases but it might update the underlying datastructure.
Two primary examples for cursors that I have in mind and that are critical
for optimization:
1. Local string variable introduced by ``for x in a``::
var i = 0
while i < a.len:
let cursor = a[i]
use cursor
inc i
2. Local ``ref`` variable for navigation::
var cursor = listHead
while cursor != nil:
use cursor
cursor = cursor.next
Cursors are very interesting for the optimizer because they can be copyMem'ed
and don't need a destructor.
More formally, a cursor is a variable that is set on all paths to
a *location* or a proc call that produced a ``lent/var`` type. All statements
that come after these assignments MUST not mutate what the cursor aliases.
Mutations *through* the cursor are allowed if the cursor has ref semantics.
Look at this complex real world example taken from the compiler itself:
.. code-block:: Nim
proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
var t = typ
while true:
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
return t.sym.loc.r
if t.kind in irrelevantForBackend:
t = t.lastSon
else:
break
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ
if typ.loc.r == nil:
typ.loc.r = typ.typeName & $sig
result = typ.loc.r
if result == nil: internalError(m.config, "getTypeName: " & $typ.kind)
Here `t` is a cursor but without a control flow based analysis we are unlikely
to detect it.
]##
# Araq: I owe you an implementation. For now use the .cursor pragma. :-/

View File

@@ -1,72 +0,0 @@
##[
Utilities to help with debugging nim compiler.
Experimental API, subject to change.
]##
#[
## example
useful debugging flags:
--stacktrace -d:debug -d:nimDebugUtils
nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim
## future work
* expose and improve astalgo.debug, replacing it by std/prettyprints,
refs https://github.com/nim-lang/RFCs/issues/385
]#
import options
import std/wrapnils
export wrapnils
# allows using things like: `?.n.sym.typ.len`
import std/stackframes
export stackframes
# allows using things like: `setFrameMsg c.config$n.info & " " & $n.kind`
# which doesn't log, but augments stacktrace with side channel information
var conf0: ConfigRef
proc onNewConfigRef*(conf: ConfigRef) {.inline.} =
## Caches `conf`, which can be retrieved with `getConfigRef`.
## This avoids having to forward `conf` all the way down the call chain to
## procs that need it during a debugging session.
conf0 = conf
proc getConfigRef*(): ConfigRef =
## nil, if -d:nimDebugUtils wasn't specified
result = conf0
proc isCompilerDebug*(): bool =
##[
Provides a simple way for user code to enable/disable logging in the compiler
in a granular way. This can then be used in the compiler as follows:
```nim
if isCompilerDebug():
echo ?.n.sym.typ.len
```
]##
runnableExamples:
proc main =
echo 2
{.define(nimCompilerDebug).}
echo 3.5 # code section in which `isCompilerDebug` will be true
{.undef(nimCompilerDebug).}
echo 'x'
conf0.isDefined("nimCompilerDebug")
proc enteringDebugSection*() {.exportc, dynlib.} =
## Provides a way for native debuggers to enable breakpoints, watchpoints, etc
## when code of interest is being compiled.
##
## Set your debugger to break on entering `nimCompilerIsEnteringDebugSection`
## and then execute a desired command.
discard
proc exitingDebugSection*() {.exportc, dynlib.} =
## Provides a way for native debuggers to disable breakpoints, watchpoints, etc
## when code of interest is no longer being compiled.
##
## Set your debugger to break on entering `exitingDebugSection`
## and then execute a desired command.
discard

View File

@@ -9,17 +9,11 @@
# This module implements a dependency file generator.
import options, ast, ropes, pathutils, msgs, lineinfos
import modulegraphs
import std/[os, parseutils]
import std/strutils except addf
import std/private/globs
when defined(nimPreviewSlimSystem):
import std/assertions
import
os, options, ast, astalgo, msgs, ropes, idents, passes, modulepaths,
pathutils
from modulegraphs import ModuleGraph, PPassContext
type
TGen = object of PPassContext
@@ -32,69 +26,23 @@ type
dotGraph: Rope
proc addDependencyAux(b: Backend; importing, imported: string) =
b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)])
addf(b.dotGraph, "$1 -> \"$2\";$n", [rope(importing), rope(imported)])
# s1 -> s2_4[label="[0-9]"];
proc toNimblePath(s: string, isStdlib: bool): string =
const stdPrefix = "std/"
const pkgPrefix = "pkg/"
if isStdlib:
let sub = "lib/"
var start = s.find(sub)
if start < 0:
raiseAssert "unreachable"
else:
start += sub.len
let base = s[start..^1]
if base.startsWith("system") or base.startsWith("std"):
result = base
else:
for dir in stdlibDirs:
if base.startsWith(dir):
return stdPrefix & base.splitFile.name
result = stdPrefix & base
else:
var sub = getEnv("NIMBLE_DIR")
if sub.len == 0:
sub = ".nimble/pkgs/"
else:
sub.add "/pkgs/"
var start = s.find(sub)
if start < 0:
sub[^1] = '2'
sub.add '/'
start = s.find(sub) # /pkgs2
if start < 0:
return s
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
doAssert n.kind == nkSym, $n.kind
let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex))
let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex))
let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module))
let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
addDependencyAux(b, parent, child)
proc addDotDependency*(c: PPassContext, n: PNode): PNode =
proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n
let g = PGen(c)
let b = Backend(g.graph.backend)
case n.kind
of nkImportStmt:
for i in 0..<n.len:
addDependency(c, g, b, n[i])
for i in 0 ..< sonsLen(n):
var imported = getModuleName(g.config, n.sons[i])
addDependencyAux(b, g.module.name.s, imported)
of nkFromStmt, nkImportExceptStmt:
addDependency(c, g, b, n[0])
var imported = getModuleName(g.config, n.sons[0])
addDependencyAux(b, g.module.name.s, imported)
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in 0..<n.len: discard addDotDependency(c, n[i])
for i in 0 ..< sonsLen(n): discard addDotDependency(c, n.sons[i])
else:
discard
@@ -104,7 +52,15 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
rope(project.splitFile.name), b.dotGraph],
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
result = PGen(module: module, config: graph.config, graph: graph)
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
g.config = graph.config
g.graph = graph
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
graph.backend = Backend(dotGraph: nil)
result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View File

@@ -9,63 +9,67 @@
## Data flow analysis for Nim.
## We transform the AST into a linear list of instructions first to
## make this easier to handle: There are only 3 different branching
## make this easier to handle: There are only 2 different branching
## instructions: 'goto X' is an unconditional goto, 'fork X'
## is a conditional goto (either the next instruction or 'X' can be
## taken), 'loop X' is the only jump that jumps back.
##
## Exhaustive case statements are translated
## taken). Exhaustive case statements are translated
## so that the last branch is transformed into an 'else' branch.
## ``return`` and ``break`` are all covered by 'goto'.
##
## Control flow through exception handling:
## Contrary to popular belief, exception handling doesn't cause
## many problems for this DFA representation, ``raise`` is a statement
## that ``goes to`` the outer ``finally`` or ``except`` if there is one,
## otherwise it is the same as ``return``. Every call is treated as
## a call that can potentially ``raise``. However, without a surrounding
## ``try`` we don't emit these ``fork ReturnLabel`` instructions in order
## to speed up the dataflow analysis passes.
##
## The data structures and algorithms used here are inspired by
## "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, lineinfos, renderer, aliasanalysis
import std/private/asciitables
import std/intsets
import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
when defined(nimPreviewSlimSystem):
import std/assertions
from patterns import sameTrees
type
InstrKind* = enum
goto, loop, fork, def, use
goto, fork, join, def, use
Instr* = object
n*: PNode
case kind*: InstrKind
of goto, fork, loop: dest*: int
of def, use:
n*: PNode # contains the def/use location.
of def, use: sym*: PSym # 'sym' can also be 'nil' and
# then 'n' contains the def/use location.
# This is used so that we can track object
# and tuple field accesses precisely.
of goto, fork, join: dest*: int
ControlFlowGraph* = seq[Instr]
TPosition = distinct int
TBlock = object
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
label: PSym
fixups: seq[TPosition]
Con = object
code: ControlFlowGraph
inTryStmt, interestingInstructions: int
inCall, inTryStmt: int
blocks: seq[TBlock]
tryStmtFixups: seq[TPosition]
forks: seq[TPosition]
owner: PSym
root: PSym
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
proc debugInfo(info: TLineInfo): string =
result = $info.line #info.toFilename & ":" & $info.line
proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
# for debugging purposes
# first iteration: compute all necessary labels:
result = ""
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, loop}:
if c[i].kind in {goto, fork, join}:
jumpTargets.incl(i+c[i].dest)
var i = start
while i <= last:
@@ -76,82 +80,327 @@ proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
case c[i].kind
of def, use:
result.add renderTree(c[i].n)
result.add("\t#")
result.add($c[i].n.info.line)
result.add("\n")
of goto, fork, loop:
of goto, fork, join:
result.add "L"
result.addInt c[i].dest+i
result.add("\t#")
result.add(debugInfo(c[i].n.info))
result.add("\n")
inc i
if i in jumpTargets: result.add("L" & $i & ": End\n")
# consider calling `asciitables.alignTable`
proc echoCfg*(c: ControlFlowGraph; start = 0; last = -1) {.deprecated.} =
proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} =
## echos the ControlFlowGraph for debugging purposes.
echo codeListing(c, start, last).alignTable
var buf = ""
codeListing(c, buf, start, last)
when declared(echo):
echo buf
proc forkI(c: var Con): TPosition =
proc forkI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)
c.code.add Instr(kind: fork, dest: 0)
c.code.add Instr(n: n, kind: fork, dest: 0)
c.forks.add result
proc gotoI(c: var Con): TPosition =
proc gotoI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)
c.code.add Instr(kind: goto, dest: 0)
c.code.add Instr(n: n, kind: goto, dest: 0)
proc genLabel(c: Con): TPosition = TPosition(c.code.len)
#[
template checkedDistance(dist): int =
doAssert low(int) div 2 + 1 < dist and dist < high(int) div 2
dist
Design of join
==============
proc jmpBack(c: var Con, p = TPosition(0)) =
c.code.add Instr(kind: loop, dest: checkedDistance(p.int - c.code.len))
block:
if cond: break
def(x)
use(x)
Generates:
L0: fork lab1
join L0 # patched.
goto Louter
lab1:
def x
join L0
Louter:
use x
block outer:
while a:
while b:
if foo:
if bar:
break outer # --> we need to 'join' every pushed 'fork' here
This works and then our abstract interpretation needs to deal with 'fork'
differently. It really causes a split in execution. Two threads are
"spawned" and both need to reach the 'join L' instruction. Afterwards
the abstract interpretations are joined and execution resumes single
threaded.
Abstract Interpretation
-----------------------
proc interpret(pc, state, comesFrom): state =
result = state
# we need an explicit 'create' instruction (an explicit heap), in order
# to deal with 'var x = create(); var y = x; var z = y; destroy(z)'
while true:
case pc
of fork:
let a = interpret(pc+1, result, pc)
let b = interpret(forkTarget, result, pc)
result = a ++ b # ++ is a union operation
inc pc
of join:
if joinTarget == comesFrom: return result
else: inc pc
of use X:
if not result.contains(x):
error "variable not initialized " & x
inc pc
of def X:
if not result.contains(x):
result.incl X
else:
error "overwrite of variable causes memory leak " & x
inc pc
of destroy X:
result.excl X
This is correct but still can lead to false positives:
proc p(cond: bool) =
if cond:
new(x)
otherThings()
if cond:
destroy x
Is not a leak. We should find a way to model *data* flow, not just
control flow. One solution is to rewrite the 'if' without a fork
instruction. The unstructured aspect can now be easily dealt with
the 'goto' and 'join' instructions.
proc p(cond: bool) =
L0: fork Lend
new(x)
# do not 'join' here!
Lend:
otherThings()
join L0 # SKIP THIS FOR new(x) SOMEHOW
destroy x
join L0 # but here.
But if we follow 'goto Louter' we will never come to the join point.
We restore the bindings after popping pc from the stack then there
"no" problem?!
while cond:
prelude()
if not condB: break
postlude()
--->
var setFlag = true
while cond and not setFlag:
prelude()
if not condB:
setFlag = true # BUT: Dependency
if not setFlag: # HERE
postlude()
--->
var setFlag = true
while cond and not setFlag:
prelude()
if not condB:
postlude()
setFlag = true
-------------------------------------------------
while cond:
prelude()
if more:
if not condB: break
stuffHere()
postlude()
-->
var setFlag = true
while cond and not setFlag:
prelude()
if more:
if not condB:
setFlag = false
else:
stuffHere()
postlude()
else:
postlude()
This is getting complicated. Instead we keep the whole 'join' idea but
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 =
result = TPosition(c.code.len)
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)
proc patch(c: var Con, p: TPosition) =
# patch with current index
c.code[p.int].dest = checkedDistance(c.code.len - p.int)
proc gen(c: var Con; n: PNode)
let p = p.int
let diff = c.code.len - p
doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2)
c.code[p].dest = diff
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition] = @[]
exits.add c.gotoI()
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
for finale in f[1]:
c.gen(finale)
exits.add c.gotoI()
for e in exits:
c.patch e
for f in c.blocks[oldLen].fixups:
c.patch(f)
c.blocks.setLen(oldLen)
template withBlock(labl: PSym; body: untyped) =
let oldLen = c.blocks.len
c.blocks.add TBlock(isTryBlock: false, label: labl)
template withBlock(labl: PSym; body: untyped) {.dirty.} =
var oldLen {.gensym.} = c.blocks.len
c.blocks.add TBlock(label: labl, fixups: @[])
body
popBlock(c, oldLen)
template forkT(body) =
let lab1 = c.forkI()
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
# through the loop. We need to prove this is correct for our
# purposes. But Herb Sutter claims it is. (Proof by authority.)
#[
while cond:
body
Becomes:
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.
So the code to generate is:
cond
fork L4 # F1
body
cond
fork L5 # F2
body
cond
fork L6 # F3
body
L6:
join F3
L5:
join F2
L4:
join F1
]#
if isTrue(n.sons[0]):
# 'while true' is an idiom in Nim and so we produce
# better code for it:
for i in 0..2:
withBlock(nil):
c.gen(n.sons[1])
else:
let oldForksLen = c.forks.len
var endings: array[3, TPosition]
for i in 0..2:
withBlock(nil):
c.gen(n.sons[0])
endings[i] = c.forkI(n)
c.gen(n.sons[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)
else:
proc genWhile(c: var Con; n: PNode) =
# lab1:
# cond, tmp
# fork tmp, lab2
# body
# jmp lab1
# lab2:
let oldForksLen = c.forks.len
let lab1 = c.genLabel
withBlock(nil):
if isTrue(n.sons[0]):
c.gen(n.sons[1])
c.jmpBack(n, lab1)
else:
c.gen(n.sons[0])
let lab2 = c.forkI(n)
c.gen(n.sons[1])
c.jmpBack(n, lab1)
c.patch(lab2)
setLen(c.forks, oldForksLen)
proc genBlock(c: var Con; n: PNode) =
withBlock(n.sons[0].sym):
c.gen(n.sons[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.sons[0].kind == nkSym:
#echo cast[int](n.sons[0].sym)
for i in countdown(c.blocks.len-1, 0):
if c.blocks[i].label == n.sons[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
template forkT(n, body) =
let oldLen = c.forks.len
let lab1 = c.forkI(n)
body
c.patch(lab1)
proc genWhile(c: var Con; n: PNode) =
# lab1:
# cond, tmp
# fork tmp, lab2
# body
# jmp lab1
# lab2:
let lab1 = c.genLabel
withBlock(nil):
if isTrue(n[0]):
c.gen(n[1])
c.jmpBack(lab1)
else:
c.gen(n[0])
forkT:
c.gen(n[1])
c.jmpBack(lab1)
c.joinI(lab1, n)
setLen(c.forks, oldLen)
proc genIf(c: var Con, n: PNode) =
#[
@@ -181,33 +430,40 @@ proc genIf(c: var Con, n: PNode) =
goto Lend3
L3:
D
goto Lend3 # not eliminated to simplify the join generation
Lend3:
join F3
Lend2:
join F2
Lend:
join F1
]#
let oldLen = c.forks.len
var endings: seq[TPosition] = @[]
let oldInteresting = c.interestingInstructions
let oldLen = c.code.len
for i in 0..<n.len:
let it = n[i]
c.gen(it[0])
for i in 0 ..< len(n):
var it = n.sons[i]
c.gen(it.sons[0])
if it.len == 2:
forkT:
c.gen(it.lastSon)
endings.add c.gotoI()
if oldInteresting == c.interestingInstructions:
setLen c.code, oldLen
else:
for i in countdown(endings.high, 0):
c.patch(endings[i])
let elsePos = forkI(c, it[1])
c.gen(it.sons[1])
endings.add(c.gotoI(it.sons[1]))
c.patch(elsePos)
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 genAndOr(c: var Con; n: PNode) =
# asgn dest, a
# fork lab1
# asgn dest, b
# lab1:
c.gen(n[1])
forkT:
c.gen(n[2])
# join F1
c.gen(n.sons[1])
forkT(n):
c.gen(n.sons[2])
proc genCase(c: var Con; n: PNode) =
# if (!expr1) goto lab1;
@@ -220,172 +476,253 @@ proc genCase(c: var Con; n: PNode) =
# lab2:
# elsePart
# Lend:
let isExhaustive = skipTypes(n[0].typ,
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString, tyCstring}
let isExhaustive = skipTypes(n.sons[0].typ,
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
var endings: seq[TPosition] = @[]
c.gen(n[0])
let oldInteresting = c.interestingInstructions
let oldLen = c.code.len
for i in 1..<n.len:
let it = n[i]
if it.len == 1 or (i == n.len-1 and isExhaustive):
let oldLen = c.forks.len
c.gen(n.sons[0])
for i in 1 ..< n.len:
let it = n.sons[i]
if it.len == 1:
c.gen(it.sons[0])
elif i == n.len-1 and isExhaustive:
# treat the last branch as 'else' if this is an exhaustive case statement.
c.gen(it.lastSon)
else:
forkT:
c.gen(it.lastSon)
endings.add c.gotoI()
if oldInteresting == c.interestingInstructions:
setLen c.code, oldLen
else:
for i in countdown(endings.high, 0):
c.patch(endings[i])
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()
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) =
inc c.interestingInstructions
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
let elsePos = c.forkI(it.lastSon)
c.gen(it.lastSon)
endings.add(c.gotoI(it.lastSon))
c.patch(elsePos)
for i in countdown(endings.high, 0):
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
doAssert(c.forks.len == oldLen)
proc genTry(c: var Con; n: PNode) =
let oldLen = c.forks.len
var endings: seq[TPosition] = @[]
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])
let oldFixups = c.tryStmtFixups.len
#let elsePos = c.forkI(n)
c.gen(n.sons[0])
dec c.inTryStmt
for f in c.blocks[oldLen].raiseFixups:
for i in oldFixups..c.tryStmtFixups.high:
let f = c.tryStmtFixups[i]
c.patch(f)
# we also need to produce join instructions
# for the 'fork' that might preceed the goto instruction
if f.int-1 >= 0 and c.code[f.int-1].kind == fork:
c.joinI(TPosition(f.int-1), n)
c.blocks.setLen oldLen
setLen(c.tryStmtFixups, oldFixups)
for i in 1..<n.len:
let it = n[i]
#c.patch(elsePos)
for i in 1 ..< n.len:
let it = n.sons[i]
if it.kind != nkFinally:
forkT:
c.gen(it.lastSon)
endings.add c.gotoI()
var blen = len(it)
let endExcept = c.forkI(it)
c.gen(it.lastSon)
endings.add(c.gotoI(it))
c.patch(endExcept)
for i in countdown(endings.high, 0):
c.patch(endings[i])
let endPos = endings[i]
c.patch(endPos)
c.joinI(c.forks.pop(), n)
# join the 'elsePos' forkI instruction:
#c.joinI(c.forks.pop(), n)
let fin = lastSon(n)
if fin.kind == nkFinally:
c.gen(fin[0])
c.gen(fin.sons[0])
doAssert(c.forks.len == oldLen)
template genNoReturn(c: var Con) =
template genNoReturn(c: var Con; n: PNode) =
# leave the graph
c.code.add Instr(kind: goto, dest: high(int) - c.code.len)
c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
proc genRaise(c: var Con; n: PNode) =
inc c.interestingInstructions
gen(c, n[0])
genJoins(c, n)
gen(c, n.sons[0])
if c.inTryStmt > 0:
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
return
assert false # Unreachable
c.tryStmtFixups.add c.gotoI(n)
else:
genNoReturn(c)
genNoReturn(c, n)
proc genImplicitReturn(c: var Con) =
if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len:
gen(c, c.owner.ast[resultPos])
gen(c, c.owner.ast.sons[resultPos])
proc genReturn(c: var Con; n: PNode) =
inc c.interestingInstructions
if n[0].kind != nkEmpty:
gen(c, n[0])
genJoins(c, n)
if n.sons[0].kind != nkEmpty:
gen(c, n.sons[0])
else:
genImplicitReturn(c)
genBreakOrRaiseAux(c, 0, n)
genNoReturn(c, n)
const
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
PathKinds0 = {nkDotExpr, nkCheckedFieldExpr,
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
nkAddr, nkHiddenAddr,
nkObjDownConv, nkObjUpConv}
PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv}
proc skipTrivials(c: var Con, n: PNode): PNode =
proc getRoot(n: PNode): PNode =
result = n
while true:
case result.kind
of PathKinds0 - {nkBracketExpr}:
of PathKinds0:
result = result[0]
of nkBracketExpr:
gen(c, result[1])
of PathKinds1:
result = result[1]
else: break
proc skipConvDfa*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkObjDownConv, nkObjUpConv:
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:
if n.sym.kind in InterestingSyms and n.sym == c.root:
c.code.add Instr(kind: use, n: orig)
inc c.interestingInstructions
else:
gen(c, n)
proc genDef(c: var Con; orig: PNode) =
let n = c.skipTrivials(orig)
let n = dfa.getRoot(orig)
if n.kind == nkSym and n.sym.kind in InterestingSyms:
if n.sym == c.root:
c.code.add Instr(kind: def, n: orig)
inc c.interestingInstructions
c.code.add Instr(n: orig, kind: use, sym: if orig != n: nil else: n.sym)
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 nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv, nkHiddenDeref, nkDerefExpr:
n = n[0]
of nkBracketExpr:
let x = n[0]
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
n = x
else:
break
else:
break
return false
proc useInstrTargets*(ins: Instr; loc: PNode): bool =
assert ins.kind == use
if ins.sym != nil and loc.kind == nkSym:
result = ins.sym == loc.sym
else:
result = ins.n == loc or sameTrees(ins.n, loc)
if not result:
# 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.
# use x.f; question: does it affect the full 'x'? No.
# use x; question does it affect 'x.f'? Yes.
result = aliases(ins.n, loc) or aliases(loc, ins.n)
proc defInstrTargets*(ins: Instr; loc: PNode): bool =
assert ins.kind == def
if ins.sym != nil and loc.kind == nkSym:
result = ins.sym == loc.sym
else:
result = ins.n == loc or sameTrees(ins.n, loc)
if not result:
# 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.
# use x.f; question: does it affect the full 'x'? No.
# use x; question does it affect 'x.f'? Yes.
result = aliases(ins.n, loc)
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
var n = orig
while true:
case n.kind
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
nkObjDownConv, nkObjUpConv:
n = n[0]
of nkHiddenDeref, nkDerefExpr:
# We "own" sinkparam[].loc but not ourVar[].location as it is a nasty
# pointer indirection.
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})
of nkBracketExpr:
let x = n[0]
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
n = x
else:
break
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
(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
#
# let splited = split(move self.root, x)
# self.root = merge(splited.lower, splited.greater)
#
# could be written without the ``move self.root``. However, this would be
# wrong! Then the write barrier for the ``self.root`` assignment would
# 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) =
if n.kind == nkSym and n.sym.kind in InterestingSyms:
c.code.add Instr(n: n, kind: def, sym: n.sym)
elif isAnalysableFieldAccess(n, c.owner):
c.code.add Instr(n: n, kind: def, sym: nil)
proc canRaise(fn: PNode): bool =
const magicsThatCanRaise = {
mNone, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst}
if fn.kind == nkSym and fn.sym.magic notin magicsThatCanRaise:
result = false
else:
result = true
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])
if t != nil and i < t.signatureLen and isOutParam(t[i]):
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
genDef(c, n[i])
when false:
if t != nil and i < t.len and t.sons[i].kind == tyVar:
# This is wrong! Pass by var is a 'might def', not a 'must def'
# like the other defs we emit. This is not good enough for a move
# optimizer.
genDef(c, n[i])
# every call can potentially raise:
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
inc c.interestingInstructions
if c.inTryStmt > 0 and canRaise(n[0]):
# we generate the instruction sequence:
# fork lab1
# goto exceptionHandler (except or finally)
# lab1:
forkT:
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
break
# 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
proc genMagic(c: var Con; n: PNode; m: TMagic) =
case m
@@ -402,45 +739,39 @@ proc genVarSection(c: var Con; n: PNode) =
discard
elif a.kind == nkVarTuple:
gen(c, a.lastSon)
for i in 0..<a.len-2: genDef(c, a[i])
for i in 0 .. a.len-3: genDef(c, a[i])
else:
gen(c, a.lastSon)
if a.lastSon.kind != nkEmpty:
genDef(c, a[0])
genDef(c, a.sons[0])
proc gen(c: var Con; n: PNode) =
case n.kind
of nkSym: genUse(c, n)
of nkCallKinds:
if n[0].kind == nkSym:
let s = n[0].sym
if n.sons[0].kind == nkSym:
let s = n.sons[0].sym
if s.magic != mNone:
genMagic(c, n, s.magic)
else:
genCall(c, n)
if sfNoReturn in n[0].sym.flags:
genNoReturn(c)
if sfNoReturn in n.sons[0].sym.flags:
genNoReturn(c, n)
else:
genCall(c, n)
of nkCharLit..nkNilLit: discard
of nkAsgn, nkFastAsgn, nkSinkAsgn:
of nkAsgn, nkFastAsgn:
gen(c, n[1])
if n[0].kind in PathKinds0:
let a = c.skipTrivials(n[0])
if a.kind in nkCallKinds:
gen(c, a)
# watch out: 'obj[i].f2 = value' sets 'f2' but
# "uses" 'i'. But we are only talking about builtin array indexing so
# it doesn't matter and 'x = 34' is NOT a usage of 'x'.
genDef(c, n[0])
of PathKinds0 - {nkObjDownConv, nkObjUpConv}:
of PathKinds0 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}:
genUse(c, n)
of nkIfStmt, nkIfExpr: genIf(c, n)
of nkWhenStmt:
# This is "when nimvm" node. Chose the first branch.
gen(c, n[0][1])
gen(c, n.sons[0].sons[1])
of nkCaseStmt: genCase(c, n)
of nkWhileStmt: genWhile(c, n)
of nkBlockExpr, nkBlockStmt: genBlock(c, n)
@@ -452,40 +783,18 @@ proc gen(c: var Con; n: PNode) =
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkYieldStmt:
for x in n: gen(c, x)
of nkPragmaBlock: gen(c, n.lastSon)
of nkDiscardStmt, nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
gen(c, n[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
gen(c, n[1])
of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n.sons[0])
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv:
gen(c, n.sons[1])
of nkStringToCString, nkCStringToString: gen(c, n.sons[0])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
of nkDefer:
doAssert false, "dfa construction pass requires the elimination of 'defer'"
else: discard
when false:
proc optimizeJumps(c: var ControlFlowGraph) =
for i in 0..<c.len:
case c[i].kind
of goto, fork:
var pc = i + c[i].dest
if pc < c.len and c[pc].kind == goto:
while pc < c.len and c[pc].kind == goto:
let newPc = pc + c[pc].dest
if newPc > pc:
pc = newPc
else:
break
c[i].dest = pc - i
of loop, def, use: discard
proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
## constructs a control flow graph for ``body``.
var c = Con(code: @[], blocks: @[], owner: s, root: root)
withBlock(s):
gen(c, body)
if root.kind == skResult:
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = c.code # will move
else:
shallowCopy(result, c.code)
when false:
optimizeJumps result
var c = Con(code: @[], blocks: @[], owner: s)
gen(c, body)
genImplicitReturn(c)
shallowCopy(result, c.code)

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,8 @@
# semantic checking.
import
options, ast, msgs, docgen, lineinfos, pathutils, packages
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos,
pathutils
from modulegraphs import ModuleGraph, PPassContext
@@ -22,43 +23,39 @@ type
config: ConfigRef
PGen = ref TGen
proc shouldProcess(g: PGen): bool =
(optWholeProject in g.doc.conf.globalOptions and g.doc.conf.belongsToProjectPackage(g.module)) or
template shouldProcess(g): bool =
(g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or
sfMainModule in g.module.flags or g.config.projectMainIdx == g.module.info.fileIndex
template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
let groupedToc = true
if shouldProcess(g):
finishGenerateDoc(g.doc)
body
try:
generateIndex(g.doc)
except IOError:
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
writeOutput(g.doc, useWarning)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutputJson(g.doc, useWarning)
proc processNode*(c: PPassContext, n: PNode): PNode =
proc processNode(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateDoc(g.doc, n, n, g.config)
generateDoc(g.doc, n, n)
proc processNodeJson*(c: PPassContext, n: PNode): PNode =
proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n, g.config, false)
generateJson(g.doc, n, false)
template myOpenImpl(ext: untyped) {.dirty.} =
var g: PGen
@@ -66,15 +63,20 @@ template myOpenImpl(ext: untyped) {.dirty.} =
g.module = module
g.config = graph.config
var d = newDocumentor(AbsoluteFile toFullPath(graph.config, FileIndex module.position),
graph.cache, graph.config, ext, module, hasToc = true)
graph.cache, graph.config, ext)
d.hasToc = true
g.doc = d
result = g
proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
myOpenImpl(HtmlExt)
proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
myOpenImpl(TexExt)
proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpenJson(graph: ModuleGraph; module: PSym): PPassContext =
myOpenImpl(JsonExt)
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson,
close = closeJson)
proc finishDoc2Pass*(project: string) =
discard

View File

@@ -1,23 +1,19 @@
import ast, idents, lineinfos, modulegraphs, magicsys
when defined(nimPreviewSlimSystem):
import std/assertions
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
result = newSym(skProc, getIdent(g.cache, "$"), t.owner, info)
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), result, info)
dest.typ = t
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, idgen, t.owner)
result.typ = newType(tyProc, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
addSon(result.typ.n, newNodeI(nkEffectList, info))
result.typ.addParam dest
@@ -26,60 +22,52 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
caseStmt.add(newSymNode dest)
# copy the branches over, but replace the fields with the for loop body:
for i in 0..<t.n.len:
for i in 0 ..< t.n.len:
assert(t.n[i].kind == nkSym)
var field = t.n[i].sym
let val = if field.ast == nil: field.name.s else: field.ast.strVal
caseStmt.add newTree(nkOfBranch, newIntTypeNode(field.position, t),
caseStmt.add newTree(nkOfBranch, newSymNode(field),
newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newStrNode(val, info))))
#newIntTypeNode(nkIntLit, field.position, t)
body.add(caseStmt)
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = body
n[resultPos] = newSymNode(res)
for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
n.sons[namePos] = newSymNode(result)
n.sons[paramsPos] = result.typ.n
n.sons[bodyPos] = body
n.sons[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfNeverRaises
proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
proc searchObjCase(obj: PNode; field: PSym): PNode =
case obj.kind
of nkSym:
result = nil
of nkElse, nkOfBranch:
result = searchObjCaseImpl(obj.lastSon, field)
result = searchObjCase(obj.lastSon, field)
else:
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
result = nil
for x in obj:
result = searchObjCaseImpl(x, field)
result = searchObjCase(x, field)
if result != nil: break
proc searchObjCase(t: PType; field: PSym): PNode =
result = searchObjCaseImpl(t.n, field)
if result == nil and t.baseClass != nil:
result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field)
doAssert result != nil
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph): PSym =
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), t.owner, info)
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), result, info)
dest.typ = field.typ
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, idgen, t.owner)
result.typ = newType(tyProc, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
addSon(result.typ.n, newNodeI(nkEffectList, info))
result.typ.addParam dest
@@ -87,11 +75,12 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
var caseStmt = newNodeI(nkCaseStmt, info)
caseStmt.add(newSymNode dest)
let subObj = searchObjCase(t, field)
for i in 1..<subObj.len:
let subObj = searchObjCase(t.n, field)
doAssert subObj != nil
for i in 1 ..< subObj.len:
let ofBranch = subObj[i]
var newBranch = newNodeI(ofBranch.kind, ofBranch.info)
for j in 0..<ofBranch.len-1:
for j in 0..ofBranch.len-2:
newBranch.add ofBranch[j]
newBranch.add newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newIntNode(nkInt8Lit, i)))
@@ -100,11 +89,10 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
body.add(caseStmt)
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = body
n[resultPos] = newSymNode(res)
for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
n.sons[namePos] = newSymNode(result)
n.sons[paramsPos] = result.typ.n
n.sons[bodyPos] = body
n.sons[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfNeverRaises

View File

@@ -1,85 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains support code for new-styled error
## handling via an `nkError` node kind.
import ast, renderer, options, types
import std/strutils
when defined(nimPreviewSlimSystem):
import std/assertions
type
ErrorKind* = enum ## expand as you need.
RawTypeMismatchError
ExpressionCannotBeCalled
CustomError
WrongNumberOfArguments
AmbiguousCall
proc errorSubNode*(n: PNode): PNode =
case n.kind
of nkEmpty..nkNilLit:
result = nil
of nkError:
result = n
else:
result = nil
for i in 0..<n.len:
result = errorSubNode(n[i])
if result != nil: break
proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
assert wrongNode.kind != nkError
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(k))
for a in args: result.add a
proc newError*(wrongNode: PNode; msg: string): PNode =
assert wrongNode.kind != nkError
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(CustomError))
result.add newStrNode(msg, wrongNode.info)
proc errorToString*(config: ConfigRef; n: PNode): string =
assert n.kind == nkError
assert n.len > 1
let wrongNode = n[0]
case ErrorKind(n[1].intVal)
of RawTypeMismatchError:
result = "type mismatch"
of ExpressionCannotBeCalled:
result = "expression '$1' cannot be called" % wrongNode[0].renderTree
of CustomError:
result = n[2].strVal
of WrongNumberOfArguments:
result = "wrong number of arguments"
of AmbiguousCall:
let a = n[2].sym
let b = n[3].sym
var args = "("
for i in 1..<wrongNode.len:
if i > 1: args.add(", ")
args.add(typeToString(wrongNode[i].typ))
args.add(")")
result = "ambiguous call; both $1 and $2 match for: $3" % [
getProcHeader(config, a),
getProcHeader(config, b),
args]

View File

@@ -9,20 +9,13 @@
## This file implements the FFI part of the evaluator for Nim code.
import ast, types, options, msgs, lineinfos
from std/os import getAppFilename
import libffi/libffi
import std/[tables, dynlib]
import ast, astalgo, ropes, types, options, tables, dynlib, msgs, os, lineinfos
import pkg/libffi
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):
const libcDll = "/usr/lib/libSystem.dylib"
else:
@@ -34,15 +27,14 @@ var
gDllCache = initTable[string, LibHandle]()
when defined(windows):
var gExeHandle = loadLib(getAppFilename())
var gExeHandle = loadLib(os.getAppFilename())
else:
var gExeHandle = loadLib()
proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = nil
if dll in cache:
return cache[dll]
var libs: seq[string] = @[]
var libs: seq[string]
libCandidates(dll, libs)
for c in libs:
result = loadLib(c)
@@ -54,35 +46,38 @@ proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo)
const
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
let name = sym.cname # $sym.loc.r would point to internal name
let name = $sym.loc.r
# the AST does not support untyped pointers directly, so we use an nkIntLit
# that contains the address instead:
result = newNodeIT(nkPtrLit, sym.info, sym.typ)
when true:
var libPathMsg = ""
case name
of "stdin": result.intVal = cast[ByteAddress](system.stdin)
of "stdout": result.intVal = cast[ByteAddress](system.stdout)
of "stderr": result.intVal = cast[ByteAddress](system.stderr)
of "vmErrnoWrapper": result.intVal = cast[ByteAddress](myerrno)
else:
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
globalError(conf, sym.info, "dynlib needs to be a string lit")
var theAddr: pointer = nil
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll
var theAddr: pointer
if (lib.isNil or lib.kind == libHeader) and not gExehandle.isNil:
# first try this exe itself:
theAddr = gExeHandle.symAddr(name.cstring)
theAddr = gExehandle.symAddr(name)
# then try libc:
if theAddr.isNil:
let dllhandle = getDll(conf, gDllCache, libcDll, sym.info)
theAddr = dllhandle.symAddr(name.cstring)
theAddr = dllhandle.symAddr(name)
elif not lib.isNil:
let dll = if lib.kind == libHeader: libcDll else: lib.path.strVal
libPathMsg = dll
let dllhandle = getDll(conf, gDllCache, dll, sym.info)
theAddr = dllhandle.symAddr(name.cstring)
if theAddr.isNil: globalError(conf, sym.info,
"cannot import symbol: " & name & " from " & libPathMsg)
result.intVal = cast[int](theAddr)
theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(conf, sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[ByteAddress](theAddr)
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.TType =
if t == nil: return addr libffi.type_void
case t.kind
@@ -95,11 +90,11 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
else: result = nil
of tyFloat, tyFloat64: result = addr libffi.type_double
of tyFloat32: result = addr libffi.type_float
of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCstring, tySequence, tyString, tyUntyped,
of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped,
tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil:
result = addr libffi.type_pointer
of tyDistinct, tyAlias, tySink:
result = mapType(conf, t.skipModifier)
result = mapType(conf, t.sons[0])
else:
result = nil
# too risky:
@@ -107,17 +102,16 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI =
case cc
of ccNimCall: result = DEFAULT_ABI
of ccDefault: result = DEFAULT_ABI
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
result = default(TABI)
globalError(conf, info, "cannot map calling convention to FFI")
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v
template rd(T, p: untyped): untyped = (cast[ptr T](p))[]
template wr(T, p, v: untyped): untyped = (cast[ptr T](p))[] = v
template `+!`(x, y: untyped): untyped =
cast[pointer](cast[int](x) + y)
cast[pointer](cast[ByteAddress](x) + y)
proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
## computes the size of the blob
@@ -126,18 +120,16 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
else:
result = sizeof(pointer) + packSize(conf, v[0], typ.elementType)
result = sizeof(pointer) + packSize(conf, v.sons[0], typ.lastSon)
of tyDistinct, tyGenericInst, tyAlias, tySink:
result = packSize(conf, v, typ.skipModifier)
result = packSize(conf, v, typ.sons[0])
of tyArray:
# consider: ptr array[0..1000_000, int] which is common for interfacing;
# we use the real length here instead
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
elif v.len != 0:
result = v.len * packSize(conf, v[0], typ.elementType)
else:
result = 0
result = v.len * packSize(conf, v.sons[0], typ.sons[1])
else:
result = getSize(conf, typ).int
@@ -146,34 +138,32 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
case n.kind
of nkRecList:
result = nil
for i in 0..<n.len:
result = getField(conf, n[i], position)
for i in 0 ..< sonsLen(n):
result = getField(conf, n.sons[i], position)
if result != nil: return
of nkRecCase:
result = getField(conf, n[0], position)
result = getField(conf, n.sons[0], position)
if result != nil: return
for i in 1..<n.len:
case n[i].kind
for i in 1 ..< sonsLen(n):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = getField(conf, lastSon(n[i]), position)
result = getField(conf, lastSon(n.sons[i]), position)
if result != nil: return
else: internalError(conf, n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: result = nil
else: result = nil
else: discard
proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
# compute the field's offsets:
discard getSize(conf, typ)
for i in ord(x.kind == nkObjConstr)..<x.len:
var it = x[i]
for i in ord(x.kind == nkObjConstr) ..< sonsLen(x):
var it = x.sons[i]
if it.kind == nkExprColonExpr:
internalAssert conf, it[0].kind == nkSym
let field = it[0].sym
pack(conf, it[1], field.typ, res +! field.offset)
internalAssert conf, it.sons[0].kind == nkSym
let field = it.sons[0].sym
pack(conf, it.sons[1], field.typ, res +! field.offset)
elif typ.n != nil:
let field = getField(conf, typ.n, i)
pack(conf, it, field.typ, res +! field.offset)
@@ -185,8 +175,8 @@ const maxPackDepth = 20
var packRecCheck = 0
proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
template awr(typ, v: untyped): untyped =
wr(typ, res, v)
template awr(T, v: untyped): untyped =
wr(T, res, v)
case typ.kind
of tyBool: awr(bool, v.intVal != 0)
@@ -213,7 +203,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
of tyFloat32: awr(float32, v.floatVal)
of tyFloat64: awr(float64, v.floatVal)
of tyPointer, tyProc, tyCstring, tyString:
of tyPointer, tyProc, tyCString, tyString:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
discard
@@ -234,19 +224,19 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
packRecCheck = 0
globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
inc packRecCheck
pack(conf, v[0], typ.elementType, res +! sizeof(pointer))
pack(conf, v.sons[0], typ.lastSon, res +! sizeof(pointer))
dec packRecCheck
awr(pointer, res +! sizeof(pointer))
of tyArray:
let baseSize = getSize(conf, typ.elementType)
for i in 0..<v.len:
pack(conf, v[i], typ.elementType, res +! i * baseSize)
let baseSize = getSize(conf, typ.sons[1])
for i in 0 ..< v.len:
pack(conf, v.sons[i], typ.sons[1], res +! i * baseSize)
of tyObject, tyTuple:
packObject(conf, v, typ, res)
of tyNil:
discard
of tyDistinct, tyGenericInst, tyAlias, tySink:
pack(conf, v, typ.skipModifier, res)
pack(conf, v, typ.sons[0], res)
else:
globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
@@ -255,14 +245,14 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode
proc unpackObjectAdd(conf: ConfigRef, x: pointer, n, result: PNode) =
case n.kind
of nkRecList:
for i in 0..<n.len:
unpackObjectAdd(conf, x, n[i], result)
for i in 0 ..< sonsLen(n):
unpackObjectAdd(conf, x, n.sons[i], result)
of nkRecCase:
globalError(conf, result.info, "case objects cannot be unpacked")
of nkSym:
var pair = newNodeI(nkExprColonExpr, result.info, 2)
pair[0] = n
pair[1] = unpack(conf, x +! n.sym.offset, n.sym.typ, nil)
pair.sons[0] = n
pair.sons[1] = unpack(conf, x +! n.sym.offset, n.sym.typ, nil)
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
result.add pair
else: discard
@@ -275,7 +265,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
# the nkPar node:
if n.isNil:
result = newNode(nkTupleConstr)
result.typ() = typ
result.typ = typ
if typ.n.isNil:
internalError(conf, "cannot unpack unnamed tuple")
unpackObjectAdd(conf, x, typ.n, result)
@@ -285,28 +275,28 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
globalError(conf, n.info, "cannot map value from FFI")
if typ.n.isNil:
globalError(conf, n.info, "cannot unpack unnamed tuple")
for i in ord(n.kind == nkObjConstr)..<n.len:
var it = n[i]
for i in ord(n.kind == nkObjConstr) ..< sonsLen(n):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
internalAssert conf, it[0].kind == nkSym
let field = it[0].sym
it[1] = unpack(conf, x +! field.offset, field.typ, it[1])
internalAssert conf, it.sons[0].kind == nkSym
let field = it.sons[0].sym
it.sons[1] = unpack(conf, x +! field.offset, field.typ, it.sons[1])
else:
let field = getField(conf, typ.n, i)
n[i] = unpack(conf, x +! field.offset, field.typ, it)
n.sons[i] = unpack(conf, x +! field.offset, field.typ, it)
proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
if n.isNil:
result = newNode(nkBracket)
result.typ() = typ
newSeq(result.sons, lengthOrd(conf, typ).toInt)
result.typ = typ
newSeq(result.sons, lengthOrd(conf, typ).int)
else:
result = n
if result.kind != nkBracket:
globalError(conf, n.info, "cannot map value from FFI")
let baseSize = getSize(conf, typ.elementType)
for i in 0..<result.len:
result[i] = unpack(conf, x +! i * baseSize, typ.elementType, result[i])
let baseSize = getSize(conf, typ.sons[1])
for i in 0 ..< result.len:
result.sons[i] = unpack(conf, x +! i * baseSize, typ.sons[1], result.sons[i])
proc canonNodeKind(k: TNodeKind): TNodeKind =
case k
@@ -319,7 +309,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template aw(k, v, field: untyped): untyped =
if n.isNil:
result = newNode(k)
result.typ() = typ
result.typ = typ
else:
# check we have the right field:
result = n
@@ -333,12 +323,12 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template setNil() =
if n.isNil:
result = newNode(nkNilLit)
result.typ() = typ
result.typ = typ
else:
reset n[]
result = n
result[] = TNode(kind: nkNilLit)
result.typ() = typ
result.kind = nkNilLit
result.typ = typ
template awi(kind, v: untyped): untyped = aw(kind, v, intVal)
template awf(kind, v: untyped): untyped = aw(kind, v, floatVal)
@@ -364,7 +354,6 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
@@ -378,25 +367,24 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
# in their unboxed representation so nothing it to be unpacked:
result = n
else:
awi(nkPtrLit, cast[int](p))
awi(nkPtrLit, cast[ByteAddress](p))
of tyPtr, tyRef, tyVar, tyLent:
let p = rd(pointer, x)
if p.isNil:
setNil()
elif n == nil or n.kind == nkPtrLit:
awi(nkPtrLit, cast[int](p))
awi(nkPtrLit, cast[ByteAddress](p))
elif n != nil and n.len == 1:
internalAssert(conf, n.kind == nkRefTy)
n[0] = unpack(conf, p, typ.elementType, n[0])
n.sons[0] = unpack(conf, p, typ.lastSon, n.sons[0])
result = n
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(conf, x, typ, n)
of tyArray:
result = unpackArray(conf, x, typ, n)
of tyCstring, tyString:
of tyCString, tyString:
let p = rd(cstring, x)
if p.isNil:
setNil()
@@ -405,15 +393,14 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
of tyNil:
setNil()
of tyDistinct, tyGenericInst, tyAlias, tySink:
result = unpack(conf, x, typ.skipModifier, n)
result = unpack(conf, x, typ.lastSon, n)
else:
# XXX what to do with 'array' here?
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyLent, tyPointer,
tyProc, tyCstring, tyString,
tyProc, tyCString, tyString,
tySequence}:
result = newNodeIT(x.kind, x.info, destTyp)
result.intVal = x.intVal
@@ -427,46 +414,46 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
# cast through a pointer needs a new inner object:
let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
else: x.copyTree
y.typ() = x.typ
y.typ = x.typ
result = unpack(conf, a, destTyp, y)
dealloc a
proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
internalAssert conf, call[0].kind == nkPtrLit
internalAssert conf, call.sons[0].kind == nkPtrLit
var cif: TCif = default(TCif)
var sig: ParamList = default(ParamList)
var cif: TCif
var sig: TParamList
# use the arguments' types for varargs support:
for i in 1..<call.len:
sig[i-1] = mapType(conf, call[i].typ)
for i in 1..call.len-1:
sig[i-1] = mapType(conf, call.sons[i].typ)
if sig[i-1].isNil:
globalError(conf, call.info, "cannot map FFI type")
let typ = call[0].typ
let typ = call.sons[0].typ
if prep_cif(cif, mapCallConv(conf, typ.callConv, call.info), cuint(call.len-1),
mapType(conf, typ.returnType), sig) != OK:
mapType(conf, typ.sons[0]), sig) != OK:
globalError(conf, call.info, "error in FFI call")
var args: ArgList = default(ArgList)
let fn = cast[pointer](call[0].intVal)
for i in 1..<call.len:
var t = call[i].typ
args[i-1] = alloc0(packSize(conf, call[i], t))
pack(conf, call[i], t, args[i-1])
let retVal = if isEmptyType(typ.returnType): pointer(nil)
else: alloc(getSize(conf, typ.returnType).int)
var args: TArgList
let fn = cast[pointer](call.sons[0].intVal)
for i in 1 .. call.len-1:
var t = call.sons[i].typ
args[i-1] = alloc0(packSize(conf, call.sons[i], t))
pack(conf, call.sons[i], t, args[i-1])
let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
else: alloc(getSize(conf, typ.sons[0]).int)
libffi.call(cif, fn, retVal, args)
if retVal.isNil:
result = newNode(nkEmpty)
else:
result = unpack(conf, retVal, typ.returnType, nil)
result = unpack(conf, retVal, typ.sons[0], nil)
result.info = call.info
if retVal != nil: dealloc retVal
for i in 1..<call.len:
call[i] = unpack(conf, args[i-1], typ[i], call[i])
for i in 1 .. call.len-1:
call.sons[i] = unpack(conf, args[i-1], typ.sons[i], call[i])
dealloc args[i-1]
proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
@@ -474,40 +461,40 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
info: TLineInfo): PNode =
internalAssert conf, fn.kind == nkPtrLit
var cif: TCif = default(TCif)
var sig: ParamList = default(ParamList)
var cif: TCif
var sig: TParamList
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
internalAssert conf, i+1 < fntyp.len
aTyp = fntyp[i+1]
args[i+start].typ() = aTyp
aTyp = fntyp.sons[i+1]
args[i+start].typ = aTyp
sig[i] = mapType(conf, aTyp)
if sig[i].isNil: globalError(conf, info, "cannot map FFI type")
if prep_cif(cif, mapCallConv(conf, fntyp.callConv, info), cuint(len),
mapType(conf, fntyp[0]), sig) != OK:
mapType(conf, fntyp.sons[0]), sig) != OK:
globalError(conf, info, "error in FFI call")
var cargs: ArgList = default(ArgList)
var cargs: TArgList
let fn = cast[pointer](fn.intVal)
for i in 0..len-1:
for i in 0 .. len-1:
let t = args[i+start].typ
cargs[i] = alloc0(packSize(conf, args[i+start], t))
pack(conf, args[i+start], t, cargs[i])
let retVal = if isEmptyType(fntyp[0]): pointer(nil)
else: alloc(getSize(conf, fntyp[0]).int)
let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
else: alloc(getSize(conf, fntyp.sons[0]).int)
libffi.call(cif, fn, retVal, cargs)
if retVal.isNil:
result = newNode(nkEmpty)
else:
result = unpack(conf, retVal, fntyp[0], nil)
result = unpack(conf, retVal, fntyp.sons[0], nil)
result.info = info
if retVal != nil: dealloc retVal
for i in 0..len-1:
for i in 0 .. len-1:
let t = args[i+start].typ
args[i+start] = unpack(conf, cargs[i], t, args[i+start])
dealloc cargs[i]

View File

@@ -9,43 +9,28 @@
## Template evaluation engine. Now hygienic.
import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
import std/strutils
import
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
lineinfos
type
TemplCtx = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
isDeclarative: bool
mapping: SymMapping # every gensym'ed symbol needs to be mapped to some
# new symbol
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
config: ConfigRef
ic: IdentCache
instID: int
idgen: IdGenerator
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
if ctx.instLines: setInfoRecursive(result, b.info)
if ctx.instLines: result.info = b.info
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
template handleParam(param) =
let x = param
if x.kind == nkArgList:
for y in items(x): result.add(y)
elif nfDefaultRefsParam in x.flags:
# value of default param needs to be evaluated like template body
# if it contains other template params
var res: PNode
if isAtom(x):
res = newNodeI(nkPar, x.info)
evalTemplateAux(x, actual, c, res)
if res.len == 1: res = res[0]
else:
res = copyNode(x)
for i in 0..<x.safeLen:
evalTemplateAux(x[i], actual, c, res)
result.add res
else:
result.add copyTree(x)
@@ -53,27 +38,22 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
of nkSym:
var s = templ.sym
if (s.owner == nil and s.kind == skParam) or s.owner == c.owner:
if s.kind == skParam and {sfGenSym, sfTemplateParam} * s.flags == {sfTemplateParam}:
handleParam actual[s.position]
if s.kind == skParam and sfGenSym notin s.flags:
handleParam actual.sons[s.position]
elif (s.owner != nil) and (s.kind == skGenericParam or
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
handleParam actual[s.owner.typ.signatureLen + s.position - 1]
handleParam actual.sons[s.owner.typ.len + s.position - 1]
else:
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = idTableGet(c.mapping, s)
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, c.idgen)
x = copySym(s)
# sem'check needs to set the owner properly later, see bug #9476
setOwner(x, nil) # c.genSymOwner
x.owner = nil # c.genSymOwner
#if x.kind == skParam and x.owner.kind == skModule:
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
if sfGenSym in s.flags:
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
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)
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
else:
result.add copyNode(c, templ, actual)
of nkNone..nkIdent, nkType..nkNilLit: # atom
@@ -84,8 +64,8 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
# "declarative" context (bug #9235).
if c.isDeclarative:
var res = copyNode(c, templ, actual)
for i in 0..<templ.len:
evalTemplateAux(templ[i], actual, c, res)
for i in 0 ..< sonsLen(templ):
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
else:
result.add newNodeI(nkEmpty, templ.info)
@@ -97,14 +77,10 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
not c.isDeclarative:
c.isDeclarative = true
isDeclarative = true
if (not c.isDeclarative) and templ.kind in nkCallKinds and isRunnableExamples(templ[0]):
# fixes bug #16993, bug #18054
discard
else:
var res = copyNode(c, templ, actual)
for i in 0..<templ.len:
evalTemplateAux(templ[i], actual, c, res)
result.add res
var res = copyNode(c, templ, actual)
for i in 0 ..< sonsLen(templ):
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
if isDeclarative: c.isDeclarative = false
const
@@ -130,7 +106,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
# now that we have working untyped parameters.
genericParams = if fromHlo: 0
else: s.ast[genericParamsPos].len
expectedRegularParams = s.typ.paramsLen
expectedRegularParams = s.typ.len-1
givenRegularParams = totalParams - genericParams
if givenRegularParams < 0: givenRegularParams = 0
@@ -142,22 +118,22 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
n.renderTree)
result = newNodeI(nkArgList, n.info)
for i in 1..givenRegularParams:
result.add n[i]
for i in 1 .. givenRegularParams:
result.addSon n[i]
# handle parameters with default values, which were
# not supplied by the user
for i in givenRegularParams+1..expectedRegularParams:
let default = s.typ.n[i].sym.ast
for i in givenRegularParams+1 .. expectedRegularParams:
let default = s.typ.n.sons[i].sym.ast
if default.isNil or default.kind == nkEmpty:
localError(conf, n.info, errWrongNumberOfArguments)
result.add newNodeI(nkEmpty, n.info)
addSon(result, newNodeI(nkEmpty, n.info))
else:
result.add default.copyTree
addSon(result, default.copyTree)
# add any generic parameters
for i in 1..genericParams:
result.add n[givenRegularParams + i]
# add any generic paramaters
for i in 1 .. genericParams:
result.addSon n.sons[givenRegularParams + i]
# to prevent endless recursion in template instantiation
const evalTemplateLimit* = 1000
@@ -175,20 +151,17 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
if x.kind in nkCallKinds:
for i in 1..<x.len:
if x[i].kind in nkCallKinds:
x[i].info = info
x.sons[i].info = info
else:
result = newNodeI(nkStmtListExpr, info)
var d = newNodeI(nkComesFrom, info)
d.add newSymNode(sym, info)
result.add d
result.add res
result.typ() = res.typ
result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef;
ic: IdentCache; instID: ref int;
idgen: IdGenerator;
fromHlo=false): PNode =
conf: ConfigRef; fromHlo=false): PNode =
inc(conf.evalTemplateCounter)
if conf.evalTemplateCounter > evalTemplateLimit:
globalError(conf, n.info, errTemplateInstantiationTooNested)
@@ -196,21 +169,18 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
# replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
var ctx = TemplCtx(owner: tmpl,
genSymOwner: genSymOwner,
config: conf,
ic: ic,
mapping: initSymMapping(),
instID: instID[],
idgen: idgen
)
var ctx: TemplCtx
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner
ctx.config = conf
initIdTable(ctx.mapping)
let body = tmpl.ast[bodyPos]
let body = tmpl.getBody
#echo "instantion of ", renderTree(body, {renderIds})
if isAtom(body):
result = newNodeI(nkPar, body.info)
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result[0]
if result.len == 1: result = result.sons[0]
else:
localError(conf, result.info, "illformed AST: " &
renderTree(result, {renderNoComments}))
@@ -218,13 +188,11 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
result = copyNode(body)
ctx.instLines = sfCallsite in tmpl.flags
if ctx.instLines:
setInfoRecursive(result, n.info)
for i in 0..<body.safeLen:
evalTemplateAux(body[i], args, ctx, result)
result.info = n.info
for i in 0 ..< safeLen(body):
evalTemplateAux(body.sons[i], args, ctx, result)
result.flags.incl nfFromTemplate
result = wrapInComesFrom(n.info, tmpl, result)
#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

@@ -1,131 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import lineinfos, ast, types
proc caseObjDefaultBranch*(obj: PNode; branch: Int128): int =
result = 0
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
return 1
template newZero(t: PType; info: TLineInfo; k = nkIntLit): PNode = newNodeIT(k, info, t)
proc expandDefault*(t: PType; info: TLineInfo): PNode
proc expandField(s: PSym; info: TLineInfo): PNode =
result = newNodeIT(nkExprColonExpr, info, s.typ)
result.add newSymNode(s)
result.add expandDefault(s.typ, info)
proc expandDefaultN(n: PNode; info: TLineInfo; res: PNode) =
case n.kind
of nkRecList:
for i in 0..<n.len:
expandDefaultN(n[i], info, res)
of nkRecCase:
res.add expandField(n[0].sym, info)
var branch = Zero
let constOrNil = n[0].sym.astdef
if constOrNil != nil:
branch = getOrdValue(constOrNil)
let selectedBranch = caseObjDefaultBranch(n, branch)
let b = lastSon(n[selectedBranch])
expandDefaultN b, info, res
of nkSym:
res.add expandField(n.sym, info)
else:
discard
proc expandDefaultObj(t: PType; info: TLineInfo; res: PNode) =
if t.baseClass != nil:
expandDefaultObj(t.baseClass, info, res)
expandDefaultN(t.n, info, res)
proc expandDefault(t: PType; info: TLineInfo): PNode =
case t.kind
of tyInt: result = newZero(t, info, nkIntLit)
of tyInt8: result = newZero(t, info, nkInt8Lit)
of tyInt16: result = newZero(t, info, nkInt16Lit)
of tyInt32: result = newZero(t, info, nkInt32Lit)
of tyInt64: result = newZero(t, info, nkInt64Lit)
of tyUInt: result = newZero(t, info, nkUIntLit)
of tyUInt8: result = newZero(t, info, nkUInt8Lit)
of tyUInt16: result = newZero(t, info, nkUInt16Lit)
of tyUInt32: result = newZero(t, info, nkUInt32Lit)
of tyUInt64: result = newZero(t, info, nkUInt64Lit)
of tyFloat: result = newZero(t, info, nkFloatLit)
of tyFloat32: result = newZero(t, info, nkFloat32Lit)
of tyFloat64: result = newZero(t, info, nkFloat64Lit)
of tyFloat128: result = newZero(t, info, nkFloat64Lit)
of tyChar: result = newZero(t, info, nkCharLit)
of tyBool: result = newZero(t, info, nkIntLit)
of tyEnum:
# Could use low(T) here to finally fix old language quirks
result = newZero(t, info, nkIntLit)
of tyRange:
# Could use low(T) here to finally fix old language quirks
result = expandDefault(skipModifier t, info)
of tyVoid: result = newZero(t, info, nkEmpty)
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned:
result = expandDefault(t.skipModifier, info)
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.hasElementType:
result = expandDefault(t.skipModifier, info)
else:
result = newZero(t, info, nkEmpty)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = expandDefault(t.n.typ, info)
else:
result = newZero(t, info, nkEmpty)
of tyArray:
result = newZero(t, info, nkBracket)
let n = toInt64(lengthOrd(nil, t))
for i in 0..<n:
result.add expandDefault(t.elementType, info)
of tyPtr, tyRef, tyProc, tyPointer, tyCstring:
result = newZero(t, info, nkNilLit)
of tyVar, tyLent:
let e = t.elementType
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = expandDefault(e, info)
else:
result = newZero(e, info, nkNilLit)
of tySet:
result = newZero(t, info, nkCurly)
of tyObject:
result = newNodeIT(nkObjConstr, info, t)
result.add newNodeIT(nkType, info, t)
expandDefaultObj(t, info, result)
of tyTuple:
result = newZero(t, info, nkTupleConstr)
for it in t.kids:
result.add expandDefault(it, info)
of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray:
result = newZero(t, info, nkBracket)
of tyString:
result = newZero(t, info, nkStrLit)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyError, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = newZero(t, info, nkEmpty) # bug indicator

File diff suppressed because it is too large Load Diff

View File

@@ -10,10 +10,8 @@
# This module implements Nim's standard template filter.
import
llstream, ast, msgs, options,
filters, lineinfos, pathutils
import std/strutils
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer, filters, lineinfos, pathutils
type
TParseState = enum
@@ -24,7 +22,7 @@ type
info: TLineInfo
indent, emitPar: int
x: string # the current input line
outp: PLLStream # the output will be parsed by parser
outp: PLLStream # the ouput will be parsed by pnimsyn
subsChar, nimDirective: char
emit, conc, toStr: string
curly, bracket, par: int
@@ -77,7 +75,7 @@ proc parseLine(p: var TTmplParser) =
let d = j
var keyw = ""
while j < len and p.x[j] in PatternChars:
keyw.add(p.x[j])
add(keyw, p.x[j])
inc(j)
scanPar(p, j)
@@ -201,22 +199,24 @@ proc parseLine(p: var TTmplParser) =
inc(j)
llStreamWrite(p.outp, "\\n\"")
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
outp: llStreamOpen(""), inp: stdin,
subsChar: charArg(conf, call, "subschar", 1, '$'),
nimDirective: charArg(conf, call, "metachar", 2, '#'),
emit: strArg(conf, call, "emit", 3, "result.add"),
conc: strArg(conf, call, "conc", 4, " & "),
toStr: strArg(conf, call, "tostring", 5, "$"),
x: newStringOfCap(120)
)
proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile,
call: PNode; conf: ConfigRef): PLLStream =
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line
p.info.line = p.info.line + 1'u16
while llStreamReadLine(p.inp, p.x):
inc p.info.line
p.info.line = p.info.line + 1'u16
parseLine(p)
newLine(p)
result = p.outp

View File

@@ -10,11 +10,9 @@
# This module implements Nim's simple filters and helpers for filters.
import
llstream, idents, ast, msgs, options,
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer, pathutils
import std/strutils
proc invalidPragma(conf: ConfigRef; n: PNode) =
localError(conf, n.info,
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
@@ -22,39 +20,32 @@ proc invalidPragma(conf: ConfigRef; n: PNode) =
proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
result = nil
if n.kind in {nkEmpty..nkNilLit}: return
for i in 1..<n.len:
if n[i].kind == nkExprEqExpr:
if n[i][0].kind != nkIdent: invalidPragma(conf, n)
if cmpIgnoreStyle(n[i][0].ident.s, name) == 0:
return n[i][1]
for i in 1 ..< sonsLen(n):
if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
return n.sons[i].sons[1]
elif i == pos:
return n[i]
return n.sons[i]
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else:
result = default(char)
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else:
result = ""
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else:
result = false
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")
@@ -64,7 +55,7 @@ proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, cal
var line = newStringOfCap(80)
while llStreamReadLine(stdin, line):
var stripped = strip(line, leading, trailing)
if pattern.len == 0 or startsWith(stripped, pattern):
if len(pattern) == 0 or startsWith(stripped, pattern):
llStreamWriteln(result, stripped)
else:
llStreamWriteln(result, line)
@@ -72,7 +63,7 @@ proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, cal
proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var sub = strArg(conf, call, "sub", 1, "")
if sub.len == 0: invalidPragma(conf, call)
if len(sub) == 0: invalidPragma(conf, call)
var by = strArg(conf, call, "by", 2, "")
result = llStreamOpen("")
var line = newStringOfCap(80)

89
compiler/forloops.nim Normal file
View File

@@ -0,0 +1,89 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements for loop detection for better C code generation.
import ast, astalgo
const
someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, 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 ..< safeLen(n):
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

@@ -9,14 +9,8 @@
## Module that implements ``gorge`` for the compiler.
import msgs, options, lineinfos, pathutils
import std/[os, osproc, streams]
when defined(nimPreviewSlimSystem):
import std/syncio
import ../dist/checksums/src/checksums/sha1
import msgs, std / sha1, os, osproc, streams, strutils, options,
lineinfos, pathutils
proc readOutput(p: Process): (string, int) =
result[0] = ""
@@ -30,11 +24,10 @@ proc readOutput(p: Process): (string, int) =
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
let workingDir = parentDir(toFullPath(conf, info))
result = ("", 0)
if cache.len > 0:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
var f: File = default(File)
var f: File
if optForceFullMake notin conf.globalOptions and open(f, filename):
result = (f.readAll, 0)
f.close
@@ -47,17 +40,12 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (str
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
p.close()
readSuccessful = true
# only cache successful runs:
if result[1] == 0:
writeFile(filename, result[0])
except IOError, OSError:
if not readSuccessful:
when defined(nimLegacyGorgeErrors):
result = ("", -1)
else:
result = ("Error running startProcess: " & getCurrentExceptionMsg(), -1)
if not readSuccessful: result = ("", -1)
else:
try:
var p = startProcess(cmd, workingDir,
@@ -66,9 +54,5 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (str
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
p.close()
except IOError, OSError:
when defined(nimLegacyGorgeErrors):
result = ("", -1)
else:
result = ("Error running startProcess: " & getCurrentExceptionMsg(), -1)
result = ("", -1)

File diff suppressed because it is too large Load Diff

View File

@@ -8,21 +8,18 @@
#
# This include implements the high level optimization pass.
# included from sem.nim
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
internalAssert c.config, n.kind == nkCall and n[0].kind == nkSym
internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# awful to semcheck before macro invocation, so we don't and treat
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
var rule: string =
if c.config.hasHint(hintPattern):
renderTree(n, {renderNoComments})
else:
""
let s = n[0].sym
var rule: string
if optHints in c.config.options and hintPattern in c.config.notes:
rule = renderTree(n, {renderNoComments})
let s = n.sons[0].sym
case s.kind
of skMacro:
result = semMacroExpr(c, n, orig, s)
@@ -30,7 +27,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
result = semTemplateExpr(c, n, s, {efFromHlo})
else:
result = semDirectOp(c, n, {})
if c.config.hasHint(hintPattern):
if optHints in c.config.options and hintPattern in c.config.notes:
message(c.config, orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'")
@@ -53,7 +50,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
c.patterns[i] = nil
if x.kind == nkStmtList:
assert x.len == 3
x[1] = evalPattern(c, x[1], result)
x.sons[1] = evalPattern(c, x.sons[1], result)
result = flattenStmts(x)
else:
result = evalPattern(c, x, result)
@@ -70,18 +67,18 @@ proc hlo(c: PContext, n: PNode): PNode =
# already processed (special cases in semstmts.nim)
result = n
else:
if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
n[0].kind == nkSym and
{sfGlobal, sfPure} <= n[0].sym.flags:
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
n.sons[0].kind == nkSym and
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)
if result == n:
# no optimization applied, try subtrees:
for i in 0..<result.safeLen:
let a = result[i]
for i in 0 ..< safeLen(result):
let a = result.sons[i]
let h = hlo(c, a)
if h != a: result[i] = h
if h != a: result.sons[i] = h
else:
# perform type checking, so that the replacement still fits:
if isEmptyType(n.typ) and isEmptyType(result.typ):
@@ -89,9 +86,9 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
result = fitNode(c, n.typ, result, n.info)
# optimization has been applied so check again:
result = commonOptimizations(c.graph, c.idgen, c.module, result)
result = commonOptimizations(c.graph, c.module, result)
result = hlo(c, result)
result = commonOptimizations(c.graph, c.idgen, c.module, result)
result = commonOptimizations(c.graph, c.module, result)
proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:

View File

@@ -1,178 +0,0 @@
## A BiTable is a table that can be seen as an optimized pair
## of `(Table[LitId, Val], Table[Val, LitId])`.
import std/hashes
import rodfiles
when defined(nimPreviewSlimSystem):
import std/assertions
type
LitId* = distinct uint32
BiTable*[T] = object
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template maxHash(t): untyped = high(t.keys)
template isFilled(x: LitId): bool = x.uint32 > 0'u32
proc `$`*(x: LitId): string {.borrow.}
proc `<`*(x, y: LitId): bool {.borrow.}
proc `<=`*(x, y: LitId): bool {.borrow.}
proc `==`*(x, y: LitId): bool {.borrow.}
proc hash*(x: LitId): Hash {.borrow.}
proc len*[T](t: BiTable[T]): int = t.vals.len
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
const
idStart = 1
template idToIdx(x: LitId): int = x.int - idStart
proc hasLitId*[T](t: BiTable[T]; x: LitId): bool =
let idx = idToIdx(x)
result = idx >= 0 and idx < t.vals.len
proc enlarge[T](t: var BiTable[T]) =
var n: seq[LitId]
newSeq(n, len(t.keys) * 2)
swap(t.keys, n)
for i in 0..high(n):
let eh = n[i]
if isFilled(eh):
var j = hash(t.vals[idToIdx eh]) and maxHash(t)
while isFilled(t.keys[j]):
j = nextTry(j, maxHash(t))
t.keys[j] = move n[i]
proc getKeyId*[T](t: BiTable[T]; v: T): LitId =
let origH = hash(v)
var h = origH and maxHash(t)
if t.keys.len != 0:
while true:
let litId = t.keys[h]
if not isFilled(litId): break
if t.vals[idToIdx t.keys[h]] == v: return litId
h = nextTry(h, maxHash(t))
return LitId(0)
proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId =
let origH = hash(v)
var h = origH and maxHash(t)
if t.keys.len != 0:
while true:
let litId = t.keys[h]
if not isFilled(litId): break
if t.vals[idToIdx t.keys[h]] == v: return litId
h = nextTry(h, maxHash(t))
# not found, we need to insert it:
if mustRehash(t.keys.len, t.vals.len):
enlarge(t)
# recompute where to insert:
h = origH and maxHash(t)
while true:
let litId = t.keys[h]
if not isFilled(litId): break
h = nextTry(h, maxHash(t))
else:
setLen(t.keys, 16)
h = origH and maxHash(t)
result = LitId(t.vals.len + idStart)
t.keys[h] = result
t.vals.add v
proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} =
let idx = idToIdx litId
assert idx < t.vals.len
result = t.vals[idx]
proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} =
let idx = idToIdx litId
assert idx < t.vals.len
result = t.vals[idx]
proc hash*[T](t: BiTable[T]): Hash =
## as the keys are hashes of the values, we simply use them instead
var h: Hash = 0
for i, n in pairs t.keys:
h = h !& hash((i, n))
result = !$h
proc store*[T](f: var RodFile; t: BiTable[T]) =
storeSeq(f, t.vals)
storeSeq(f, t.keys)
proc load*[T](f: var RodFile; t: var BiTable[T]) =
loadSeq(f, t.vals)
loadSeq(f, t.keys)
proc sizeOnDisc*(t: BiTable[string]): int =
result = 4
for x in t.vals:
result += x.len + 4
result += t.keys.len * sizeof(LitId)
when isMainModule:
var t: BiTable[string]
echo getOrIncl(t, "hello")
echo getOrIncl(t, "hello")
echo getOrIncl(t, "hello3")
echo getOrIncl(t, "hello4")
echo getOrIncl(t, "helloasfasdfdsa")
echo getOrIncl(t, "hello")
echo getKeyId(t, "hello")
echo getKeyId(t, "none")
for i in 0 ..< 100_000:
discard t.getOrIncl($i & "___" & $i)
for i in 0 ..< 100_000:
assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4
echo "begin"
echo t.vals.len
echo t.vals[0]
echo t.vals[1004]
echo "middle"
var tf: BiTable[float]
discard tf.getOrIncl(0.4)
discard tf.getOrIncl(16.4)
discard tf.getOrIncl(32.4)
echo getKeyId(tf, 32.4)
var f2 = open("testblah.bin", fmWrite)
echo store(f2, tf)
f2.close
var f1 = open("testblah.bin", fmRead)
var t2: BiTable[float]
echo f1.load(t2)
echo t2.vals.len
echo getKeyId(t2, 32.4)
echo "end"
f1.close

View File

@@ -1,180 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## New entry point into our C/C++ code generator. Ideally
## somebody would rewrite the old backend (which is 8000 lines of crufty Nim code)
## to work on packed trees directly and produce the C code as an AST which can
## then be rendered to text in a very simple manner. Unfortunately nobody wrote
## this code. So instead we wrap the existing cgen.nim and its friends so that
## we call directly into the existing code generation logic but avoiding the
## naive, outdated `passes` design. Thus you will see some
## `useAliveDataFromDce in flags` checks in the old code -- the old code is
## also doing cross-module dependency tracking and DCE that we don't need
## anymore. DCE is now done as prepass over the entire packed module graph.
import std/[packedsets, algorithm, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen,
pathutils, extccomp, msgs, modulepaths]
import packed_ast, ic, dce, rodfiles
proc unpackTree(g: ModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
var decoder = initPackedDecoder(g.config, g.cache)
result = loadNodes(decoder, g.packed, thisModule, tree, n)
proc setupBackendModule(g: ModuleGraph; m: var LoadedModule) =
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
assert g.backend != nil
var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config)
bmod.idgen = idgenFromLoadedModule(m)
proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) =
var bmod = BModuleList(g.backend).modules[m.module.position]
assert bmod != nil
bmod.flags.incl useAliveDataFromDce
bmod.alive = move alive[m.module.position]
for p in allNodes(m.fromDisk.topLevel):
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
for disp in getDispatchers(g):
genProcAux(bmod, disp)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
for x in mitems(m.fromDisk.emittedTypeInfo):
#echo "found type ", x, " for file ", int(origin)
g.emittedTypeInfo[x] = origin
proc addFileToLink(config: ConfigRef; m: PSym) =
let filename = AbsoluteFile toFullPath(config, m.position.FileIndex)
let ext =
if config.backend == backendCpp: ".nim.cpp"
elif config.backend == backendObjc: ".nim.m"
else: ".nim.c"
let cfile = changeFileExt(completeCfilePath(config,
mangleModuleName(config, filename).AbsoluteFile), ext)
let objFile = completeCfilePath(config, toObjFile(config, cfile))
if fileExists(objFile):
var cf = Cfile(nimname: m.name.s, cname: cfile,
obj: objFile,
flags: {CfileFlag.Cached})
addFileToCompile(config, cf)
when defined(debugDce):
import os, std/packedsets
proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) =
var f = rodfiles.create(asymFile.string)
f.storeHeader()
f.storeSection aliveSymsSection
f.storeSeq(s)
close f
template prepare {.dirty.} =
let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms")
var s = newSeqOfCap[int32](alive[position].len)
for a in items(alive[position]): s.add int32(a)
sort(s)
proc storeAliveSyms(config: ConfigRef; position: int; alive: AliveSyms) =
prepare()
storeAliveSymsImpl(asymFile, s)
proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool =
prepare()
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32] = @[]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:
result = false
else:
when defined(debugDce):
let oldAsSet = toPackedSet[int32](oldData)
let newAsSet = toPackedSet[int32](s)
echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err
echo "in old but not in new ", oldAsSet.difference(newAsSet), " number of entries in old ", oldAsSet.len
echo "in new but not in old ", newAsSet.difference(oldAsSet), " number of entries in new ", newAsSet.len
#if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0:
# echo "command failed"
result = true
storeAliveSymsImpl(asymFile, s)
proc genPackedModule(g: ModuleGraph, i: int; alive: var AliveSyms) =
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading, stored:
assert false
of storing, outdated:
storeAliveSyms(g.config, g.packed[i].module.position, alive)
generateCodeForModule(g, g.packed[i], alive)
closeRodFile(g, g.packed[i].module)
of loaded:
if g.packed[i].loadedButAliveSetChanged:
generateCodeForModule(g, g.packed[i], alive)
else:
addFileToLink(g.config, g.packed[i].module)
replayTypeInfo(g, g.packed[i], FileIndex(i))
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags)
proc generateCode*(g: ModuleGraph) =
## The single entry point, generate C(++) code for the entire
## Nim program aka `ModuleGraph`.
resetForBackend(g)
var alive = computeAliveSyms(g.packed, g.config)
when false:
for i in 0..<len(g.packed):
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
# First pass: Setup all the backend modules for all the modules that have
# changed:
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading, stored:
assert false
of storing, outdated:
setupBackendModule(g, g.packed[i])
of loaded:
# Even though this module didn't change, DCE might trigger a change.
# Consider this case: Module A uses symbol S from B and B does not use
# S itself. A is then edited not to use S either. Thus we have to
# recompile B in order to remove S from the final result.
if aliveSymsChanged(g.config, g.packed[i].module.position, alive):
g.packed[i].loadedButAliveSetChanged = true
setupBackendModule(g, g.packed[i])
# Second pass: Code generation.
let mainModuleIdx = g.config.projectMainIdx2.int
# We need to generate the main module last, because only then
# all init procs have been registered:
for i in 0..<len(g.packed):
if i != mainModuleIdx:
genPackedModule(g, i, alive)
if mainModuleIdx >= 0:
genPackedModule(g, mainModuleIdx, alive)

View File

@@ -1,169 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Dead code elimination (=DCE) for IC.
import std/[intsets, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, options, lineinfos, types]
import packed_ast, ic, bitabs
type
AliveSyms* = seq[IntSet]
AliveContext* = object ## Purpose is to fill the 'alive' field.
stack: seq[(int, TOptions, NodePos)] ## A stack for marking symbols as alive.
decoder: PackedDecoder ## We need a PackedDecoder for module ID address translations.
thisModule: int ## The module we're currently analysing for DCE.
alive: AliveSyms ## The final result of our computation.
options: TOptions
compilerProcs: Table[string, (int, int32)]
proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool =
## "Exported to C" procs are special (these are marked with '.exportc') because these
## must not be optimized away!
let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId]
let flags = symPtr.flags
# due to a bug/limitation in the lambda lifting, unused inner procs
# are not transformed correctly; issue (#411). However, the whole purpose here
# is to eliminate unused procs. So there is no special logic required for this case.
if sfCompileTime notin flags:
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: int32) =
## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will
## be analysed.
if not c.alive[module].containsOrIncl(item):
var body = g[module].fromDisk.syms[item].ast
if body != emptyNodeId:
let opt = g[module].fromDisk.syms[item].options
if g[module].fromDisk.syms[item].kind in routineKinds:
body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos)
c.stack.add((module, opt, NodePos(body)))
when false:
let nid = g[module].fromDisk.syms[item].name
if nid != LitId(0):
let name = g[module].fromDisk.strings[nid]
if name in ["nimFrame", "callDepthLimitReached"]:
echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item
proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string) =
let (module, item) = c.compilerProcs[name]
followLater(c, g, module, item)
proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind =
template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind
var t2 = translateId(t, g, c.thisModule, c.decoder.config)
result = t2.kind
while result in toSkip:
t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config)
result = t2.kind
proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
## Replicates the logic of `ccgexprs.genRangeChck`.
## XXX Refactor so that the duplicated logic is avoided. However, for now it's not clear
## the approach has enough merit.
var dest = loadTypeKind(n.typ, c, g, abstractVar)
if optRangeCheck notin c.options or dest in {tyUInt..tyUInt64}:
discard "no need to generate a check because it was disabled"
else:
let n0t = loadTypeKind(n.firstSon.typ, c, g, {})
if n0t in {tyUInt, tyUInt64}:
c.requestCompilerProc(g, "raiseRangeErrorNoArgs")
else:
let raiser =
case loadTypeKind(n.typ, c, g, abstractVarRange)
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
c.requestCompilerProc(g, raiser)
proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
## Marks the symbols we encounter when we traverse the AST at `tree[n]` as alive, unless
## it is purely in a declarative context (type section etc.).
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
discard "ignore non-sym atoms"
of nkSym:
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, tree[n].soperand)
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
let m = n1.litId
let item = tree[n2].soperand
let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
followLater(c, g, otherModule, item)
of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
nkCommentStmt, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkStaticStmt:
discard
of nkVarSection, nkLetSection, nkConstSection:
# XXX ignore the defining local variable name?
for son in sonsReadonly(tree, n):
aliveCode(c, g, tree, son)
of nkChckRangeF, nkChckRange64, nkChckRange:
rangeCheckAnalysis(c, g, tree, n)
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
if n.firstSon.kind == nkSym and isNotGeneric(n):
let item = tree[n.firstSon].soperand
if isExportedToC(c, g, item):
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, item)
else:
for son in sonsReadonly(tree, n):
aliveCode(c, g, tree, son)
proc followNow(c: var AliveContext; g: PackedModuleGraph) =
## Mark all entries in the stack. Marking can add more entries
## to the stack but eventually we have looked at every alive symbol.
while c.stack.len > 0:
let (modId, opt, ast) = c.stack.pop()
c.thisModule = modId
c.options = opt
aliveCode(c, g, g[modId].fromDisk.bodies, ast)
proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
## Entry point for our DCE algorithm.
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
thisModule: -1, alive: newSeq[IntSet](g.len),
options: conf.options)
for i in countdown(len(g)-1, 0):
if g[i].status != undefined:
c.thisModule = i
for p in allNodes(g[i].fromDisk.topLevel):
aliveCode(c, g, g[i].fromDisk.topLevel, p)
followNow(c, g)
result = move(c.alive)
proc isAlive*(a: AliveSyms; module: int, item: int32): bool =
## Backends use this to query if a symbol is `alive` which means
## we need to produce (C/C++/etc) code for it.
result = a[module].contains(item)

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