mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 11:23:40 +00:00
Compare commits
261 Commits
v1.0.2
...
version-1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a1f77cb18 | ||
|
|
a57b1d7fac | ||
|
|
f577229a6f | ||
|
|
b057bb6654 | ||
|
|
af2b7ff28f | ||
|
|
f964fdbec0 | ||
|
|
d5a7fb8ea0 | ||
|
|
22e71cbc0f | ||
|
|
f40c941580 | ||
|
|
e5a3f30519 | ||
|
|
286b94e7de | ||
|
|
52155b5587 | ||
|
|
9edb694173 | ||
|
|
8be2614608 | ||
|
|
bd2b298244 | ||
|
|
311b7aaf37 | ||
|
|
a13fd00729 | ||
|
|
a8c706760c | ||
|
|
86298e30d9 | ||
|
|
19440baa80 | ||
|
|
a0d62e654a | ||
|
|
67d9848027 | ||
|
|
4663a261f9 | ||
|
|
69322f86de | ||
|
|
f29e7cfdcd | ||
|
|
bf85f35226 | ||
|
|
f76ed447c2 | ||
|
|
0ca09f64cf | ||
|
|
52ad63bc22 | ||
|
|
98073624f7 | ||
|
|
c32e002e63 | ||
|
|
5b920dc01f | ||
|
|
4234a6373a | ||
|
|
f6ada8874a | ||
|
|
4088d7f2ae | ||
|
|
ad29fe8946 | ||
|
|
52a3d38bda | ||
|
|
1b530b5897 | ||
|
|
9193c85b61 | ||
|
|
758a54ce23 | ||
|
|
cc49902fa2 | ||
|
|
8ec5dc1969 | ||
|
|
dc5e8fc39d | ||
|
|
37c3465081 | ||
|
|
f713c54166 | ||
|
|
dc519a539b | ||
|
|
acfd1b272d | ||
|
|
53fc3924a0 | ||
|
|
95d4961612 | ||
|
|
b5ec602763 | ||
|
|
9a649d91ad | ||
|
|
e6cdbad6a5 | ||
|
|
e79e0616b1 | ||
|
|
6b555e78b7 | ||
|
|
36619e3569 | ||
|
|
f4ae3ab729 | ||
|
|
289e35166b | ||
|
|
338f25b56f | ||
|
|
872795e18a | ||
|
|
58515f6042 | ||
|
|
59a35563cf | ||
|
|
66c21b9e95 | ||
|
|
94a855893e | ||
|
|
46c9eb5904 | ||
|
|
9cc5927a99 | ||
|
|
85fb709020 | ||
|
|
3483fdd43c | ||
|
|
507d7a9daa | ||
|
|
75f427a57b | ||
|
|
b0f71b051f | ||
|
|
b036c57dd3 | ||
|
|
339c08ce5b | ||
|
|
5c266cdf05 | ||
|
|
234f4a27e1 | ||
|
|
c7cf5d4e73 | ||
|
|
561092003d | ||
|
|
5b168d3f9b | ||
|
|
965f7ebf54 | ||
|
|
da7a6f4875 | ||
|
|
ff9d59747d | ||
|
|
6d5761d488 | ||
|
|
931a70b123 | ||
|
|
0c6c11f2aa | ||
|
|
d15cbb229a | ||
|
|
c90bbe3201 | ||
|
|
45b53ee36f | ||
|
|
20e5173cca | ||
|
|
46d785aa40 | ||
|
|
71027936e8 | ||
|
|
f89db4915f | ||
|
|
d4f961b08a | ||
|
|
8cf8879941 | ||
|
|
5a1ed8f4d4 | ||
|
|
fec5d04afc | ||
|
|
3dd84b36fd | ||
|
|
490bf10a6c | ||
|
|
50de7732ed | ||
|
|
df6fbf6521 | ||
|
|
5cae61ce21 | ||
|
|
122ac6775a | ||
|
|
73c83905af | ||
|
|
22d60a53f7 | ||
|
|
265f565be3 | ||
|
|
6673934482 | ||
|
|
8a8fddcc40 | ||
|
|
99e6d328ec | ||
|
|
2dcf32f5c8 | ||
|
|
6f79408576 | ||
|
|
17ae3016c7 | ||
|
|
02d7a181f6 | ||
|
|
349039678a | ||
|
|
b64e109fdc | ||
|
|
26681769e8 | ||
|
|
c160b2161e | ||
|
|
fbf28d1ce7 | ||
|
|
b6924383df | ||
|
|
cfd0ae4adb | ||
|
|
04e70f1f4b | ||
|
|
14e1f82f42 | ||
|
|
2304af294f | ||
|
|
5768dd08cd | ||
|
|
8cdba8ea29 | ||
|
|
3bf9ef537f | ||
|
|
bdb679c487 | ||
|
|
a9fa981000 | ||
|
|
3a47e433be | ||
|
|
6d65e69b10 | ||
|
|
faa4720dcf | ||
|
|
6d3a1fcda6 | ||
|
|
bf24379af5 | ||
|
|
0591cc2f8a | ||
|
|
89b39ee8fe | ||
|
|
d038e1b750 | ||
|
|
a6846b81eb | ||
|
|
de43bdfa70 | ||
|
|
25a4026cda | ||
|
|
2e9d595f92 | ||
|
|
13ad15dffe | ||
|
|
0ff510ca07 | ||
|
|
16eaebbf51 | ||
|
|
61c8a2b1e7 | ||
|
|
b64d59635c | ||
|
|
cd28e01a1a | ||
|
|
2f557f74e5 | ||
|
|
f1ec998e71 | ||
|
|
a3d5a3ca9b | ||
|
|
74350447ed | ||
|
|
83c1ec46ce | ||
|
|
29b6dd6196 | ||
|
|
8994e8f2e2 | ||
|
|
3e76777de8 | ||
|
|
d237b73e6e | ||
|
|
7134d57cd4 | ||
|
|
17ddc7e894 | ||
|
|
26331a9005 | ||
|
|
6d2884be9c | ||
|
|
e636b47429 | ||
|
|
4028514eeb | ||
|
|
8b956dba09 | ||
|
|
78f9933b8f | ||
|
|
46be787fb2 | ||
|
|
7afe6b1f4b | ||
|
|
f9d30dc1e5 | ||
|
|
89b244a2f5 | ||
|
|
4c120c1978 | ||
|
|
bc601a62a2 | ||
|
|
9167eb6c89 | ||
|
|
7c4bc63b00 | ||
|
|
261592de18 | ||
|
|
f52395f2d8 | ||
|
|
d807c4b7c0 | ||
|
|
65aa564c54 | ||
|
|
0f05a0dd5b | ||
|
|
512727d75e | ||
|
|
00408a4554 | ||
|
|
09be379b91 | ||
|
|
6f520fb6d9 | ||
|
|
789a984c1e | ||
|
|
1edb81b66c | ||
|
|
340c9248f1 | ||
|
|
9ec09bfa55 | ||
|
|
a13f623f16 | ||
|
|
5129a1e88d | ||
|
|
3f6a08d5b0 | ||
|
|
299f1e99cd | ||
|
|
a02a4d8fc5 | ||
|
|
10935a71ed | ||
|
|
d0e8ad17b5 | ||
|
|
60100a9a64 | ||
|
|
c8998c498f | ||
|
|
97e0ce3c75 | ||
|
|
aa7b0c8581 | ||
|
|
d6f52f3cef | ||
|
|
fa15083cc9 | ||
|
|
c868f1ef67 | ||
|
|
8f0b891e68 | ||
|
|
4084ef19a3 | ||
|
|
7d444ff04c | ||
|
|
aaf06dba1b | ||
|
|
0e1dd54fee | ||
|
|
c78cee697d | ||
|
|
4c4116d63a | ||
|
|
9d17d02734 | ||
|
|
e8578c926e | ||
|
|
5937c40928 | ||
|
|
f3e088f11a | ||
|
|
39122ecd93 | ||
|
|
7ea60f78b5 | ||
|
|
ee260dd838 | ||
|
|
23881b188e | ||
|
|
e5f968da0c | ||
|
|
cb2f8d4d39 | ||
|
|
e2aa1d6d84 | ||
|
|
beaead0fd1 | ||
|
|
763486a3aa | ||
|
|
d61dd518d9 | ||
|
|
2a292c0e71 | ||
|
|
814e237ab6 | ||
|
|
8324b7a86d | ||
|
|
7ccefbc422 | ||
|
|
8fddc8e8a1 | ||
|
|
f47d977f6d | ||
|
|
a5c98bf3af | ||
|
|
93b868bff9 | ||
|
|
274f94c84a | ||
|
|
1ff3494dab | ||
|
|
1d43c8620e | ||
|
|
f5e096b13f | ||
|
|
29c099ccd1 | ||
|
|
6887d6de80 | ||
|
|
7c2d64c18d | ||
|
|
f991d2c1fd | ||
|
|
d6ae4e00f4 | ||
|
|
2a2a9110b2 | ||
|
|
4a7ccfa333 | ||
|
|
476d677c6f | ||
|
|
ee0c1482d7 | ||
|
|
731d1dff84 | ||
|
|
e02dc971f5 | ||
|
|
5f77d5ad85 | ||
|
|
f69dac8038 | ||
|
|
338f43f305 | ||
|
|
d1d8cd1000 | ||
|
|
f042acc535 | ||
|
|
eac5452082 | ||
|
|
80861998c7 | ||
|
|
c1fd463834 | ||
|
|
dedff71ca0 | ||
|
|
cd60067638 | ||
|
|
bf047d6ef1 | ||
|
|
313b2f0d71 | ||
|
|
f5269876ea | ||
|
|
89738fd95d | ||
|
|
ab51a8e08b | ||
|
|
6ffe5ee7e8 | ||
|
|
ab2a8344b3 | ||
|
|
fc9cccccd3 | ||
|
|
faf5ffd970 | ||
|
|
6fc9327ebf | ||
|
|
93aeb9c825 | ||
|
|
59e8ca721e |
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Avoids changelog conflicts by assuming additions-only, which is by far the common case.
|
||||
# In the rare case where branch b1 rebases against branch b2 and both branches
|
||||
# modified the same changelog entry, you'll end up with that changelog entry
|
||||
# duplicated, which is easily identifiable and fixable.
|
||||
/changelog.md merge=union
|
||||
|
||||
@@ -51,6 +51,8 @@ addons:
|
||||
- libsdl1.2-dev
|
||||
- libgc-dev
|
||||
- libsfml-dev
|
||||
- libc6-dbg
|
||||
- valgrind
|
||||
homebrew:
|
||||
packages:
|
||||
- boehmgc
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
@@ -33,9 +42,10 @@ steps:
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
displayName: 'Checkout csources'
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources
|
||||
displayName: 'Checkout Nim csources'
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
@@ -46,26 +56,20 @@ steps:
|
||||
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
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
displayName: 'Install dependencies (amd64 Linux)'
|
||||
condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
|
||||
|
||||
- bash: |
|
||||
sudo dpkg --add-architecture i386
|
||||
|
||||
# Downgrade llvm, libgcc and libstdc++:
|
||||
# Downgrade llvm:
|
||||
# - llvm has to be downgraded to have 32bit version installed for sfml.
|
||||
# - libgcc and libstdc++ have to be downgraded as an optimization to
|
||||
# prevent the use of the toolchain ppa, which has a terrible download
|
||||
# speed.
|
||||
cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel
|
||||
Package: libllvm6.0 libgcc1 libstdc++6
|
||||
Package: libllvm6.0
|
||||
Pin: origin "azure.archive.ubuntu.com"
|
||||
Pin-Priority: 1001
|
||||
|
||||
Package: *
|
||||
Pin: release o=LP-PPA-ubuntu-toolchain-r-test
|
||||
Pin-Priority: 100
|
||||
EOF
|
||||
|
||||
sudo apt-fast update -qq
|
||||
@@ -119,8 +123,19 @@ steps:
|
||||
make -v
|
||||
displayName: 'System information'
|
||||
|
||||
- bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)"
|
||||
displayName: 'Get csources version'
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)'
|
||||
path: csources/bin
|
||||
displayName: 'Restore built csources'
|
||||
|
||||
|
||||
- bash: |
|
||||
ncpu=
|
||||
ext=
|
||||
case '$(Agent.OS)' in
|
||||
'Linux')
|
||||
ncpu=$(nproc)
|
||||
@@ -130,19 +145,24 @@ steps:
|
||||
;;
|
||||
'Windows_NT')
|
||||
ncpu=$NUMBER_OF_PROCESSORS
|
||||
ext=.exe
|
||||
;;
|
||||
esac
|
||||
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
|
||||
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU)
|
||||
displayName: 'Build csources'
|
||||
if [[ -x csources/bin/nim$ext ]]; then
|
||||
echo "Found cached compiler, skipping build"
|
||||
else
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no
|
||||
fi
|
||||
cp csources/bin/nim$ext bin
|
||||
displayName: 'Build 1-stage compiler from csources'
|
||||
|
||||
- bash: nim c koch
|
||||
displayName: 'Build koch'
|
||||
|
||||
# set result to omit the "bash exited with error code '1'" message
|
||||
- bash: |
|
||||
./koch runCI || echo '##vso[task.complete result=Failed]'
|
||||
- bash: ./koch runCI || echo '##vso[task.complete result=Failed]'
|
||||
displayName: 'Run CI'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
|
||||
12
changelog.md
12
changelog.md
@@ -1,4 +1,4 @@
|
||||
# v1.1 - xxxx-xx-xx
|
||||
# v1.0.8 - xxxx-xx-xx
|
||||
|
||||
|
||||
## Changes affecting backwards compatibility
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
### Breaking changes in the standard library
|
||||
|
||||
- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it
|
||||
was an oversight to be included in v1.0.
|
||||
|
||||
|
||||
|
||||
### Breaking changes in the compiler
|
||||
@@ -14,7 +17,11 @@
|
||||
|
||||
|
||||
## Library additions
|
||||
- Fixed buffer overflow bugs in `net`
|
||||
|
||||
- Added `sections` iterator in `parsecfg`.
|
||||
|
||||
- Added `browsers.osOpen` const alias for the operating system specific *"open"* command.
|
||||
|
||||
|
||||
## Library changes
|
||||
@@ -25,6 +32,9 @@
|
||||
|
||||
|
||||
|
||||
- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to
|
||||
hangs if a process had both reads from stdin and writes (eg to stdout).
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
|
||||
@@ -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 "heterogenous" slice type ``system.HSlice`` that takes 2
|
||||
support. There is a new "heterogeneous" 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))
|
||||
|
||||
56
changelogs/changelog_1_0_2.md
Normal file
56
changelogs/changelog_1_0_2.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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
|
||||
75
changelogs/changelog_1_0_4.md
Normal file
75
changelogs/changelog_1_0_4.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# v1.0.4 - 2019-11-26
|
||||
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- 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. (#12688)
|
||||
|
||||
- Add `or detectOs(Manjaro)` (#12587)
|
||||
|
||||
- --os:ios needs to imply defined(macosx) (#12585)
|
||||
|
||||
- export nim.cfg parser (#12602)
|
||||
|
||||
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fixed "gorge(Ex) fails after a few calls on OSX"
|
||||
([#12337](https://github.com/nim-lang/Nim/issues/12337))
|
||||
- Fixed "Improve posix module"
|
||||
([#10723](https://github.com/nim-lang/Nim/issues/10723))
|
||||
- Fixed "nim check allows gorgeEx but doesn't allow writeFile"
|
||||
([#12491](https://github.com/nim-lang/Nim/issues/12491))
|
||||
- Fixed "Low level arithmetics bug: -3 mod 7 == 3"
|
||||
([#12514](https://github.com/nim-lang/Nim/issues/12514))
|
||||
- Fixed "Broken link to c2nim in backends.rst/.html"
|
||||
([#12537](https://github.com/nim-lang/Nim/issues/12537))
|
||||
- Fixed "generic argument with default value causes incorrect generic type resolution"
|
||||
([#12528](https://github.com/nim-lang/Nim/issues/12528))
|
||||
- Fixed "regression: compiler/vmgen.nim(354, 20) `false` leaking temporary 10 slotTempInt [AssertionError]
|
||||
([#12547](https://github.com/nim-lang/Nim/issues/12547))
|
||||
- Fixed "Compile/link broken for nim (64-bit only) on Windows"
|
||||
([#12536](https://github.com/nim-lang/Nim/issues/12536))
|
||||
- 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 "[1.0.0] Cannot compile anything with --cpu:avr"
|
||||
([#12395](https://github.com/nim-lang/Nim/issues/12395))
|
||||
- Fixed "Compiler crash with invalid object variant"
|
||||
([#12379](https://github.com/nim-lang/Nim/issues/12379))
|
||||
- Fixed "push pragma is silently ignored if position is in front of import statement"
|
||||
([#5050](https://github.com/nim-lang/Nim/issues/5050))
|
||||
- Fixed "Error with strformat + asyncdispatch + const"
|
||||
([#12612](https://github.com/nim-lang/Nim/issues/12612))
|
||||
- Fixed "The --nimblePath is additive; need a pain-free workaround"
|
||||
([#12601](https://github.com/nim-lang/Nim/issues/12601))
|
||||
- Fixed "nim.cfg syntax for --define:FOO:VAL undocumented or absent"
|
||||
([#12367](https://github.com/nim-lang/Nim/issues/12367))
|
||||
- Fixed "vm string literals do not work when generated by a macro"
|
||||
([#12670](https://github.com/nim-lang/Nim/issues/12670))
|
||||
- Fixed "StaticRead does force a recompile if static file changes."
|
||||
([#12663](https://github.com/nim-lang/Nim/issues/12663))
|
||||
- Fixed crash in terminate handler
|
||||
([#12572](https://github.com/nim-lang/Nim/pull/12572))
|
||||
- Fixed newLit for objects having string fields
|
||||
([#12542](https://github.com/nim-lang/Nim/pull/12542))
|
||||
|
||||
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
- Documentation Math module (#12460)
|
||||
- Fix many broken links and prefer relative links within docs (#12463)
|
||||
- sequtils: replace deprecated 'random' call within example (#12515)
|
||||
- integer literal documentation (#12513)
|
||||
- Fix code style errors (#12545)
|
||||
- fix several typos in documentation and comments (#12553)
|
||||
- Add docs to better distinguish among getProjectPath, getCurrentDir and currentSourcePath (#12565)
|
||||
- doc/tut3.rst: Fix typo in Introduction (#12607)
|
||||
- Add links to packaging and distro pages (#12603)
|
||||
- fix documentation of `$`\*(dt: DateTime) (#12660)
|
||||
- Clarifies experimental / parallel example on manual.rst (#12472)
|
||||
- Fix wrong section hierarchy in the manual (#12724)
|
||||
68
changelogs/changelog_1_0_6.md
Normal file
68
changelogs/changelog_1_0_6.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# v1.0.6 - 2020-01-24
|
||||
|
||||
|
||||
## Bugfixes
|
||||
|
||||
### Fixed issues
|
||||
|
||||
- Fixed "Nim stdlib style issues with --styleCheck:error"
|
||||
([#12687](https://github.com/nim-lang/Nim/issues/12687))
|
||||
- Fixed "new(ref MyObject) doesn't work at compile time"
|
||||
([#12488](https://github.com/nim-lang/Nim/issues/12488))
|
||||
- Fixed "Accessing the wrong variant field in the VM does not trigger the appropriate error message"
|
||||
([#11727](https://github.com/nim-lang/Nim/issues/11727))
|
||||
- Fixed "orderedTable.del() crashes with unitialized table"
|
||||
([#12798](https://github.com/nim-lang/Nim/issues/12798))
|
||||
- Fixed "semfold bug with negative value * 0"
|
||||
([#12783](https://github.com/nim-lang/Nim/issues/12783))
|
||||
- Fixed "nimsuggest `use` command does not return all instances of symbol"
|
||||
([#12832](https://github.com/nim-lang/Nim/issues/12832))
|
||||
- Fixed "Codegen ICE in allPathsAsgnResult"
|
||||
([#12827](https://github.com/nim-lang/Nim/issues/12827))
|
||||
- Fixed "Static[T] + syntactic error in the for loop = compiler crash"
|
||||
([#12148](https://github.com/nim-lang/Nim/issues/12148))
|
||||
- Fixed "Incorrect unused import warning involving templates and tables"
|
||||
([#12885](https://github.com/nim-lang/Nim/issues/12885))
|
||||
- Fixed "regression(1.0.4): undeclared identifier: 'readLines'; plus another regression and bug"
|
||||
([#13013](https://github.com/nim-lang/Nim/issues/13013))
|
||||
- Fixed "`nim doc` treats `export localSymbol` incorrectly"
|
||||
([#13100](https://github.com/nim-lang/Nim/issues/13100))
|
||||
- Fixed "symbols not defined in the grammar"
|
||||
([#10665](https://github.com/nim-lang/Nim/issues/10665))
|
||||
- Fixed "nim-gdb is missing from all released packages"
|
||||
([#13104](https://github.com/nim-lang/Nim/issues/13104))
|
||||
- Fixed "[JS] Move is not defined"
|
||||
([#9674](https://github.com/nim-lang/Nim/issues/9674))
|
||||
- Fixed "Error: usage of 'isNil' is a user-defined error"
|
||||
([#11440](https://github.com/nim-lang/Nim/issues/11440))
|
||||
|
||||
|
||||
### Other bugfixes
|
||||
|
||||
- make addQuoted work on nimscript (#12717)
|
||||
- fix db_mysql getRow() when column is null error raised (#12806)
|
||||
- Fixed objects being erroneously zeroed out before object construction (#12814)
|
||||
- added cstrutils (#12858): fixed for 'csuCmpIgnoreStyle' error on hotcodereloading
|
||||
- Better clang_cl support (#12896)
|
||||
- fix cmdline bugs affecting nimBetterRun correctness (#12933)
|
||||
- fixes a bug that kept sugar.collect from working with for loop macros
|
||||
- Path substitution for --out and --outdir (#12796)
|
||||
- fix crash due to errant symbols in nim.cfg (#13073)
|
||||
- Allow `-o` option for `buildIndex` (#13037)
|
||||
- Deleted misplaced separator (#13085): Misplaced separator, which was constantly breaking compilation on Haiku OS, was deleted.
|
||||
- fixes an asyncftpclient bug; refs #13096
|
||||
- fix the ftp store function read the local file bug (#13108)
|
||||
- fix rtti sizeof for varargs in global scope (#13125)
|
||||
- Correctly remove a key from CountTable when it is set to zero.
|
||||
- fixes the distros.nim regression
|
||||
- fixes a critical times.nim bug reported on IRC
|
||||
- c_fflush() the rawWrite() buffer
|
||||
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
- Fixed "Documentation, Testament missing from "Tools available with Nim""
|
||||
([#12251](https://github.com/nim-lang/Nim/issues/12251))
|
||||
- Manual update: custom exceptions (#12847)
|
||||
- times/getClockStr(): fix mistake in doc
|
||||
- Fix typo and improve in code-block of 'lib/pure/parseutils.nim'
|
||||
@@ -193,4 +193,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
if res != arNo:
|
||||
result = res
|
||||
if res == arYes: break
|
||||
of nkBracket:
|
||||
if b.len > 0:
|
||||
result = isPartOf(a, b[0])
|
||||
else: discard
|
||||
|
||||
@@ -291,10 +291,6 @@ type
|
||||
const
|
||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||
|
||||
sfCursor* = sfDispatcher
|
||||
# local variable has been computed to be a "cursor".
|
||||
# see cursors.nim for details about what that means.
|
||||
|
||||
sfAllUntyped* = sfVolatile # macro or template is immediately expanded \
|
||||
# in a generic context
|
||||
|
||||
@@ -540,6 +536,7 @@ type
|
||||
tfContravariant # contravariant generic param
|
||||
tfCheckedForDestructor # type was checked for having a destructor.
|
||||
# If it has one, t.destructor is not nil.
|
||||
tfIncompleteStruct # treat this type as if it had sizeof(pointer)
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
@@ -581,7 +578,6 @@ type
|
||||
const
|
||||
routineKinds* = {skProc, skFunc, skMethod, skIterator,
|
||||
skConverter, skMacro, skTemplate}
|
||||
tfIncompleteStruct* = tfVarargs
|
||||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
|
||||
@@ -858,7 +858,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if optBoundsCheck in p.options and ty.kind != tyUncheckedArray:
|
||||
if not isConstExpr(y):
|
||||
# semantic pass has already checked for const index expressions
|
||||
if firstOrd(p.config, ty) == 0:
|
||||
if firstOrd(p.config, ty) == 0 and lastOrd(p.config, ty) >= 0:
|
||||
if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)):
|
||||
linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError2($1, $2);$n",
|
||||
[rdCharLoc(b), intLiteral(lastOrd(p.config, ty))])
|
||||
@@ -1206,7 +1206,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||
if sizeExpr.isNil:
|
||||
sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)]
|
||||
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optOwnedRefs in p.config.globalOptions:
|
||||
b.r = ropecg(p.module, "($1) #nimNewObj($2)",
|
||||
[getTypeDesc(p.module, typ), sizeExpr])
|
||||
genAssignment(p, a, b, {})
|
||||
@@ -1484,7 +1484,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
result = ropecg(p.module, "#isObj($1.m_type, $2)",
|
||||
[a, genTypeInfo2Name(p.module, dest)])
|
||||
else:
|
||||
@@ -1535,7 +1535,7 @@ proc genOf(p: BProc, n: PNode, d: var TLoc) =
|
||||
genOf(p, n.sons[1], n.sons[2].typ, d)
|
||||
|
||||
proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
localError(p.config, e.info, "'repr' is not available for --newruntime")
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
@@ -1735,9 +1735,9 @@ template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
|
||||
|
||||
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
|
||||
case int(getSize(p.config, skipTypes(e.sons[1].typ, abstractVar)))
|
||||
of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)")
|
||||
of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)")
|
||||
of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)")
|
||||
of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)")
|
||||
of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)")
|
||||
of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)")
|
||||
of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)")
|
||||
else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)")
|
||||
|
||||
@@ -1824,7 +1824,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mCard:
|
||||
if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)")
|
||||
else: unaryExprChar(p, e, d, "#countBits64($1)")
|
||||
of mLtSet: binaryExprChar(p, e, d, "(($1 & ~ $2 ==0)&&($1 != $2))")
|
||||
of mLtSet: binaryExprChar(p, e, d, "((($1 & ~ $2)==0)&&($1 != $2))")
|
||||
of mLeSet: binaryExprChar(p, e, d, "(($1 & ~ $2)==0)")
|
||||
of mEqSet: binaryExpr(p, e, d, "($1 == $2)")
|
||||
of mMulSet: binaryExpr(p, e, d, "($1 & $2)")
|
||||
@@ -1931,7 +1931,8 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
|
||||
var a: TLoc
|
||||
var dest = skipTypes(n.typ, abstractVar)
|
||||
if optRangeCheck notin p.options:
|
||||
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
putIntoDest(p, d, n, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
|
||||
@@ -2148,7 +2149,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
|
||||
of mStrToStr, mUnown: expr(p, e.sons[1], d)
|
||||
of mEnumToStr:
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
genEnumToStr(p, e, d)
|
||||
else:
|
||||
genRepr(p, e, d)
|
||||
@@ -2423,7 +2424,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
add(r, ".Sup")
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
let checkFor = if optNimV2 in p.config.globalOptions:
|
||||
let checkFor = if optTinyRtti in p.config.globalOptions:
|
||||
genTypeInfo2Name(p.module, dest)
|
||||
else:
|
||||
genTypeInfo(p.module, dest, n.info)
|
||||
|
||||
@@ -17,7 +17,7 @@ const
|
||||
|
||||
proc getTraverseProc(p: BProc, v: PSym): Rope =
|
||||
if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and
|
||||
optNimV2 notin p.config.globalOptions and
|
||||
optOwnedRefs notin p.config.globalOptions and
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
# we register a specialized marked proc here; this has the advantage
|
||||
# that it works out of the box for thread local storage then :-)
|
||||
@@ -692,7 +692,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
[e, makeCString(typ.sym.name.s),
|
||||
makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s),
|
||||
quotedFilename(p.config, t.info), toLinenumber(t.info)])
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optOwnedRefs in p.config.globalOptions:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [e])
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
@@ -1057,7 +1057,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
for j in 0 .. blen - 2:
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
let checkFor = if optNimV2 in p.config.globalOptions:
|
||||
let checkFor = if optTinyRtti in p.config.globalOptions:
|
||||
genTypeInfo2Name(p.module, t[i][j].typ)
|
||||
else:
|
||||
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
|
||||
@@ -1220,7 +1220,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
getTemp(p, a.t, tmp)
|
||||
expr(p, e.sons[1], tmp)
|
||||
let field = dotExpr.sons[1].sym
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let t = dotExpr[0].typ.skipTypes(abstractInst)
|
||||
var oldVal, newVal: TLoc
|
||||
genCaseObjDiscMapping(p, e[0], t, field, oldVal)
|
||||
|
||||
@@ -17,7 +17,7 @@ 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)
|
||||
@@ -104,7 +104,8 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
elif containsGarbageCollectedRef(typ.lastSon):
|
||||
# destructor based seqs are themselves not traced but their data is, if
|
||||
# they contain a GC'ed type:
|
||||
genTraverseProcSeq(c, accessor, typ)
|
||||
lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
|
||||
#genTraverseProcSeq(c, accessor, typ)
|
||||
of tyString:
|
||||
if tfHasAsgn notin typ.flags:
|
||||
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
|
||||
|
||||
@@ -1365,7 +1365,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
of tySet: genSetInfo(m, t, result, info)
|
||||
of tyEnum: genEnumInfo(m, t, result, info)
|
||||
of tyObject:
|
||||
if optNimV2 in m.config.globalOptions:
|
||||
if optTinyRtti in m.config.globalOptions:
|
||||
genObjectInfoV2(m, t, origType, result, info)
|
||||
else:
|
||||
genObjectInfo(m, t, origType, result, info)
|
||||
|
||||
@@ -347,7 +347,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
s = skipTypes(s.sons[0], skipPtrs)
|
||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
|
||||
of frEmbedded:
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
localError(p.config, p.prc.info,
|
||||
"complex object initialization is not supported with --newruntime")
|
||||
# worst case for performance:
|
||||
@@ -931,11 +931,12 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
|
||||
# assignment this is not good enough! The only pattern we allow for
|
||||
# is 'finally: result = x'
|
||||
result = InitSkippable
|
||||
for it in n:
|
||||
if it.kind == nkFinally:
|
||||
result = allPathsAsgnResult(it.lastSon)
|
||||
allPathsInBranch(n[0])
|
||||
for i in 1..<n.len:
|
||||
if n[i].kind == nkFinally:
|
||||
result = allPathsAsgnResult(n[i].lastSon)
|
||||
else:
|
||||
allPathsInBranch(it.lastSon)
|
||||
allPathsInBranch(n[i].lastSon)
|
||||
else:
|
||||
for i in 0..<safeLen(n):
|
||||
allPathsInBranch(n[i])
|
||||
|
||||
@@ -29,10 +29,7 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
|
||||
proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
|
||||
self.processCmdLine(passCmd1, "", conf)
|
||||
if self.supportsStdinFile and conf.projectName == "-":
|
||||
conf.projectName = "stdinfile"
|
||||
conf.projectFull = AbsoluteFile "stdinfile"
|
||||
conf.projectPath = AbsoluteDir getCurrentDir()
|
||||
conf.projectIsStdin = true
|
||||
handleStdinInput(conf)
|
||||
elif conf.projectName != "":
|
||||
try:
|
||||
conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName)
|
||||
|
||||
@@ -359,6 +359,14 @@ proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, in
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
options.inclDynlibOverride(conf, arg)
|
||||
|
||||
proc handleStdinInput*(conf: ConfigRef) =
|
||||
conf.projectName = "stdinfile"
|
||||
conf.projectFull = conf.projectName.AbsoluteFile
|
||||
conf.projectPath = AbsoluteDir getCurrentDir()
|
||||
conf.projectIsStdin = true
|
||||
if conf.outDir.isEmpty:
|
||||
conf.outDir = getNimcacheDir(conf)
|
||||
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf: ConfigRef) =
|
||||
var
|
||||
@@ -380,6 +388,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "nonimblepath", "nobabelpath":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
disableNimblePath(conf)
|
||||
of "clearnimblepath":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
clearNimblePath(conf)
|
||||
of "excludepath":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let path = processPath(conf, arg, info)
|
||||
@@ -387,15 +398,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf.lazyPaths.keepItIf(it != path)
|
||||
of "nimcache":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.nimcacheDir = processPath(conf, arg, info, true)
|
||||
conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
of "out", "o":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let f = splitFile(arg.expandTilde)
|
||||
let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string)
|
||||
conf.outFile = RelativeFile f.name & f.ext
|
||||
conf.outDir = toAbsoluteDir f.dir
|
||||
of "outdir":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.outDir = toAbsoluteDir arg.expandTilde
|
||||
conf.outDir = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
of "docseesrcurl":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.docSeeSrcUrl = arg
|
||||
@@ -614,22 +625,20 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optGenMapping}, arg, pass, info)
|
||||
of "os":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
let theOS = platform.nameToOS(arg)
|
||||
if theOS == osNone:
|
||||
let osList = platform.listOSnames().join(", ")
|
||||
localError(conf, info, "unknown OS: '$1'. Available options are: $2" % [arg, $osList])
|
||||
elif theOS != conf.target.hostOS:
|
||||
setTarget(conf.target, theOS, conf.target.targetCPU)
|
||||
let theOS = platform.nameToOS(arg)
|
||||
if theOS == osNone:
|
||||
let osList = platform.listOSnames().join(", ")
|
||||
localError(conf, info, "unknown OS: '$1'. Available options are: $2" % [arg, $osList])
|
||||
else:
|
||||
setTarget(conf.target, theOS, conf.target.targetCPU)
|
||||
of "cpu":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
let cpu = platform.nameToCPU(arg)
|
||||
if cpu == cpuNone:
|
||||
let cpuList = platform.listCPUnames().join(", ")
|
||||
localError(conf, info, "unknown CPU: '$1'. Available options are: $2" % [ arg, cpuList])
|
||||
elif cpu != conf.target.hostCPU:
|
||||
setTarget(conf.target, conf.target.targetOS, cpu)
|
||||
let cpu = platform.nameToCPU(arg)
|
||||
if cpu == cpuNone:
|
||||
let cpuList = platform.listCPUnames().join(", ")
|
||||
localError(conf, info, "unknown CPU: '$1'. Available options are: $2" % [ arg, cpuList])
|
||||
else:
|
||||
setTarget(conf.target, conf.target.targetOS, cpu)
|
||||
of "run", "r":
|
||||
processOnOffSwitchG(conf, {optRun}, arg, pass, info)
|
||||
of "errormax":
|
||||
@@ -758,7 +767,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if pass in {passCmd2, passPP}:
|
||||
doAssert(conf != nil)
|
||||
incl(conf.features, destructor)
|
||||
incl(conf.globalOptions, optNimV2)
|
||||
incl(conf.globalOptions, optTinyRtti)
|
||||
incl(conf.globalOptions, optOwnedRefs)
|
||||
incl(conf.globalOptions, optSeqDestructors)
|
||||
defineSymbol(conf.symbols, "nimV2")
|
||||
conf.selectedGC = gcDestructors
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
@@ -792,8 +803,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
discard "the default"
|
||||
else:
|
||||
localError(conf, info, "unknown Nim version; currently supported values are: {1.0}")
|
||||
of "":
|
||||
conf.projectName = "-"
|
||||
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
|
||||
handleStdinInput(conf)
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#
|
||||
#
|
||||
# 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. :-/
|
||||
@@ -26,6 +26,7 @@ type
|
||||
TSections = array[TSymKind, Rope]
|
||||
TDocumentor = object of rstgen.RstGenerator
|
||||
modDesc: Rope # module description
|
||||
module: PSym
|
||||
modDeprecationMsg: Rope
|
||||
toc, section: TSections
|
||||
indexValFilename: string
|
||||
@@ -115,9 +116,10 @@ proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
|
||||
else:
|
||||
result = getOutFile(conf, filename, ext)
|
||||
|
||||
proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, outExt: string = HtmlExt): PDoc =
|
||||
proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, outExt: string = HtmlExt, module: PSym = nil): PDoc =
|
||||
declareClosures()
|
||||
new(result)
|
||||
result.module = module
|
||||
result.conf = conf
|
||||
result.cache = cache
|
||||
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
|
||||
@@ -592,7 +594,7 @@ proc docstringSummary(rstText: string): string =
|
||||
##
|
||||
## Most docstrings will contain a one liner summary, so stripping at the
|
||||
## first newline is usually fine. If after that the content is still too big,
|
||||
## it is stripped at the first comma, colon or dot, usual english sentence
|
||||
## it is stripped at the first comma, colon or dot, usual English sentence
|
||||
## separators.
|
||||
##
|
||||
## No guarantees are made on the size of the output, but it should be small.
|
||||
@@ -631,8 +633,12 @@ proc genDeprecationMsg(d: PDoc, n: PNode): Rope =
|
||||
else:
|
||||
doAssert false
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(d, nameNode): return
|
||||
type DocFlags = enum
|
||||
kDefault
|
||||
kForceExport
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
if (docFlags != kForceExport) and not isVisible(d, nameNode): return
|
||||
let
|
||||
name = getName(d, nameNode)
|
||||
nameRope = name.rope
|
||||
@@ -848,7 +854,9 @@ proc documentRaises*(cache: IdentCache; n: PNode) =
|
||||
if p4 != nil: n.sons[pragmasPos].add p4
|
||||
if p5 != nil: n.sons[pragmasPos].add p5
|
||||
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode) =
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
|
||||
template genItemAux(skind) =
|
||||
genItem(d, n, n[namePos], skind, docFlags)
|
||||
case n.kind
|
||||
of nkPragma:
|
||||
let pragmaNode = findPragma(n, wDeprecated)
|
||||
@@ -856,27 +864,27 @@ proc generateDoc*(d: PDoc, n, orig: PNode) =
|
||||
of nkCommentStmt: add(d.modDesc, genComment(d, n))
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skProc)
|
||||
genItemAux(skProc)
|
||||
of nkFuncDef:
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skFunc)
|
||||
genItemAux(skFunc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skMethod)
|
||||
genItemAux(skMethod)
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
||||
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
|
||||
genItemAux(skIterator)
|
||||
of nkMacroDef: genItemAux(skMacro)
|
||||
of nkTemplateDef: genItemAux(skTemplate)
|
||||
of nkConverterDef:
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skConverter)
|
||||
genItemAux(skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
genItem(d, n[i], n[i][0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags)
|
||||
of nkStmtList:
|
||||
for i in 0 ..< len(n): generateDoc(d, n.sons[i], orig)
|
||||
of nkWhenStmt:
|
||||
@@ -887,7 +895,11 @@ proc generateDoc*(d: PDoc, n, orig: PNode) =
|
||||
for it in n: traceDeps(d, it)
|
||||
of nkExportStmt:
|
||||
for it in n:
|
||||
if it.kind == nkSym: exportSym(d, it.sym)
|
||||
if it.kind == nkSym:
|
||||
if d.module != nil and d.module == it.sym.owner:
|
||||
generateDoc(d, it.sym.ast, orig, kForceExport)
|
||||
else:
|
||||
exportSym(d, it.sym)
|
||||
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
of nkCallKinds:
|
||||
@@ -1169,6 +1181,9 @@ proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
|
||||
["Index".rope, nil, nil, rope(getDateStr()),
|
||||
rope(getClockStr()), content, nil, nil, nil])
|
||||
# no analytics because context is not available
|
||||
let filename = getOutFile(conf, RelativeFile"theindex", HtmlExt)
|
||||
var outFile = RelativeFile"theindex"
|
||||
if conf.outFile != RelativeFile"":
|
||||
outFile = conf.outFile
|
||||
let filename = getOutFile(conf, outFile, HtmlExt)
|
||||
if not writeRope(code, filename):
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
@@ -62,7 +62,7 @@ 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)
|
||||
graph.cache, graph.config, ext, module)
|
||||
d.hasToc = true
|
||||
g.doc = d
|
||||
result = g
|
||||
|
||||
@@ -63,9 +63,9 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
globalError(conf, sym.info, "dynlib needs to be a string lit")
|
||||
var theAddr: pointer
|
||||
if (lib.isNil or lib.kind == libHeader) and not gExehandle.isNil:
|
||||
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
|
||||
# first try this exe itself:
|
||||
theAddr = gExehandle.symAddr(name)
|
||||
theAddr = gExeHandle.symAddr(name)
|
||||
# then try libc:
|
||||
if theAddr.isNil:
|
||||
let dllhandle = getDll(conf, gDllCache, libcDll, sym.info)
|
||||
|
||||
@@ -138,12 +138,12 @@ compiler vcc:
|
||||
optSize: " /O1 /G7 ",
|
||||
compilerExe: "cl",
|
||||
cppCompiler: "cl",
|
||||
compileTmpl: "/c$vccplatform$options $include /Fo$objfile $file",
|
||||
compileTmpl: "/c$vccplatform $options $include /Fo$objfile $file",
|
||||
buildGui: " /link /SUBSYSTEM:WINDOWS ",
|
||||
buildDll: " /LD",
|
||||
buildLib: "lib /OUT:$libfile $objfiles",
|
||||
linkerExe: "cl",
|
||||
linkTmpl: "$options $builddll$vccplatform /Fe$exefile $objfiles $buildgui",
|
||||
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui $options",
|
||||
includeCmd: " /I",
|
||||
linkDirCmd: " /LIBPATH:",
|
||||
linkLibCmd: " $1.lib",
|
||||
@@ -996,15 +996,16 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
pastStart = true
|
||||
lit "\L"
|
||||
|
||||
proc nimfiles(conf: ConfigRef; f: File) =
|
||||
proc depfiles(conf: ConfigRef; f: File) =
|
||||
var i = 0
|
||||
for it in conf.m.fileInfos:
|
||||
if isAbsolute(it.fullPath.string):
|
||||
let path = it.fullPath.string
|
||||
if isAbsolute(path): # TODO: else?
|
||||
if i > 0: lit "],\L"
|
||||
lit "["
|
||||
str it.fullPath.string
|
||||
str path
|
||||
lit ", "
|
||||
str $secureHashFile(it.fullPath.string)
|
||||
str $secureHashFile(path)
|
||||
inc i
|
||||
lit "]\L"
|
||||
|
||||
@@ -1028,8 +1029,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
|
||||
lit ",\L\"cmdline\": "
|
||||
str conf.commandLine
|
||||
lit ",\L\"nimfiles\":[\L"
|
||||
nimfiles(conf, f)
|
||||
lit ",\L\"depfiles\":[\L"
|
||||
depfiles(conf, f)
|
||||
lit "],\L\"nimexe\": \L"
|
||||
str hashNimExe()
|
||||
lit "\L"
|
||||
@@ -1044,22 +1045,22 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol
|
||||
result = false
|
||||
try:
|
||||
let data = json.parseFile(jsonFile.string)
|
||||
if not data.hasKey("nimfiles") or not data.hasKey("cmdline"):
|
||||
if not data.hasKey("depfiles") or not data.hasKey("cmdline"):
|
||||
return true
|
||||
let oldCmdLine = data["cmdline"].getStr
|
||||
if conf.commandLine != oldCmdLine:
|
||||
return true
|
||||
if hashNimExe() != data["nimexe"].getStr:
|
||||
return true
|
||||
let nimfilesPairs = data["nimfiles"]
|
||||
doAssert nimfilesPairs.kind == JArray
|
||||
for p in nimfilesPairs:
|
||||
let depfilesPairs = data["depfiles"]
|
||||
doAssert depfilesPairs.kind == JArray
|
||||
for p in depfilesPairs:
|
||||
doAssert p.kind == JArray
|
||||
# >= 2 for forwards compatibility with potential later .json files:
|
||||
doAssert p.len >= 2
|
||||
let nimFilename = p[0].getStr
|
||||
let depFilename = p[0].getStr
|
||||
let oldHashValue = p[1].getStr
|
||||
let newHashValue = $secureHashFile(nimFilename)
|
||||
let newHashValue = $secureHashFile(depFilename)
|
||||
if oldHashValue != newHashValue:
|
||||
return true
|
||||
except IOError, OSError, ValueError:
|
||||
|
||||
@@ -40,6 +40,7 @@ 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:
|
||||
@@ -54,5 +55,6 @@ 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:
|
||||
result = ("", -1)
|
||||
|
||||
@@ -436,7 +436,7 @@ proc sameTree*(a, b: PNode): bool =
|
||||
if not result and a.sym.magic != mNone:
|
||||
result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym)
|
||||
of nkIdent: result = a.ident.id == b.ident.id
|
||||
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
|
||||
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkType: result = a.typ == b.typ
|
||||
|
||||
@@ -153,7 +153,11 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
|
||||
err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
|
||||
toFullPath(c.config, c.graph.importStack[i+1])
|
||||
c.recursiveDep = err
|
||||
|
||||
discard pushOptionEntry(c)
|
||||
result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f))
|
||||
popOptionEntry(c)
|
||||
|
||||
#echo "set back to ", L
|
||||
c.graph.importStack.setLen(L)
|
||||
# we cannot perform this check reliably because of
|
||||
|
||||
@@ -11,136 +11,14 @@
|
||||
## an optimizer that optimizes copies to moves. This is implemented as an
|
||||
## AST to AST transformation so that every backend benefits from it.
|
||||
|
||||
## Rules for destructor injections:
|
||||
##
|
||||
## foo(bar(X(), Y()))
|
||||
## X and Y get destroyed after bar completes:
|
||||
##
|
||||
## foo( (tmpX = X(); tmpY = Y(); tmpBar = bar(tmpX, tmpY);
|
||||
## destroy(tmpX); destroy(tmpY);
|
||||
## tmpBar))
|
||||
## destroy(tmpBar)
|
||||
##
|
||||
## var x = f()
|
||||
## body
|
||||
##
|
||||
## is the same as:
|
||||
##
|
||||
## var x;
|
||||
## try:
|
||||
## move(x, f())
|
||||
## finally:
|
||||
## destroy(x)
|
||||
##
|
||||
## But this really just an optimization that tries to avoid to
|
||||
## introduce too many temporaries, the 'destroy' is caused by
|
||||
## the 'f()' call. No! That is not true for 'result = f()'!
|
||||
##
|
||||
## x = y where y is read only once
|
||||
## is the same as: move(x, y)
|
||||
##
|
||||
## Actually the more general rule is: The *last* read of ``y``
|
||||
## can become a move if ``y`` is the result of a construction.
|
||||
##
|
||||
## We also need to keep in mind here that the number of reads is
|
||||
## control flow dependent:
|
||||
## let x = foo()
|
||||
## while true:
|
||||
## y = x # only one read, but the 2nd iteration will fail!
|
||||
## This also affects recursions! Only usages that do not cross
|
||||
## a loop boundary (scope) and are not used in function calls
|
||||
## are safe.
|
||||
##
|
||||
##
|
||||
## x = f() is the same as: move(x, f())
|
||||
##
|
||||
## x = y
|
||||
## is the same as: copy(x, y)
|
||||
##
|
||||
## Reassignment works under this scheme:
|
||||
## var x = f()
|
||||
## x = y
|
||||
##
|
||||
## is the same as:
|
||||
##
|
||||
## var x;
|
||||
## try:
|
||||
## move(x, f())
|
||||
## copy(x, y)
|
||||
## finally:
|
||||
## destroy(x)
|
||||
##
|
||||
## result = f() must not destroy 'result'!
|
||||
##
|
||||
## The produced temporaries clutter up the code and might lead to
|
||||
## inefficiencies. A better strategy is to collect all the temporaries
|
||||
## in a single object that we put into a single try-finally that
|
||||
## surrounds the proc body. This means the code stays quite efficient
|
||||
## when compiled to C. In fact, we do the same for variables, so
|
||||
## destructors are called when the proc returns, not at scope exit!
|
||||
## This makes certains idioms easier to support. (Taking the slice
|
||||
## of a temporary object.)
|
||||
##
|
||||
## foo(bar(X(), Y()))
|
||||
## X and Y get destroyed after bar completes:
|
||||
##
|
||||
## var tmp: object
|
||||
## foo( (move tmp.x, X(); move tmp.y, Y(); tmp.bar = bar(tmpX, tmpY);
|
||||
## tmp.bar))
|
||||
## destroy(tmp.bar)
|
||||
## destroy(tmp.x); destroy(tmp.y)
|
||||
##
|
||||
## See doc/destructors.rst for a spec of the implemented rewrite rules
|
||||
|
||||
#[
|
||||
From https://github.com/nim-lang/Nim/wiki/Destructors
|
||||
|
||||
Rule Pattern Transformed into
|
||||
---- ------- ----------------
|
||||
1.1 var x: T; stmts var x: T; try stmts
|
||||
finally: `=destroy`(x)
|
||||
2 x = f() `=sink`(x, f())
|
||||
3 x = lastReadOf z `=sink`(x, z); wasMoved(z)
|
||||
3.2 x = path z; body ``x = bitwiseCopy(path z);``
|
||||
do not emit `=destroy(x)`. Note: body
|
||||
must not mutate ``z`` nor ``x``. All
|
||||
assignments to ``x`` must be of the form
|
||||
``path z`` but the ``z`` can differ.
|
||||
Neither ``z`` nor ``x`` can have the
|
||||
flag ``sfAddrTaken`` to ensure no other
|
||||
aliasing is going on.
|
||||
4.1 y = sinkParam `=sink`(y, sinkParam)
|
||||
4.2 x = y `=`(x, y) # a copy
|
||||
5.1 f_sink(g()) f_sink(g())
|
||||
5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read
|
||||
5.3 f_sink(move y) f_sink(y); wasMoved(y) # explicit moves empties 'y'
|
||||
5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp)
|
||||
|
||||
Rule 3.2 describes a "cursor" variable, a variable that is only used as a
|
||||
view into some data structure. See ``compiler/cursors.nim`` for details.
|
||||
|
||||
Note: In order to avoid the very common combination ``reset(x); =sink(x, y)`` for
|
||||
variable definitions we must turn "the first sink/assignment" operation into a
|
||||
copyMem. This is harder than it looks:
|
||||
|
||||
while true:
|
||||
try:
|
||||
if cond: break # problem if we run destroy(x) here :-/
|
||||
var x = f()
|
||||
finally:
|
||||
destroy(x)
|
||||
|
||||
And the C++ optimizers don't sweat to optimize it for us, so we don't have
|
||||
to do it.
|
||||
]#
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||
lineinfos, parampatterns, sighashes
|
||||
|
||||
const
|
||||
InterestingSyms = {skVar, skResult, skLet, skForVar, skTemp}
|
||||
|
||||
type
|
||||
Con = object
|
||||
owner: PSym
|
||||
@@ -217,43 +95,6 @@ proc isLastRead(n: PNode; c: var Con): bool =
|
||||
dbg:
|
||||
echo "ugh ", c.otherRead.isNil, " ", result
|
||||
|
||||
when false:
|
||||
let s = n.sym
|
||||
var pcs: seq[int] = @[instr+1]
|
||||
var takenGotos: IntSet
|
||||
var takenForks = initIntSet()
|
||||
while pcs.len > 0:
|
||||
var pc = pcs.pop
|
||||
|
||||
takenGotos = initIntSet()
|
||||
while pc < c.g.len:
|
||||
case c.g[pc].kind
|
||||
of def:
|
||||
if c.g[pc].sym == s:
|
||||
# the path lead to a redefinition of 's' --> abandon it.
|
||||
break
|
||||
inc pc
|
||||
of use:
|
||||
if c.g[pc].sym == s:
|
||||
c.otherRead = c.g[pc].n
|
||||
return false
|
||||
inc pc
|
||||
of goto:
|
||||
# we must leave endless loops eventually:
|
||||
if not takenGotos.containsOrIncl(pc):
|
||||
pc = pc + c.g[pc].dest
|
||||
else:
|
||||
inc pc
|
||||
of fork:
|
||||
# we follow the next instruction but push the dest onto our "work" stack:
|
||||
if not takenForks.containsOrIncl(pc):
|
||||
pcs.add pc + c.g[pc].dest
|
||||
inc pc
|
||||
of InstrKind.join:
|
||||
inc pc
|
||||
#echo c.graph.config $ n.info, " last read here!"
|
||||
return true
|
||||
|
||||
proc initialized(code: ControlFlowGraph; pc: int,
|
||||
init, uninit: var IntSet; comesFrom: int): int =
|
||||
## Computes the set of definitely initialized variables across all code paths
|
||||
@@ -290,9 +131,6 @@ proc initialized(code: ControlFlowGraph; pc: int,
|
||||
inc pc
|
||||
return pc
|
||||
|
||||
template interestingSym(s: PSym): bool =
|
||||
s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
|
||||
|
||||
template isUnpackedTuple(s: PSym): bool =
|
||||
## we move out all elements of unpacked tuples,
|
||||
## hence unpacked tuples themselves don't need to be destroyed
|
||||
@@ -353,8 +191,8 @@ proc canBeMoved(t: PType): bool {.inline.} =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = t.kind != tyRef and t.attachedOps[attachedSink] != nil
|
||||
|
||||
proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
proc genSink(c: Con; dest, ri: PNode): PNode =
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let k = if t.attachedOps[attachedSink] != nil: attachedSink
|
||||
else: attachedAsgn
|
||||
if t.attachedOps[k] != nil:
|
||||
@@ -365,20 +203,20 @@ proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
# we generate a fast assignment in this case:
|
||||
result = newTree(nkFastAsgn, dest)
|
||||
|
||||
proc genCopy(c: var Con; t: PType; dest, ri: PNode): PNode =
|
||||
proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode =
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
|
||||
proc genCopy(c: var Con; dest, ri: PNode): PNode =
|
||||
let t = dest.typ
|
||||
if tfHasOwned in t.flags:
|
||||
# try to improve the error message here:
|
||||
if c.otherRead == nil: discard isLastRead(ri, c)
|
||||
checkForErrorPragma(c, t, ri, "=")
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
genCopyNoCheck(c, dest, ri)
|
||||
|
||||
proc genCopyNoCheck(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
|
||||
proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
proc genDestroy(c: Con; dest: PNode): PNode =
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = genOp(c, t, attachedDestructor, dest, nil)
|
||||
|
||||
proc addTopVar(c: var Con; v: PNode) =
|
||||
@@ -390,20 +228,10 @@ proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
|
||||
result = newSymNode(sym)
|
||||
c.addTopVar(result)
|
||||
|
||||
proc p(n: PNode; c: var Con): PNode
|
||||
|
||||
template recurse(n, dest) =
|
||||
for i in 0..<n.len:
|
||||
dest.add p(n[i], c)
|
||||
|
||||
proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, magicname, m)))
|
||||
result.add n
|
||||
|
||||
proc genWasMoved(n: PNode; c: var Con): PNode =
|
||||
# The mWasMoved builtin does not take the address.
|
||||
result = genMagicCall(n, c, "wasMoved", mWasMoved)
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved)))
|
||||
result.add n #mWasMoved does not take the address
|
||||
|
||||
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
@@ -422,9 +250,9 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
||||
let tempAsNode = newSymNode(temp)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart.sons[0] = tempAsNode
|
||||
vpart.sons[1] = c.emptyNode
|
||||
vpart.sons[2] = n
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = c.emptyNode
|
||||
vpart[2] = n
|
||||
add(v, vpart)
|
||||
|
||||
result.add v
|
||||
@@ -437,6 +265,10 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
||||
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
||||
|
||||
proc p(n: PNode; c: var Con): PNode
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = getTemp(c, n.typ, n.info)
|
||||
@@ -444,7 +276,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
# out of loops we need to mark it as 'wasMoved'.
|
||||
result.add genWasMoved(tmp, c)
|
||||
if hasDestructor(n.typ):
|
||||
var m = genCopy(c, n.typ, tmp, n)
|
||||
var m = genCopy(c, tmp, n)
|
||||
m.add p(n, c)
|
||||
result.add m
|
||||
if isLValue(n):
|
||||
@@ -457,7 +289,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
|
||||
proc isDangerousSeq(t: PType): bool {.inline.} =
|
||||
let t = t.skipTypes(abstractInst)
|
||||
result = t.kind == tySequence and tfHasOwned notin t.sons[0].flags
|
||||
result = t.kind == tySequence and tfHasOwned notin t[0].flags
|
||||
|
||||
proc containsConstSeq(n: PNode): bool =
|
||||
if n.kind == nkBracket and n.len > 0 and n.typ != nil and isDangerousSeq(n.typ):
|
||||
@@ -467,19 +299,66 @@ proc containsConstSeq(n: PNode): bool =
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = containsConstSeq(n[1])
|
||||
of nkObjConstr, nkClosure:
|
||||
for i in 1 ..< n.len:
|
||||
for i in 1..<n.len:
|
||||
if containsConstSeq(n[i]): return true
|
||||
of nkCurly, nkBracket, nkPar, nkTupleConstr:
|
||||
for i in 0 ..< n.len:
|
||||
if containsConstSeq(n[i]): return true
|
||||
for son in n:
|
||||
if containsConstSeq(son): return true
|
||||
else: discard
|
||||
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
template pArgIfTyped(argPart: PNode): PNode =
|
||||
# typ is nil if we are in if/case expr branch with noreturn
|
||||
if argPart.typ == nil: p(argPart, c)
|
||||
else: pArg(argPart, c, isSink)
|
||||
template handleNested(n: untyped, processCall: untyped) =
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
if n.len == 0: return n
|
||||
result = copyNode(n)
|
||||
for i in 0..<n.len-1:
|
||||
result.add p(n[i], c)
|
||||
template node: untyped = n[^1]
|
||||
result.add processCall
|
||||
of nkBlockStmt, nkBlockExpr:
|
||||
result = copyNode(n)
|
||||
result.add n[0]
|
||||
template node: untyped = n[1]
|
||||
result.add processCall
|
||||
of nkIfStmt, nkIfExpr:
|
||||
result = copyNode(n)
|
||||
for son in n:
|
||||
var branch = copyNode(son)
|
||||
if son.kind in {nkElifBranch, nkElifExpr}:
|
||||
template node: untyped = son[1]
|
||||
branch.add p(son[0], c) #The condition
|
||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
else:
|
||||
template node: untyped = son[0]
|
||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
result.add branch
|
||||
of nkCaseStmt:
|
||||
result = copyNode(n)
|
||||
result.add p(n[0], c)
|
||||
for i in 1..<n.len:
|
||||
var branch: PNode
|
||||
if n[i].kind == nkOfBranch:
|
||||
branch = n[i] # of branch conditions are constants
|
||||
template node: untyped = n[i][^1]
|
||||
branch[^1] = if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
elif n[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
branch = copyNode(n[i])
|
||||
branch.add p(n[i][0], c) #The condition
|
||||
template node: untyped = n[i][1]
|
||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
else:
|
||||
branch = copyNode(n[i])
|
||||
template node: untyped = n[i][0]
|
||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
result.add branch
|
||||
else: assert(false)
|
||||
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
if isSink:
|
||||
if arg.kind in nkCallKinds:
|
||||
# recurse but skip the call expression in order to prevent
|
||||
@@ -495,8 +374,8 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
# sink parameter (bug #11524). Note that the string implementation is
|
||||
# different and can deal with 'const string sunk into var'.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkCharLit..nkTripleStrLit}:
|
||||
discard "object construction to sink parameter: nothing to do"
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr} + nkLiterals:
|
||||
# object construction to sink parameter: nothing to do
|
||||
result = arg
|
||||
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
@@ -507,202 +386,216 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
# it is the last read, can be sinked. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
result = destructiveMoveVar(arg, c)
|
||||
elif arg.kind in {nkBlockExpr, nkBlockStmt}:
|
||||
result = copyNode(arg)
|
||||
result.add arg[0]
|
||||
result.add pArg(arg[1], c, isSink)
|
||||
elif arg.kind == nkStmtListExpr:
|
||||
result = copyNode(arg)
|
||||
for i in 0..arg.len-2:
|
||||
result.add p(arg[i], c)
|
||||
result.add pArg(arg[^1], c, isSink)
|
||||
elif arg.kind in {nkIfExpr, nkIfStmt}:
|
||||
result = copyNode(arg)
|
||||
for i in 0..<arg.len:
|
||||
var branch = copyNode(arg[i])
|
||||
if arg[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
branch.add p(arg[i][0], c)
|
||||
branch.add pArgIfTyped(arg[i][1])
|
||||
else:
|
||||
branch.add pArgIfTyped(arg[i][0])
|
||||
result.add branch
|
||||
elif arg.kind == nkCaseStmt:
|
||||
result = copyNode(arg)
|
||||
result.add p(arg[0], c)
|
||||
for i in 1..<arg.len:
|
||||
var branch: PNode
|
||||
if arg[i].kind == nkOfBranch:
|
||||
branch = arg[i] # of branch conditions are constants
|
||||
branch[^1] = pArgIfTyped(arg[i][^1])
|
||||
elif arg[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
branch = copyNode(arg[i])
|
||||
branch.add p(arg[i][0], c)
|
||||
branch.add pArgIfTyped(arg[i][1])
|
||||
else:
|
||||
branch = copyNode(arg[i])
|
||||
branch.add pArgIfTyped(arg[i][0])
|
||||
result.add branch
|
||||
elif arg.kind in {nkStmtListExpr, nkBlockExpr, nkBlockStmt, nkIfExpr, nkIfStmt, nkCaseStmt}:
|
||||
handleNested(arg): pArg(node, c, isSink)
|
||||
else:
|
||||
# an object that is not temporary but passed to a 'sink' parameter
|
||||
# results in a copy.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind == nkBracket:
|
||||
# Treat `f([...])` like `f(...)`
|
||||
result = copyNode(arg)
|
||||
for son in arg:
|
||||
result.add pArg(son, c, isSinkTypeForParam(son.typ))
|
||||
elif arg.kind in nkCallKinds and arg.typ != nil and hasDestructor(arg.typ):
|
||||
# produce temp creation
|
||||
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
|
||||
let tmp = getTemp(c, arg.typ, arg.info)
|
||||
let res = p(arg, c)
|
||||
var sinkExpr = genSink(c, tmp, res)
|
||||
sinkExpr.add res
|
||||
result.add sinkExpr
|
||||
result.add tmp
|
||||
c.destroys.add genDestroy(c, tmp)
|
||||
else:
|
||||
result = p(arg, c)
|
||||
|
||||
proc p(n: PNode; c: var Con): PNode =
|
||||
case n.kind
|
||||
of nkCallKinds:
|
||||
let parameters = n[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
for i in 1..<n.len:
|
||||
n[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
result = n
|
||||
of nkDiscardStmt: #Small optimization
|
||||
if n[0].kind != nkEmpty:
|
||||
n[0] = pArg(n[0], c, false)
|
||||
result = n
|
||||
of nkBracket:
|
||||
result = copyTree(n)
|
||||
for i in 0..<n.len:
|
||||
# everything that is passed to an array constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
result[i] = pArg(n[i], c, isSink = true)
|
||||
of nkObjConstr:
|
||||
result = copyTree(n)
|
||||
for i in 1..<n.len:
|
||||
# everything that is passed to an object constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
result[i][1] = pArg(n[i][1], c, isSink = true)
|
||||
of nkTupleConstr, nkClosure:
|
||||
result = copyTree(n)
|
||||
for i in ord(n.kind == nkClosure)..<n.len:
|
||||
# everything that is passed to an tuple constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
if n[i].kind == nkExprColonExpr:
|
||||
result[i][1] = pArg(n[i][1], c, isSink = true)
|
||||
else:
|
||||
result[i] = pArg(n[i], c, isSink = true)
|
||||
of nkVarSection, nkLetSection:
|
||||
# transform; var x = y to var x; x op y where op is a move or copy
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for it in n:
|
||||
var ri = it[^1]
|
||||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c)
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
|
||||
for j in 0..<it.len-2:
|
||||
let v = it[j]
|
||||
if v.kind == nkSym:
|
||||
if sfCompileTime in v.sym.flags: continue
|
||||
# move the variable declaration to the top of the frame:
|
||||
c.addTopVar v
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v)
|
||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||
ri = genDefaultCall(v.typ, c, v.info)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
else: # keep the var but transform 'ri':
|
||||
var v = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..<it.len-1:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[^1], c)
|
||||
v.add itCopy
|
||||
result.add v
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}:
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add n[0]
|
||||
result.add p(n[1], c)
|
||||
of nkRaiseStmt:
|
||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
if n[0].kind in nkCallKinds:
|
||||
let call = p(n[0], c)
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let tmp = getTemp(c, n[0].typ, n.info)
|
||||
var m = genCopyNoCheck(c, tmp, n[0])
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add p(n[0], c)
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
||||
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef,
|
||||
nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, nkExportStmt,
|
||||
nkPragma, nkCommentStmt, nkBreakStmt:
|
||||
result = n
|
||||
of nkWhileStmt:
|
||||
result = copyNode(n)
|
||||
inc c.inLoop
|
||||
result.add p(n[0], c)
|
||||
result.add p(n[1], c)
|
||||
dec c.inLoop
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = p(result[1][0], c)
|
||||
of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt:
|
||||
handleNested(n): p(node, c)
|
||||
else:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = p(n[i], c)
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
# unfortunately, this needs to be kept consistent with the cases
|
||||
# we handle in the 'case of' statement below:
|
||||
const movableNodeKinds = (nkCallKinds + {nkSym, nkTupleConstr, nkObjConstr,
|
||||
nkBracket, nkBracketExpr, nkNilLit})
|
||||
|
||||
template moveOrCopyIfTyped(riPart: PNode): PNode =
|
||||
# typ is nil if we are in if/case expr branch with noreturn
|
||||
if riPart.typ == nil: p(riPart, c)
|
||||
else: moveOrCopy(dest, riPart, c)
|
||||
|
||||
case ri.kind
|
||||
of nkCallKinds:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
# watch out and no not transform 'ri' twice if it's a call:
|
||||
let ri2 = copyNode(ri)
|
||||
let parameters = ri[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
ri2.add ri[0]
|
||||
for i in 1..<ri.len:
|
||||
ri2.add pArg(ri[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
#recurse(ri, ri2)
|
||||
result.add ri2
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkBracketExpr:
|
||||
if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
|
||||
# unpacking of tuple: move out the elements
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
var snk = genSink(c, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkStmtListExpr:
|
||||
result = newNodeI(nkStmtList, ri.info)
|
||||
for i in 0..ri.len-2:
|
||||
result.add p(ri[i], c)
|
||||
result.add moveOrCopy(dest, ri[^1], c)
|
||||
of nkBlockExpr, nkBlockStmt:
|
||||
result = newNodeI(nkBlockStmt, ri.info)
|
||||
result.add ri[0] ## add label
|
||||
result.add moveOrCopy(dest, ri[1], c)
|
||||
of nkIfExpr, nkIfStmt:
|
||||
result = newNodeI(nkIfStmt, ri.info)
|
||||
for i in 0..<ri.len:
|
||||
var branch = copyNode(ri[i])
|
||||
if ri[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
branch.add p(ri[i][0], c)
|
||||
branch.add moveOrCopyIfTyped(ri[i][1])
|
||||
else:
|
||||
branch.add moveOrCopyIfTyped(ri[i][0])
|
||||
result.add branch
|
||||
of nkCaseStmt:
|
||||
result = newNodeI(nkCaseStmt, ri.info)
|
||||
result.add p(ri[0], c)
|
||||
for i in 1..<ri.len:
|
||||
var branch: PNode
|
||||
if ri[i].kind == nkOfBranch:
|
||||
branch = ri[i] # of branch conditions are constants
|
||||
branch[^1] = moveOrCopyIfTyped(ri[i][^1])
|
||||
elif ri[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
branch = copyNode(ri[i])
|
||||
branch.add p(ri[i][0], c)
|
||||
branch.add moveOrCopyIfTyped(ri[i][1])
|
||||
else:
|
||||
branch = copyNode(ri[i])
|
||||
branch.add moveOrCopyIfTyped(ri[i][0])
|
||||
result.add branch
|
||||
of nkBracket:
|
||||
# array constructor
|
||||
if ri.len > 0 and isDangerousSeq(ri.typ):
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result = genCopy(c, dest, ri)
|
||||
else:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in 0..<ri.len:
|
||||
# everything that is passed to an array constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
ri2[i] = pArg(ri[i], c, isSink = true)
|
||||
result.add ri2
|
||||
of nkObjConstr:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in 1..<ri.len:
|
||||
# everything that is passed to an object constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
|
||||
result.add ri2
|
||||
of nkTupleConstr, nkClosure:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in ord(ri.kind == nkClosure)..<ri.len:
|
||||
# everything that is passed to an tuple constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
if ri[i].kind == nkExprColonExpr:
|
||||
ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
|
||||
else:
|
||||
ri2[i] = pArg(ri[i], c, isSink = true)
|
||||
result.add ri2
|
||||
of nkNilLit:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
result.add ri
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkSym:
|
||||
if isSinkParam(ri.sym):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
sinkParamIsLastReadCheck(c, ri)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
var snk = genSink(c, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||
isLastRead(ri, c) and canBeMoved(dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
var snk = genSink(c, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkHiddenSubConv, nkHiddenStdConv:
|
||||
if sameType(ri.typ, ri[1].typ):
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
elif ri[1].kind in movableNodeKinds:
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
var b = newNodeIT(ri.kind, ri.info, ri.typ)
|
||||
b.add ri[0] # add empty node
|
||||
let L = result.len-1
|
||||
b.add result[L]
|
||||
result[L] = b
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
if not sameType(ri.typ, ri[1].typ):
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[1] = result[^1]
|
||||
result[^1] = copyRi
|
||||
of nkObjDownConv, nkObjUpConv:
|
||||
if ri[0].kind in movableNodeKinds:
|
||||
result = moveOrCopy(dest, ri[0], c)
|
||||
var b = newNodeIT(ri.kind, ri.info, ri.typ)
|
||||
let L = result.len-1
|
||||
b.add result[L]
|
||||
result[L] = b
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
result = moveOrCopy(dest, ri[0], c)
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[0] = result[^1]
|
||||
result[^1] = copyRi
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
|
||||
handleNested(ri): moveOrCopy(dest, node, c)
|
||||
else:
|
||||
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and
|
||||
canBeMoved(dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
var snk = genSink(c, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
# XXX At least string literals can be moved?
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c)
|
||||
|
||||
proc computeUninit(c: var Con) =
|
||||
@@ -715,17 +608,14 @@ proc computeUninit(c: var Con) =
|
||||
proc injectDefaultCalls(n: PNode, c: var Con) =
|
||||
case n.kind
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
let L = it.len-1
|
||||
let ri = it[L]
|
||||
if it.kind == nkIdentDefs and ri.kind == nkEmpty:
|
||||
for it in n:
|
||||
if it.kind == nkIdentDefs and it[^1].kind == nkEmpty:
|
||||
computeUninit(c)
|
||||
for j in 0..L-2:
|
||||
for j in 0..<it.len-2:
|
||||
let v = it[j]
|
||||
doAssert v.kind == nkSym
|
||||
if c.uninit.contains(v.sym.id):
|
||||
it[L] = genDefaultCall(v.sym.typ, c, v.info)
|
||||
it[^1] = genDefaultCall(v.sym.typ, c, v.info)
|
||||
break
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
||||
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
|
||||
@@ -734,130 +624,16 @@ proc injectDefaultCalls(n: PNode, c: var Con) =
|
||||
for i in 0..<safeLen(n):
|
||||
injectDefaultCalls(n[i], c)
|
||||
|
||||
proc isCursor(n: PNode): bool {.inline.} =
|
||||
result = n.kind == nkSym and sfCursor in n.sym.flags
|
||||
|
||||
proc keepVar(n, it: PNode, c: var Con): PNode =
|
||||
# keep the var but transform 'ri':
|
||||
result = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..it.len-2:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[it.len-1], c)
|
||||
result.add itCopy
|
||||
|
||||
proc p(n: PNode; c: var Con): PNode =
|
||||
case n.kind
|
||||
of nkVarSection, nkLetSection:
|
||||
discard "transform; var x = y to var x; x op y where op is a move or copy"
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
let L = it.len
|
||||
var ri = it[L-1]
|
||||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c)
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0]):
|
||||
for j in 0..L-3:
|
||||
let v = it[j]
|
||||
if v.kind == nkSym:
|
||||
if sfCompileTime in v.sym.flags: continue
|
||||
# move the variable declaration to the top of the frame:
|
||||
c.addTopVar v
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v.typ, v)
|
||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||
ri = genDefaultCall(v.typ, c, v.info)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
else:
|
||||
result.add keepVar(n, it, c)
|
||||
of nkCallKinds:
|
||||
let parameters = n[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
for i in 1 ..< n.len:
|
||||
n.sons[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
if n.typ != nil and hasDestructor(n.typ):
|
||||
discard "produce temp creation"
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = getTemp(c, n.typ, n.info)
|
||||
var sinkExpr = genSink(c, n.typ, tmp, n)
|
||||
sinkExpr.add n
|
||||
result.add sinkExpr
|
||||
result.add tmp
|
||||
c.destroys.add genDestroy(c, n.typ, tmp)
|
||||
else:
|
||||
result = n
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}:
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
||||
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
|
||||
result = n
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = copyNode(n)
|
||||
# Destination type
|
||||
result.add n[0]
|
||||
# Analyse the inner expression
|
||||
result.add p(n[1], c)
|
||||
of nkWhen:
|
||||
# This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = p(result[1][0], c)
|
||||
of nkRaiseStmt:
|
||||
if optNimV2 in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
if n[0].kind in nkCallKinds:
|
||||
let call = copyNode(n[0])
|
||||
recurse(n[0], call)
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let t = n[0].typ
|
||||
let tmp = getTemp(c, t, n.info)
|
||||
var m = genCopyNoCheck(c, t, tmp, n[0])
|
||||
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
of nkForStmt, nkParForStmt, nkWhileStmt:
|
||||
inc c.inLoop
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
dec c.inLoop
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
|
||||
proc extractDestroysForTemporaries(c: Con, destroys: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, destroys.info)
|
||||
for i in 0 ..< destroys.len:
|
||||
for i in 0..<destroys.len:
|
||||
if destroys[i][1][0].sym.kind == skTemp:
|
||||
result.add destroys[i]
|
||||
destroys[i] = c.emptyNode
|
||||
|
||||
proc reverseDestroys(destroys: PNode) =
|
||||
var reversed: seq[PNode]
|
||||
proc reverseDestroys(destroys: seq[PNode]): seq[PNode] =
|
||||
for i in countdown(destroys.len - 1, 0):
|
||||
reversed.add(destroys[i])
|
||||
destroys.sons = reversed
|
||||
result.add destroys[i]
|
||||
|
||||
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||
if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n
|
||||
@@ -874,14 +650,15 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||
if c.g[i].kind in {goto, fork}:
|
||||
c.jumpTargets.incl(i+c.g[i].dest)
|
||||
dbg:
|
||||
echo "injecting into ", n
|
||||
echo "\n### ", owner.name.s, ":\nCFG:"
|
||||
echoCfg(c.g)
|
||||
echo n
|
||||
if owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}:
|
||||
let params = owner.typ.n
|
||||
for i in 1 ..< params.len:
|
||||
let param = params[i].sym
|
||||
if isSinkTypeForParam(param.typ) and hasDestructor(param.typ.skipTypes({tySink})):
|
||||
c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
|
||||
for i in 1..<params.len:
|
||||
let t = params[i].sym.typ
|
||||
if isSinkTypeForParam(t) and hasDestructor(t.skipTypes({tySink})):
|
||||
c.destroys.add genDestroy(c, params[i])
|
||||
|
||||
#if optNimV2 in c.graph.config.globalOptions:
|
||||
# injectDefaultCalls(n, c)
|
||||
@@ -890,7 +667,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||
if c.topLevelVars.len > 0:
|
||||
result.add c.topLevelVars
|
||||
if c.destroys.len > 0:
|
||||
reverseDestroys(c.destroys)
|
||||
c.destroys.sons = reverseDestroys(c.destroys.sons)
|
||||
if owner.kind == skModule:
|
||||
result.add newTryFinally(body, extractDestroysForTemporaries(c, c.destroys))
|
||||
g.globalDestructors.add c.destroys
|
||||
@@ -898,8 +675,6 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||
result.add newTryFinally(body, c.destroys)
|
||||
else:
|
||||
result.add body
|
||||
|
||||
dbg:
|
||||
echo "------------------------------------"
|
||||
echo owner.name.s, " transformed to: "
|
||||
echo ">---------transformed-to--------->"
|
||||
echo result
|
||||
|
||||
@@ -6,12 +6,12 @@ Name: "Nim"
|
||||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
|
||||
macosx: i386;amd64;powerpc64
|
||||
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64
|
||||
macosx: i386;amd64;powerpc64;arm64
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64;powerpc64
|
||||
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64
|
||||
openbsd: i386;amd64;arm;arm64
|
||||
dragonfly: i386;amd64
|
||||
haiku: i386;amd64
|
||||
android: i386;arm;arm64
|
||||
@@ -65,6 +65,7 @@ Files: "compiler"
|
||||
Files: "doc"
|
||||
Files: "doc/html"
|
||||
Files: "tools"
|
||||
Files: "tools/nim-gdb.py"
|
||||
Files: "nimpretty"
|
||||
Files: "testament"
|
||||
Files: "nimsuggest"
|
||||
@@ -88,6 +89,7 @@ Files: "bin/vccexe.exe"
|
||||
Files: "bin/nimgrab.exe"
|
||||
Files: "bin/nimpretty.exe"
|
||||
Files: "bin/testament.exe"
|
||||
Files: "bin/nim-gdb.bat"
|
||||
|
||||
Files: "koch.exe"
|
||||
Files: "finish.exe"
|
||||
@@ -116,6 +118,8 @@ Files: "bin/nim"
|
||||
[Unix]
|
||||
InstallScript: "yes"
|
||||
UninstallScript: "yes"
|
||||
Files: "bin/nim-gdb"
|
||||
Files: "bin/nim-gdb.bash"
|
||||
|
||||
|
||||
[InnoSetup]
|
||||
|
||||
@@ -335,7 +335,6 @@ proc `*`(a: Int128, b: uint32): Int128 =
|
||||
result.udata[3] = cast[uint32](tmp3) + cast[uint32](tmp2 shr 32)
|
||||
|
||||
proc `*`*(a: Int128, b: int32): Int128 =
|
||||
let isNegative = isNegative(a) xor isNegative(b)
|
||||
result = a * cast[uint32](abs(b))
|
||||
if b < 0:
|
||||
result = -result
|
||||
@@ -356,8 +355,6 @@ proc low64(a: Int128): uint64 =
|
||||
bitconcat(a.udata[1], a.udata[0])
|
||||
|
||||
proc `*`*(lhs,rhs: Int128): Int128 =
|
||||
let isNegative = isNegative(lhs) xor isNegative(rhs)
|
||||
|
||||
let
|
||||
a = cast[uint64](lhs.udata[0])
|
||||
b = cast[uint64](lhs.udata[1])
|
||||
@@ -379,9 +376,6 @@ proc `*`*(lhs,rhs: Int128): Int128 =
|
||||
result = result + toInt128(a32 * b00) shl 32
|
||||
result = result + toInt128(a00 * b32) shl 32
|
||||
|
||||
if isNegative != isNegative(result):
|
||||
assert(false, "overflow")
|
||||
|
||||
proc `*=`*(a: var Int128, b: Int128) =
|
||||
a = a * b
|
||||
|
||||
@@ -407,11 +401,17 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
|
||||
|
||||
if divisor > dividend:
|
||||
result.quotient = Zero
|
||||
result.remainder = dividend
|
||||
if isNegativeA:
|
||||
result.remainder = -dividend
|
||||
else:
|
||||
result.remainder = dividend
|
||||
return
|
||||
|
||||
if divisor == dividend:
|
||||
result.quotient = One
|
||||
if isNegativeA xor isNegativeB:
|
||||
result.quotient = NegOne
|
||||
else:
|
||||
result.quotient = One
|
||||
result.remainder = Zero
|
||||
return
|
||||
|
||||
@@ -543,8 +543,6 @@ template bitor(a,b,c: Int128): Int128 = bitor(bitor(a,b), c)
|
||||
|
||||
proc toInt128*(arg: float64): Int128 =
|
||||
let isNegative = arg < 0
|
||||
assert(arg < 0x47E0000000000000'f64, "out of range")
|
||||
assert(arg >= 0xC7E0000000000000'f64, "out of range")
|
||||
let v0 = ldexp(abs(arg), -100)
|
||||
let w0 = uint64(trunc(v0))
|
||||
let v1 = ldexp(v0 - float64(w0), 50)
|
||||
@@ -680,8 +678,21 @@ when isMainModule:
|
||||
var ma = 100'i64
|
||||
var mb = 13
|
||||
|
||||
doAssert toInt128(ma) * toInt128(0) == toInt128(0)
|
||||
doAssert toInt128(-ma) * toInt128(0) == toInt128(0)
|
||||
|
||||
# sign correctness
|
||||
doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb))
|
||||
doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb))
|
||||
doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb))
|
||||
doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb))
|
||||
|
||||
doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb))
|
||||
doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb))
|
||||
doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb))
|
||||
doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb))
|
||||
|
||||
doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma))
|
||||
doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma))
|
||||
doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma))
|
||||
doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma))
|
||||
|
||||
@@ -1169,7 +1169,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
first = firstOrd(p.config, typ.sons[0])
|
||||
if optBoundsCheck in p.options:
|
||||
useMagic(p, "chckIndx")
|
||||
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), tmp]
|
||||
r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp]
|
||||
elif first != 0:
|
||||
r.res = "($1)-$2" % [b.res, rope(first)]
|
||||
else:
|
||||
@@ -1632,7 +1632,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
of tyObject:
|
||||
var initList: Rope
|
||||
createObjInitList(p, t, initIntSet(), initList)
|
||||
result = ("{$1}") % [initList]
|
||||
result = ("({$1})") % [initList]
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyVar, tyPtr, tyLent, tyRef, tyPointer:
|
||||
if mapType(p, t) == etyBaseIndex:
|
||||
@@ -1894,6 +1894,15 @@ proc genReset(p: PProc, n: PNode) =
|
||||
lineF(p, "$1 = genericReset($3, $2);$n", [a,
|
||||
genTypeInfo(p, n.sons[1].typ), tmp])
|
||||
|
||||
proc genMove(p: PProc; n: PNode; r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.kind = resVal
|
||||
r.res = p.getTemp()
|
||||
gen(p, n[1], a)
|
||||
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
|
||||
genReset(p, n)
|
||||
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||
|
||||
proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
a: TCompRes
|
||||
@@ -2018,7 +2027,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
|
||||
of mOf: genOf(p, n, r)
|
||||
of mDefault: genDefault(p, n, r)
|
||||
of mReset: genReset(p, n)
|
||||
of mReset, mWasMoved: genReset(p, n)
|
||||
of mEcho: genEcho(p, n, r)
|
||||
of mNLen..mNError, mSlurp, mStaticExec:
|
||||
localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
|
||||
@@ -2041,6 +2050,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[3], z)
|
||||
r.res = "($1.slice($2, $3+1))" % [x.rdLoc, y.rdLoc, z.rdLoc]
|
||||
r.kind = resExpr
|
||||
of mMove:
|
||||
genMove(p, n, r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
|
||||
@@ -2155,7 +2166,10 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
|
||||
var a, b: TCompRes
|
||||
gen(p, n.sons[0], r)
|
||||
if optRangeCheck in p.options:
|
||||
if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "XXX maybe emit masking instructions here"
|
||||
else:
|
||||
gen(p, n.sons[1], a)
|
||||
gen(p, n.sons[2], b)
|
||||
useMagic(p, "chckRange")
|
||||
|
||||
@@ -233,6 +233,10 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
|
||||
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
||||
result = conf.cmd == cmdCompileToJS and not isCompileTime
|
||||
|
||||
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo) =
|
||||
createTypeBoundOps(g, nil, refType.lastSon, info)
|
||||
createTypeBoundOps(g, nil, refType, info)
|
||||
|
||||
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
if liftingHarmful(g.config, owner): return n
|
||||
@@ -245,7 +249,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(g, owner)
|
||||
addUniqueField(it.typ.sons[0], hp, g.cache)
|
||||
addUniqueField(it.typ.skipTypes({tyOwned}).sons[0], hp, g.cache)
|
||||
env = indirectAccess(newSymNode(it), hp, hp.info)
|
||||
else:
|
||||
let e = newSym(skLet, iter.name, owner, n.info)
|
||||
@@ -257,13 +261,13 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
|
||||
if optNimV2 in g.config.globalOptions:
|
||||
if optOwnedRefs in g.config.globalOptions:
|
||||
createTypeBoundOps(g, nil, env.typ, n.info)
|
||||
result.add makeClosure(g, iter, env, n.info)
|
||||
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.skipTypes({tyOwned, tyRef})
|
||||
let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
addField(obj, s, g.cache)
|
||||
|
||||
var access = newSymNode(envParam)
|
||||
@@ -323,7 +327,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
||||
c.ownerToType[owner.id] = result
|
||||
|
||||
proc asOwnedRef(c: DetectionPass; t: PType): PType =
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
if optOwnedRefs in c.graph.config.globalOptions:
|
||||
assert t.kind == tyRef
|
||||
result = newType(tyOwned, t.owner)
|
||||
result.flags.incl tfHasOwned
|
||||
@@ -335,16 +339,17 @@ proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
|
||||
info: TLineInfo): PType =
|
||||
var r = c.getEnvTypeForOwner(owner, info)
|
||||
result = newType(tyPtr, owner)
|
||||
rawAddSon(result, r.skipTypes({tyOwned, tyRef}))
|
||||
rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr}))
|
||||
|
||||
proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
let refObj = c.getEnvTypeForOwner(dest, info) # getHiddenParam(dest).typ
|
||||
let obj = refObj.skipTypes({tyOwned, tyRef})
|
||||
let obj = refObj.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
# The assumption here is that gcDestructors means we cannot deal
|
||||
# with cycles properly, so it's better to produce a weak ref (=ptr) here.
|
||||
# This seems to be generally correct but since it's a bit risky it's only
|
||||
# enabled for gcDestructors.
|
||||
let fieldType = if false: # c.graph.config.selectedGC == gcDestructors:
|
||||
# This seems to be generally correct but since it's a bit risky it's disabled
|
||||
# for now.
|
||||
let fieldType = if isDefined(c.graph.config, "nimCycleBreaker") or
|
||||
c.graph.config.selectedGC == gcDestructors:
|
||||
c.getEnvTypeForOwnerUp(dep, info) #getHiddenParam(dep).typ
|
||||
else:
|
||||
c.getEnvTypeForOwner(dep, info)
|
||||
@@ -354,7 +359,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
let upIdent = getIdent(c.graph.cache, upName)
|
||||
let upField = lookupInRecord(obj.n, upIdent)
|
||||
if upField != nil:
|
||||
if upField.typ.skipTypes({tyOwned, tyRef}) != fieldType.skipTypes({tyOwned, tyRef}):
|
||||
if upField.typ.skipTypes({tyOwned, tyRef, tyPtr}) != fieldType.skipTypes({tyOwned, tyRef, tyPtr}):
|
||||
localError(c.graph.config, dep.info, "internal error: up references do not agree")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
|
||||
@@ -425,8 +430,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef})
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef})
|
||||
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
|
||||
if s.name.id == getIdent(c.graph.cache, ":state").id:
|
||||
obj.n[0].sym.id = -s.id
|
||||
@@ -451,8 +456,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef})
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
addField(obj, s, c.graph.cache)
|
||||
# create required upFields:
|
||||
var w = owner.skipGenericOwner
|
||||
@@ -542,7 +547,7 @@ proc setupEnvVar(owner: PSym; d: DetectionPass;
|
||||
localError d.graph.config, owner.info, "internal error: could not determine closure type"
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info)
|
||||
c.envVars[owner.id] = result
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = envVarType
|
||||
@@ -552,7 +557,7 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
let p = getHiddenParam(g, owner)
|
||||
result = p.newSymNode
|
||||
if owner.isIterator:
|
||||
let upField = lookupInRecord(p.typ.skipTypes({tyOwned, tyRef}).n, getIdent(g.cache, upName))
|
||||
let upField = lookupInRecord(p.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(g.cache, upName))
|
||||
if upField == nil:
|
||||
localError(g.config, owner.info, "could not find up reference for closure iter")
|
||||
else:
|
||||
@@ -572,20 +577,20 @@ proc rawClosureCreation(owner: PSym;
|
||||
var v = newNodeI(nkVarSection, env.info)
|
||||
addVar(v, env)
|
||||
result.add(v)
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
addVar(v, unowned)
|
||||
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
let env2 = copyTree(env)
|
||||
env2.typ = unowned.typ
|
||||
result.add newAsgnStmt(unowned, env2, env.info)
|
||||
createTypeBoundOps(d.graph, nil, unowned.typ, env.info)
|
||||
createTypeBoundOpsLL(d.graph, unowned.typ, env.info)
|
||||
|
||||
# add assignment statements for captured parameters:
|
||||
for i in 1..<owner.typ.n.len:
|
||||
@@ -595,10 +600,10 @@ proc rawClosureCreation(owner: PSym;
|
||||
# add ``env.param = param``
|
||||
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
|
||||
|
||||
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName))
|
||||
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
let up = getUpViaParam(d.graph, owner)
|
||||
if up != nil and upField.typ.skipTypes({tyOwned, tyRef}) == up.typ.skipTypes({tyOwned, tyRef}):
|
||||
if up != nil and upField.typ.skipTypes({tyOwned, tyRef, tyPtr}) == up.typ.skipTypes({tyOwned, tyRef, tyPtr}):
|
||||
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
up, env.info))
|
||||
#elif oldenv != nil and oldenv.typ == upField.typ:
|
||||
@@ -608,12 +613,12 @@ proc rawClosureCreation(owner: PSym;
|
||||
localError(d.graph.config, env.info, "internal error: cannot create up reference")
|
||||
# we are not in the sem'check phase anymore! so pass 'nil' for the PContext
|
||||
# and hope for the best:
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
createTypeBoundOps(d.graph, nil, env.typ, owner.info)
|
||||
|
||||
proc finishClosureCreation(owner: PSym; d: DetectionPass; c: LiftingPass;
|
||||
info: TLineInfo; res: PNode) =
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
let nilLit = newNodeIT(nkNilLit, info, unowned.typ)
|
||||
@@ -629,7 +634,7 @@ proc closureCreationForIter(iter: PNode;
|
||||
var vnode: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(d.graph, owner)
|
||||
addUniqueField(it.typ.skipTypes({tyOwned, tyRef}), v, d.graph.cache)
|
||||
addUniqueField(it.typ.skipTypes({tyOwned, tyRef, tyPtr}), v, d.graph.cache)
|
||||
vnode = indirectAccess(newSymNode(it), v, v.info)
|
||||
else:
|
||||
vnode = v.newSymNode
|
||||
@@ -637,13 +642,13 @@ proc closureCreationForIter(iter: PNode;
|
||||
addVar(vs, vnode)
|
||||
result.add(vs)
|
||||
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
createTypeBoundOps(d.graph, nil, vnode.typ, iter.info)
|
||||
|
||||
let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName))
|
||||
let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
let u = setupEnvVar(owner, d, c, iter.info)
|
||||
if u.typ.skipTypes({tyOwned, tyRef}) == upField.typ.skipTypes({tyOwned, tyRef}):
|
||||
if u.typ.skipTypes({tyOwned, tyRef, tyPtr}) == upField.typ.skipTypes({tyOwned, tyRef, tyPtr}):
|
||||
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
|
||||
u, iter.info))
|
||||
else:
|
||||
@@ -653,9 +658,9 @@ proc closureCreationForIter(iter: PNode;
|
||||
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
var access = setupEnvVar(owner, d, c, n.info)
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
access = c.unownedEnvVars[owner.id]
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef})
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
let field = getFieldFromObj(obj, n.sym)
|
||||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, n.info)
|
||||
@@ -664,7 +669,7 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
result = n
|
||||
|
||||
proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
|
||||
getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef}).n.sons[0].sym
|
||||
getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n.sons[0].sym
|
||||
|
||||
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode
|
||||
@@ -689,7 +694,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
while true:
|
||||
if access.typ == wanted:
|
||||
return makeClosure(d.graph, s, access, n.info)
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef})
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
let upField = lookupInRecord(obj.n, getIdent(d.graph.cache, upName))
|
||||
if upField == nil:
|
||||
localError(d.graph.config, n.info, "internal error: no environment found")
|
||||
@@ -923,7 +928,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
|
||||
if optNimV2 in g.config.globalOptions:
|
||||
if optOwnedRefs in g.config.globalOptions:
|
||||
createTypeBoundOps(g, nil, env.typ, body.info)
|
||||
|
||||
elif op.kind == nkStmtListExpr:
|
||||
|
||||
@@ -404,14 +404,14 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind == attachedDeepCopy:
|
||||
# a big problem is that we don't know the enviroment's type here, so we
|
||||
# a big problem is that we don't know the environment's type here, so we
|
||||
# have to go through some indirection; we delegate this to the codegen:
|
||||
let call = newNodeI(nkCall, c.info, 2)
|
||||
call.typ = t
|
||||
call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy))
|
||||
call.sons[1] = y
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif optNimV2 in c.g.config.globalOptions and
|
||||
elif optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options:
|
||||
let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
@@ -457,7 +457,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyPtr, tyOpt, tyUncheckedArray:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyRef:
|
||||
if optNimV2 in c.g.config.globalOptions and
|
||||
if optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options:
|
||||
weakrefOp(c, t, body, x, y)
|
||||
else:
|
||||
@@ -469,7 +469,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyOwned:
|
||||
let base = t.skipTypes(abstractInstOwned)
|
||||
if optNimV2 in c.g.config.globalOptions:
|
||||
if optOwnedRefs in c.g.config.globalOptions:
|
||||
case base.kind
|
||||
of tyRef:
|
||||
ownedRefOp(c, base, body, x, y)
|
||||
|
||||
@@ -13,7 +13,7 @@ when not defined(nimcore):
|
||||
{.error: "nimcore MUST be defined for Nim's core tooling".}
|
||||
|
||||
import
|
||||
llstream, strutils, ast, lexer, syntaxes, options, msgs,
|
||||
llstream, strutils, os, ast, lexer, syntaxes, options, msgs,
|
||||
condsyms, times,
|
||||
sem, idents, passes, extccomp,
|
||||
cgen, json, nversion,
|
||||
@@ -303,6 +303,8 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
|
||||
var dumpdata = %[
|
||||
(key: "version", val: %VersionAsString),
|
||||
(key: "nimExe", val: %(getAppFilename())),
|
||||
(key: "prefixdir", val: %conf.getPrefixDir().string),
|
||||
(key: "project_path", val: %conf.projectFull.string),
|
||||
(key: "defined_symbols", val: definedSymbols),
|
||||
(key: "lib_paths", val: %libpaths),
|
||||
|
||||
@@ -81,6 +81,7 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
|
||||
pseudoPath = true
|
||||
|
||||
if conf.m.filenameToIndexTbl.hasKey(canon.string):
|
||||
isKnownFile = true
|
||||
result = conf.m.filenameToIndexTbl[canon.string]
|
||||
else:
|
||||
isKnownFile = false
|
||||
@@ -379,7 +380,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
|
||||
if context.info != lastinfo and context.info != info:
|
||||
if conf.structuredErrorHook != nil:
|
||||
conf.structuredErrorHook(conf, context.info, instantiationFrom,
|
||||
Severity.Error)
|
||||
Severity.Hint)
|
||||
else:
|
||||
let message = if context.detail == "":
|
||||
instantiationFrom
|
||||
|
||||
@@ -40,19 +40,31 @@ proc prependCurDir(f: AbsoluteFile): AbsoluteFile =
|
||||
else:
|
||||
result = f
|
||||
|
||||
proc addCmdPrefix*(result: var string, kind: CmdLineKind) =
|
||||
# consider moving this to std/parseopt
|
||||
case kind
|
||||
of cmdLongOption: result.add "--"
|
||||
of cmdShortOption: result.add "-"
|
||||
of cmdArgument, cmdEnd: discard
|
||||
|
||||
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
|
||||
config.commandLine.setLen 0
|
||||
# bugfix: otherwise, config.commandLine ends up duplicated
|
||||
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongOption, cmdShortOption:
|
||||
config.commandLine.add " "
|
||||
config.commandLine.add p.key
|
||||
config.commandLine.addCmdPrefix p.kind
|
||||
config.commandLine.add p.key.quoteShell # quoteShell to be future proof
|
||||
if p.val.len > 0:
|
||||
config.commandLine.add ':'
|
||||
config.commandLine.add p.val
|
||||
config.commandLine.add p.val.quoteShell
|
||||
|
||||
if p.key == " ":
|
||||
p.key = "-"
|
||||
@@ -61,7 +73,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
processSwitch(pass, p, config)
|
||||
of cmdArgument:
|
||||
config.commandLine.add " "
|
||||
config.commandLine.add p.key
|
||||
config.commandLine.add p.key.quoteShell
|
||||
if processArgument(pass, p, argsCount, config): break
|
||||
if pass == passCmd2:
|
||||
if {optRun, optWasNimscript} * config.globalOptions == {} and
|
||||
|
||||
@@ -69,9 +69,10 @@ proc getPathVersion*(p: string): tuple[name, version: string] =
|
||||
result.version = ""
|
||||
|
||||
const specialSeparator = "-#"
|
||||
var sepIdx = p.find(specialSeparator)
|
||||
let last = p.rfind(p.lastPathPart) # the index where the last path part begins
|
||||
var sepIdx = p.find(specialSeparator, start = last)
|
||||
if sepIdx == -1:
|
||||
sepIdx = p.rfind('-')
|
||||
sepIdx = p.rfind('-', start = last)
|
||||
|
||||
if sepIdx == -1:
|
||||
result.name = p
|
||||
|
||||
@@ -160,8 +160,9 @@ proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
config: ConfigRef; condStack: var seq[bool]) =
|
||||
if tok.ident.s == "-" or tok.ident.s == "--":
|
||||
confTok(L, tok, config, condStack) # skip unnecessary prefix
|
||||
if tok.ident != nil:
|
||||
if tok.ident.s == "-" or tok.ident.s == "--":
|
||||
confTok(L, tok, config, condStack) # skip unnecessary prefix
|
||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||
checkSymbol(L, tok)
|
||||
var s = $tok
|
||||
@@ -190,6 +191,12 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
checkSymbol(L, tok)
|
||||
add(val, $tok)
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
if tok.tokType in {tkColon, tkEquals}:
|
||||
add(val, $tok) # add the :
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
checkSymbol(L, tok)
|
||||
add(val, $tok) # add the token after it
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
while tok.ident != nil and tok.ident.s == "&":
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
@@ -201,7 +208,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
else:
|
||||
processSwitch(s, val, passPP, info, config)
|
||||
|
||||
proc readConfigFile(filename: AbsoluteFile; cache: IdentCache;
|
||||
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
config: ConfigRef): bool =
|
||||
var
|
||||
L: TLexer
|
||||
|
||||
@@ -81,7 +81,11 @@ type # please make sure we have under 32 options
|
||||
optNoNimblePath
|
||||
optHotCodeReloading
|
||||
optDynlibOverrideAll
|
||||
optNimV2
|
||||
optSeqDestructors # active if the implementation uses the new
|
||||
# string/seq implementation based on destructors
|
||||
optTinyRtti # active if we use the new "tiny RTTI"
|
||||
# implementation
|
||||
optOwnedRefs # active if the Nim compiler knows about 'owned'.
|
||||
optMultiMethods
|
||||
optNimV019
|
||||
|
||||
@@ -140,6 +144,10 @@ type
|
||||
## Allows to modify a NimNode where the type has already been
|
||||
## flagged with nfSem. If you actually do this, it will cause
|
||||
## bugs.
|
||||
checkUnsignedConversions
|
||||
## Historically and especially in version 1.0.0 of the language
|
||||
## conversions to unsigned numbers were checked. In 1.0.4 they
|
||||
## are not anymore.
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
@@ -409,7 +417,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
of "mswindows", "win32": result = conf.target.targetOS == osWindows
|
||||
of "macintosh":
|
||||
result = conf.target.targetOS in {osMacos, osMacosx, osIos}
|
||||
of "osx":
|
||||
of "osx", "macosx":
|
||||
result = conf.target.targetOS in {osMacosx, osIos}
|
||||
of "sunos": result = conf.target.targetOS == osSolaris
|
||||
of "nintendoswitch":
|
||||
@@ -540,6 +548,9 @@ proc disableNimblePath*(conf: ConfigRef) =
|
||||
incl conf.globalOptions, optNoNimblePath
|
||||
conf.lazyPaths.setLen(0)
|
||||
|
||||
proc clearNimblePath*(conf: ConfigRef) =
|
||||
conf.lazyPaths.setLen(0)
|
||||
|
||||
include packagehandling
|
||||
|
||||
proc getOsCacheDir(): string =
|
||||
@@ -568,9 +579,7 @@ proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||
"projectname", conf.projectName,
|
||||
"projectpath", conf.projectPath.string,
|
||||
"projectdir", conf.projectPath.string,
|
||||
"nimcache", getNimcacheDir(conf).string])
|
||||
if "~/" in result:
|
||||
result = result.replace("~/", home & '/')
|
||||
"nimcache", getNimcacheDir(conf).string]).expandTilde
|
||||
|
||||
proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile,
|
||||
ext: string): AbsoluteFile =
|
||||
|
||||
@@ -26,6 +26,9 @@ when isMainModule:
|
||||
outp.write matches[0], "\L"
|
||||
outp.close
|
||||
|
||||
import ".." / tools / grammar_nanny
|
||||
checkGrammarFile()
|
||||
|
||||
import
|
||||
llstream, lexer, idents, strutils, ast, msgs, options, lineinfos,
|
||||
pathutils
|
||||
@@ -750,11 +753,10 @@ proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode =
|
||||
|
||||
proc primarySuffix(p: var TParser, r: PNode,
|
||||
baseIndent: int, mode: TPrimaryMode): PNode =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
#| | doBlocks
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')'
|
||||
#| | '.' optInd symbol generalizedLit?
|
||||
#| | '[' optInd indexExprList optPar ']'
|
||||
#| | '{' optInd indexExprList optPar '}'
|
||||
#| | '[' optInd exprColonEqExprList optPar ']'
|
||||
#| | '{' optInd exprColonEqExprList optPar '}'
|
||||
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
|
||||
result = r
|
||||
|
||||
@@ -908,7 +910,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||
p.currInd = oldInd
|
||||
|
||||
proc parsePragma(p: var TParser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
#| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
||||
result = newNodeP(nkPragma, p)
|
||||
inc p.inPragma
|
||||
when defined(nimpretty):
|
||||
@@ -937,8 +939,8 @@ proc parsePragma(p: var TParser): PNode =
|
||||
dec p.em.keepIndents
|
||||
|
||||
proc identVis(p: var TParser; allowDot=false): PNode =
|
||||
#| identVis = symbol opr? # postfix position
|
||||
#| identVisDot = symbol '.' optInd symbol opr?
|
||||
#| identVis = symbol OPR? # postfix position
|
||||
#| identVisDot = symbol '.' optInd symbol OPR?
|
||||
var a = parseSymbol(p)
|
||||
if p.tok.tokType == tkOpr:
|
||||
when defined(nimpretty):
|
||||
@@ -973,7 +975,7 @@ type
|
||||
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||
#| declColonEquals = identWithPragma (comma identWithPragma)* comma?
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?
|
||||
#| identColonEquals = ident (comma ident)* comma?
|
||||
#| identColonEquals = IDENT (comma IDENT)* comma?
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?)
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
@@ -1006,7 +1008,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||
|
||||
proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||
#| inlTupleDecl = 'tuple'
|
||||
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
#| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
#| extTupleDecl = 'tuple'
|
||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
#| tupleClass = 'tuple'
|
||||
@@ -1104,7 +1106,7 @@ proc optPragmas(p: var TParser): PNode =
|
||||
result = p.emptyNode
|
||||
|
||||
proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
|
||||
#| doBlock = 'do' paramListArrow pragmas? colcom stmt
|
||||
#| doBlock = 'do' paramListArrow pragma? colcom stmt
|
||||
let params = parseParamList(p, retColon=false)
|
||||
let pragmas = optPragmas(p)
|
||||
colcom(p, result)
|
||||
@@ -1115,7 +1117,7 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
|
||||
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
|
||||
|
||||
proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
|
||||
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
#| procExpr = 'proc' paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
# either a proc type or a anonymous proc
|
||||
let info = parLineInfo(p)
|
||||
getTok(p)
|
||||
@@ -1214,11 +1216,11 @@ proc parseExpr(p: var TParser): PNode =
|
||||
#| expr = (blockExpr
|
||||
#| | ifExpr
|
||||
#| | whenExpr
|
||||
#| | caseExpr
|
||||
#| | forExpr
|
||||
#| | caseStmt
|
||||
#| | forExpr
|
||||
#| | tryExpr)
|
||||
#| / simpleExpr
|
||||
case p.tok.tokType:
|
||||
case p.tok.tokType
|
||||
of tkBlock:
|
||||
nimprettyDontTouch:
|
||||
result = parseBlock(p)
|
||||
@@ -1248,7 +1250,7 @@ proc parseTypeClass(p: var TParser): PNode
|
||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
#| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple'
|
||||
#| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
|
||||
#| primary = typeKeyw typeDescK
|
||||
#| primary = typeKeyw optInd typeDesc
|
||||
#| / prefixOperator* identOrLiteral primarySuffix*
|
||||
#| / 'bind' primary
|
||||
if isOperator(p.tok):
|
||||
@@ -1420,8 +1422,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||
#| exprStmt = simpleExpr
|
||||
#| (( '=' optInd expr colonBody? )
|
||||
#| / ( expr ^+ comma
|
||||
#| doBlocks
|
||||
#| / macroColon
|
||||
#| postExprBlocks
|
||||
#| ))?
|
||||
var a = simpleExpr(p)
|
||||
if p.tok.tokType == tkEquals:
|
||||
@@ -1468,6 +1469,9 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| importStmt = 'import' optInd expr
|
||||
#| ((comma expr)*
|
||||
#| / 'except' optInd (expr ^+ comma))
|
||||
#| exportStmt = 'export' optInd expr
|
||||
#| ((comma expr)*
|
||||
#| / 'except' optInd (expr ^+ comma))
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p) # skip `import` or `export`
|
||||
optInd(p, result)
|
||||
@@ -1506,7 +1510,7 @@ proc parseIncludeStmt(p: var TParser): PNode =
|
||||
#expectNl(p)
|
||||
|
||||
proc parseFromStmt(p: var TParser): PNode =
|
||||
#| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
|
||||
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
result = newNodeP(nkFromStmt, p)
|
||||
getTok(p) # skip `from`
|
||||
optInd(p, result)
|
||||
@@ -1791,7 +1795,7 @@ type
|
||||
|
||||
proc parseSection(p: var TParser, kind: TNodeKind,
|
||||
defparser: TDefParser): PNode =
|
||||
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
|
||||
#| section(RULE) = COMMENT? RULE / (IND{>} (RULE / COMMENT)^+IND{=} DED)
|
||||
result = newNodeP(kind, p)
|
||||
if kind != nkTypeSection: getTok(p)
|
||||
skipComment(p, result)
|
||||
@@ -1819,7 +1823,7 @@ proc parseSection(p: var TParser, kind: TNodeKind,
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
|
||||
proc parseEnum(p: var TParser): PNode =
|
||||
#| enum = 'enum' optInd (symbol optPragmas optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
#| enum = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
result = newNodeP(nkEnumTy, p)
|
||||
getTok(p)
|
||||
addSon(result, p.emptyNode)
|
||||
@@ -2105,7 +2109,7 @@ proc parseVarTuple(p: var TParser): PNode =
|
||||
eat(p, tkParRi)
|
||||
|
||||
proc parseVariable(p: var TParser): PNode =
|
||||
#| colonBody = colcom stmt doBlocks?
|
||||
#| colonBody = colcom stmt postExprBlocks?
|
||||
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||
if p.tok.tokType == tkParLe:
|
||||
result = parseVarTuple(p)
|
||||
@@ -2117,7 +2121,7 @@ proc parseVariable(p: var TParser): PNode =
|
||||
indAndComment(p, result)
|
||||
|
||||
proc parseConstant(p: var TParser): PNode =
|
||||
#| constant = (parseVarTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
|
||||
#| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
|
||||
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
||||
else:
|
||||
result = newNodeP(nkConstDef, p)
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
|
||||
|
||||
type
|
||||
TInfoOSProp* = enum
|
||||
@@ -177,15 +177,23 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix}),
|
||||
(name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {}),
|
||||
]
|
||||
|
||||
type
|
||||
TSystemCPU* = enum # Also add CPU for in initialization section and
|
||||
# alias conditionals to condsyms (end of module).
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
|
||||
cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, cpuSparc64,
|
||||
cpuMips64, cpuMips64el, cpuRiscV64, cpuWasm32
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
|
||||
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
|
||||
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
@@ -204,6 +212,7 @@ const
|
||||
(name: "powerpc64el", intSize: 64, endian: littleEndian, floatSize: 64,bit: 64),
|
||||
(name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "hppa", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
@@ -217,7 +226,9 @@ const
|
||||
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)]
|
||||
|
||||
type
|
||||
@@ -241,23 +252,23 @@ proc setTarget*(t: var Target; o: TSystemOS, c: TSystemCPU) =
|
||||
t.tnl = OS[o].newLine
|
||||
|
||||
proc nameToOS*(name: string): TSystemOS =
|
||||
for i in succ(osNone) .. high(TSystemOS):
|
||||
for i in succ(osNone)..high(TSystemOS):
|
||||
if cmpIgnoreStyle(name, OS[i].name) == 0:
|
||||
return i
|
||||
result = osNone
|
||||
|
||||
proc listOSnames*(): seq[string] =
|
||||
for i in succ(osNone) .. high(TSystemOS):
|
||||
for i in succ(osNone)..high(TSystemOS):
|
||||
result.add OS[i].name
|
||||
|
||||
proc nameToCPU*(name: string): TSystemCPU =
|
||||
for i in succ(cpuNone) .. high(TSystemCPU):
|
||||
for i in succ(cpuNone)..high(TSystemCPU):
|
||||
if cmpIgnoreStyle(name, CPU[i].name) == 0:
|
||||
return i
|
||||
result = cpuNone
|
||||
|
||||
proc listCPUnames*(): seq[string] =
|
||||
for i in succ(cpuNone) .. high(TSystemCPU):
|
||||
for i in succ(cpuNone)..high(TSystemCPU):
|
||||
result.add CPU[i].name
|
||||
|
||||
proc setTargetFromSystem*(t: var Target) =
|
||||
|
||||
@@ -52,21 +52,21 @@ const
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
|
||||
wInjectStmt, wExperimental, wThis, wUsed}
|
||||
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv,
|
||||
wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader,
|
||||
wThread, wAsmNoStackFrame,
|
||||
wRaises, wLocks, wTags, wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
|
||||
wRaises, wLocks, wTags, wGcSafe, wCodegenDecl, wNoInit}
|
||||
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||
wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
|
||||
fieldPragmas* = declPragmas + {
|
||||
wGuard, wBitsize} - {wExportNims, wNodecl} # why exclude these?
|
||||
wGuard, wBitsize, wAlign} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
|
||||
wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto}
|
||||
constPragmas* = declPragmas + {wHeader, wMagic,
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
|
||||
@@ -418,14 +418,7 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
|
||||
proc processPush(c: PContext, n: PNode, start: int) =
|
||||
if n.sons[start-1].kind in nkPragmaCallKinds:
|
||||
localError(c.config, n.info, "'push' cannot have arguments")
|
||||
var x = newOptionEntry(c.config)
|
||||
var y = c.optionStack[^1]
|
||||
x.options = c.config.options
|
||||
x.defaultCC = y.defaultCC
|
||||
x.dynlib = y.dynlib
|
||||
x.notes = c.config.notes
|
||||
x.features = c.features
|
||||
c.optionStack.add(x)
|
||||
var x = pushOptionEntry(c)
|
||||
for i in start ..< len(n):
|
||||
if not tryProcessOption(c, n.sons[i], c.config.options):
|
||||
# simply store it somewhere:
|
||||
@@ -444,10 +437,7 @@ proc processPop(c: PContext, n: PNode) =
|
||||
if c.optionStack.len <= 1:
|
||||
localError(c.config, n.info, "{.pop.} without a corresponding {.push.}")
|
||||
else:
|
||||
c.config.options = c.optionStack[^1].options
|
||||
c.config.notes = c.optionStack[^1].notes
|
||||
c.features = c.optionStack[^1].features
|
||||
c.optionStack.setLen(c.optionStack.len - 1)
|
||||
popOptionEntry(c)
|
||||
when defined(debugOptions):
|
||||
echo c.config $ n.info, " POP config is now ", c.config.options
|
||||
|
||||
@@ -1103,11 +1093,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
invalidPragma(c, it)
|
||||
else:
|
||||
sym.flags.incl sfGoto
|
||||
of wCursor:
|
||||
if sym == nil or sym.kind notin {skVar, skLet}:
|
||||
invalidPragma(c, it)
|
||||
else:
|
||||
sym.flags.incl sfCursor
|
||||
of wExportNims:
|
||||
if sym == nil: invalidPragma(c, it)
|
||||
else: magicsys.registerNimScriptSymbol(c.graph, sym)
|
||||
|
||||
@@ -217,7 +217,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
let oldGlobalOptions = conf.globalOptions
|
||||
let oldSelectedGC = conf.selectedGC
|
||||
undefSymbol(conf.symbols, "nimv2")
|
||||
conf.globalOptions.excl optNimV2
|
||||
conf.globalOptions.excl {optTinyRtti, optOwnedRefs, optSeqDestructors}
|
||||
conf.selectedGC = gcUnselected
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
@@ -229,8 +229,8 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
|
||||
# watch out, "newruntime" can be set within NimScript itself and then we need
|
||||
# to remember this:
|
||||
if optNimV2 in oldGlobalOptions:
|
||||
conf.globalOptions.incl optNimV2
|
||||
if optOwnedRefs in oldGlobalOptions:
|
||||
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
if conf.selectedGC == gcUnselected:
|
||||
conf.selectedGC = oldSelectedGC
|
||||
|
||||
@@ -196,7 +196,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
||||
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam: candidates.add("\n unknown named parameter: " & $nArg[0])
|
||||
of kUnknownNamedParam:
|
||||
if nArg == nil:
|
||||
candidates.add("\n unknown named parameter")
|
||||
else:
|
||||
candidates.add("\n unknown named parameter: " & $nArg[0])
|
||||
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
|
||||
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
|
||||
of kExtraArg: candidates.add("\n extra argument given")
|
||||
@@ -293,10 +297,10 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
|
||||
assert result.startsWith "sk"
|
||||
result = result[2..^1].toLowerAscii
|
||||
result &= "\n found '$1' of kind '$2'" % [getSymRepr(c.config, sym), sym.kind.toHumanStr]
|
||||
sym = nextOverloadIter(o, c, n)
|
||||
sym = nextOverloadIter(o, c, f)
|
||||
|
||||
let ident = considerQuotedIdent(c, f, n).s
|
||||
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
||||
if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}:
|
||||
let sym = n.sons[1].typ.sym
|
||||
var typeHint = ""
|
||||
if sym == nil:
|
||||
@@ -304,7 +308,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
|
||||
# in a concept, eg:
|
||||
# ExplainedConcept {.explain.} = concept x
|
||||
# x.foo is int
|
||||
# We coudl use: `(c.config $ n.sons[1].info)` to get more context.
|
||||
# We could use: `(c.config $ n.sons[1].info)` to get more context.
|
||||
discard
|
||||
else:
|
||||
typeHint = " for type " & getProcHeader(c.config, sym)
|
||||
|
||||
@@ -212,13 +212,28 @@ proc newOptionEntry*(conf: ConfigRef): POptionEntry =
|
||||
result.dynlib = nil
|
||||
result.notes = conf.notes
|
||||
|
||||
proc pushOptionEntry*(c: PContext): POptionEntry =
|
||||
new(result)
|
||||
var prev = c.optionStack[^1]
|
||||
result.options = c.config.options
|
||||
result.defaultCC = prev.defaultCC
|
||||
result.dynlib = prev.dynlib
|
||||
result.notes = c.config.notes
|
||||
result.features = c.features
|
||||
c.optionStack.add(result)
|
||||
|
||||
proc popOptionEntry*(c: PContext) =
|
||||
c.config.options = c.optionStack[^1].options
|
||||
c.config.notes = c.optionStack[^1].notes
|
||||
c.features = c.optionStack[^1].features
|
||||
c.optionStack.setLen(c.optionStack.len - 1)
|
||||
|
||||
proc newContext*(graph: ModuleGraph; module: PSym): PContext =
|
||||
new(result)
|
||||
result.enforceVoidContext = PType(kind: tyTyped)
|
||||
result.ambiguousSymbols = initIntSet()
|
||||
result.optionStack = @[]
|
||||
result.optionStack = @[newOptionEntry(graph.config)]
|
||||
result.libs = @[]
|
||||
result.optionStack.add(newOptionEntry(graph.config))
|
||||
result.module = module
|
||||
result.friendModules = @[module]
|
||||
result.converters = @[]
|
||||
|
||||
@@ -508,7 +508,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
addSon(a, m)
|
||||
changeType(m, tup.sons[i], check)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if check and n.kind != nkUInt64Lit:
|
||||
if check and n.kind != nkUInt64Lit and not sameType(n.typ, newType):
|
||||
let value = n.intVal
|
||||
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
|
||||
localError(c.config, n.info, "cannot convert " & $value &
|
||||
@@ -2034,6 +2034,10 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# watch out, hacks ahead:
|
||||
when defined(nimsuggest):
|
||||
# Remove the error hook so nimsuggest doesn't report errors there
|
||||
let tempHook = c.graph.config.structuredErrorHook
|
||||
c.graph.config.structuredErrorHook = nil
|
||||
let oldErrorCount = c.config.errorCounter
|
||||
let oldErrorMax = c.config.errorMax
|
||||
let oldCompilesId = c.compilesContextId
|
||||
@@ -2080,6 +2084,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
c.config.m.errorOutputs = oldErrorOutputs
|
||||
c.config.errorCounter = oldErrorCount
|
||||
c.config.errorMax = oldErrorMax
|
||||
when defined(nimsuggest):
|
||||
# Restore the error hook
|
||||
c.graph.config.structuredErrorHook = tempHook
|
||||
|
||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
@@ -2394,7 +2401,7 @@ proc checkPar(c: PContext; n: PNode): TParKind =
|
||||
for i in 0 ..< length:
|
||||
if result == paTupleFields:
|
||||
if (n.sons[i].kind != nkExprColonExpr) or
|
||||
n.sons[i].sons[0].kind notin {nkSym, nkIdent}:
|
||||
n.sons[i].sons[0].kind notin {nkSym, nkIdent, nkAccQuoted}:
|
||||
localError(c.config, n.sons[i].info, errNamedExprExpected)
|
||||
return paNone
|
||||
else:
|
||||
@@ -2563,7 +2570,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# if isGenericRoutine(result.sym):
|
||||
# localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
|
||||
# "procs literals" are 'owned'
|
||||
if optNimV2 in c.config.globalOptions:
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
else:
|
||||
result = semSym(c, n, s, flags)
|
||||
|
||||
@@ -23,7 +23,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
result = newNode(nkEmpty)
|
||||
return
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
|
||||
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = copyNode(n)
|
||||
of nkIdent, nkSym:
|
||||
result = n
|
||||
let ident = considerQuotedIdent(c.c, n)
|
||||
@@ -53,8 +53,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
if n.kind == nkContinueStmt:
|
||||
localError(c.c.config, n.info,
|
||||
"'continue' not supported in a 'fields' loop")
|
||||
result = copyNode(n)
|
||||
newSons(result, len(n))
|
||||
result = shallowCopy(n)
|
||||
for i in 0 ..< len(n):
|
||||
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
|
||||
|
||||
|
||||
@@ -433,15 +433,12 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
|
||||
let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
|
||||
|
||||
|
||||
# if srcTyp.kind == tyUInt64 and "FFFFFF" in $n:
|
||||
# echo "n: ", n, " a: ", a
|
||||
# echo "from: ", srcTyp, " to: ", dstTyp, " check: ", check
|
||||
# echo getInt(a)
|
||||
# echo high(int64)
|
||||
# writeStackTrace()
|
||||
|
||||
# XXX range checks?
|
||||
case dstTyp.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
case srcTyp.kind
|
||||
@@ -451,7 +448,7 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
var val = a.getOrdValue
|
||||
if check: rangeCheck(n, val, g)
|
||||
result = newIntNodeT(val, n, g)
|
||||
if dstTyp.kind in {tyUInt .. tyUInt64}:
|
||||
if dstTyp.kind in {tyUInt..tyUInt64}:
|
||||
result.kind = nkUIntLit
|
||||
else:
|
||||
result = a
|
||||
@@ -736,7 +733,11 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n, g)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n, g)
|
||||
of nkStmtListExpr:
|
||||
if n.len == 2 and n[0].kind == nkComesFrom:
|
||||
result = getConstExpr(m, n[1], g)
|
||||
var i = 0
|
||||
while i <= n.len - 2:
|
||||
if n[i].kind in {nkComesFrom, nkCommentStmt, nkEmpty}: i.inc
|
||||
else: break
|
||||
if i == n.len - 1:
|
||||
result = getConstExpr(m, n[i], g)
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -380,7 +380,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||
if t.kind == tyRef:
|
||||
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||
if optNimV2 in c.config.globalOptions:
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
# we have to watch out, there are also 'owned proc' types that can be used
|
||||
# multiple times as long as they don't have closures.
|
||||
|
||||
@@ -792,7 +792,8 @@ proc isTrivalStmtExpr(n: PNode): bool =
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string): PNode =
|
||||
proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string;
|
||||
flags: TExprFlags): PNode =
|
||||
if selector.kind in nkCallKinds:
|
||||
# we transform
|
||||
# n := for a, b, c in m(x, y, z): Y
|
||||
@@ -821,14 +822,14 @@ proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string): PNode
|
||||
callExpr.add newSymNode(match)
|
||||
callExpr.add n
|
||||
case match.kind
|
||||
of skMacro: result = semMacroExpr(c, callExpr, callExpr, match, {})
|
||||
of skTemplate: result = semTemplateExpr(c, callExpr, match, {})
|
||||
of skMacro: result = semMacroExpr(c, callExpr, callExpr, match, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, callExpr, match, flags)
|
||||
else: result = nil
|
||||
|
||||
proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
||||
result = handleStmtMacro(c, n, n[^2], "ForLoopStmt")
|
||||
proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
result = handleStmtMacro(c, n, n[^2], "ForLoopStmt", flags)
|
||||
|
||||
proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||
proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
# n[0] has been sem'checked and has a type. We use this to resolve
|
||||
# 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to
|
||||
# be the best solution.
|
||||
@@ -848,8 +849,8 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||
r.call.sons[1] = n
|
||||
let toExpand = semResolvedCall(c, r, r.call, {})
|
||||
case match.kind
|
||||
of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, {})
|
||||
of skTemplate: result = semTemplateExpr(c, toExpand, match, {})
|
||||
of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, toExpand, match, flags)
|
||||
else: result = nil
|
||||
# this would be the perfectly consistent solution with 'for loop macros',
|
||||
# but it kinda sucks for pattern matching as the matcher is not attached to
|
||||
@@ -861,7 +862,7 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
checkMinSonsLen(n, 3, c.config)
|
||||
var length = len(n)
|
||||
if forLoopMacros in c.features:
|
||||
result = handleForLoopMacro(c, n)
|
||||
result = handleForLoopMacro(c, n, flags)
|
||||
if result != nil: return result
|
||||
openScope(c)
|
||||
result = n
|
||||
@@ -924,7 +925,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
popCaseContext(c)
|
||||
closeScope(c)
|
||||
if caseStmtMacros in c.features:
|
||||
result = handleCaseStmtMacro(c, n)
|
||||
result = handleCaseStmtMacro(c, n, flags)
|
||||
if result != nil:
|
||||
return result
|
||||
localError(c.config, n.sons[0].info, errSelectorMustBeOfCertainTypes)
|
||||
@@ -954,9 +955,9 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
checkSonsLen(x, 1, c.config)
|
||||
x.sons[0] = semExprBranchScope(c, x.sons[0])
|
||||
typ = commonType(typ, x.sons[0])
|
||||
hasElse = true
|
||||
if chckCovered and covered == toCover(c, n.sons[0].typ):
|
||||
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
|
||||
localError(c.config, x.info, "invalid else, all cases are already covered")
|
||||
hasElse = true
|
||||
chckCovered = false
|
||||
else:
|
||||
illFormedAst(x, c.config)
|
||||
@@ -1449,8 +1450,13 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||
continue
|
||||
|
||||
doAssert r.sons[0].kind == nkSym
|
||||
# Expand the macro here
|
||||
result = semMacroExpr(c, r, r, r.sons[0].sym, {})
|
||||
let m = r.sons[0].sym
|
||||
case m.kind
|
||||
of skMacro: result = semMacroExpr(c, r, r, m, {})
|
||||
of skTemplate: result = semTemplateExpr(c, r, m, {})
|
||||
else:
|
||||
prc.sons[pragmasPos] = n
|
||||
continue
|
||||
|
||||
doAssert result != nil
|
||||
|
||||
@@ -1526,7 +1532,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
closeScope(c) # close scope for parameters
|
||||
popOwner(c)
|
||||
result.typ = s.typ
|
||||
if optNimV2 in c.config.globalOptions:
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
|
||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
@@ -1563,7 +1569,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
popProcCon(c)
|
||||
popOwner(c)
|
||||
closeScope(c)
|
||||
if optNimV2 in c.config.globalOptions and result.typ != nil:
|
||||
if optOwnedRefs in c.config.globalOptions and result.typ != nil:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
# alternative variant (not quite working):
|
||||
# var prc = arg[0].sym
|
||||
@@ -1955,7 +1961,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if isAnon:
|
||||
n.kind = nkLambda
|
||||
result.typ = s.typ
|
||||
if optNimV2 in c.config.globalOptions:
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
if isTopLevel(c) and s.kind != skIterator and
|
||||
s.typ.callConv == ccClosure:
|
||||
|
||||
@@ -242,6 +242,10 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||
|
||||
proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||
incl(s.flags, sfUsed)
|
||||
# bug #12885; ideally sem'checking is performed again afterwards marking
|
||||
# the symbol as used properly, but the nfSem mechanism currently prevents
|
||||
# that from happening, so we mark the module as used here already:
|
||||
markOwnerModuleAsUsed(c, s)
|
||||
# we do not call onUse here, as the identifier is not really
|
||||
# resolved here. We will fixup the used identifiers later.
|
||||
case s.kind
|
||||
@@ -261,6 +265,11 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||
else:
|
||||
if isField and sfGenSym in s.flags: result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
# Issue #12832
|
||||
when defined(nimsuggest):
|
||||
suggestSym(c.config, n.info, s, c.graph.usageSym, false)
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
styleCheckUse(c.config, n.info, s)
|
||||
|
||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
@@ -626,7 +626,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
case typ.kind
|
||||
of shouldChckCovered:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
of tyFloat..tyFloat128, tyError:
|
||||
discard
|
||||
of tyRange:
|
||||
if skipTypes(typ.sons[0], abstractInst).kind in shouldChckCovered:
|
||||
@@ -634,8 +634,8 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
of tyForward:
|
||||
errorUndeclaredIdentifier(c, n.sons[0].info, typ.sym.name.s)
|
||||
elif not isOrdinalType(typ):
|
||||
localError(c.config, n.sons[0].info, "selector must be of an ordinal type, float or string")
|
||||
elif firstOrd(c.config, typ) != 0:
|
||||
localError(c.config, n.sons[0].info, "selector must be of an ordinal type or float")
|
||||
if firstOrd(c.config, typ) != 0:
|
||||
localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
|
||||
") must be 0 for discriminant")
|
||||
elif lengthOrd(c.config, typ) > 0x00007FFF:
|
||||
@@ -768,7 +768,7 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
|
||||
else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)")
|
||||
of nkRecList, nkRecWhen, nkElifBranch, nkElse:
|
||||
for i in 0 ..< len(n):
|
||||
for i in int(n.kind == nkElifBranch) ..< len(n):
|
||||
addInheritedFieldsAux(c, check, pos, n.sons[i])
|
||||
of nkSym:
|
||||
incl(check, n.sym.name.id)
|
||||
@@ -877,7 +877,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
if tfPartial in result.flags:
|
||||
if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial)
|
||||
#if not isNilable: result.flags.incl tfNotNil
|
||||
if isOwned and optNimV2 in c.config.globalOptions:
|
||||
if isOwned and optOwnedRefs in c.config.globalOptions:
|
||||
let t = newTypeS(tyOwned, c)
|
||||
t.flags.incl tfHasOwned
|
||||
t.rawAddSonNoPropagationOfTypeFlags result
|
||||
@@ -1644,7 +1644,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = semTypeof(c, n[1], prev)
|
||||
elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeOf:
|
||||
result = semTypeof2(c, n, prev)
|
||||
elif op.s == "owned" and optNimV2 notin c.config.globalOptions and n.len == 2:
|
||||
elif op.s == "owned" and optOwnedRefs notin c.config.globalOptions and n.len == 2:
|
||||
result = semTypeExpr(c, n[1], prev)
|
||||
else:
|
||||
if c.inGenericContext > 0 and n.kind == nkCall:
|
||||
|
||||
@@ -134,11 +134,14 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
|
||||
initIdTable(c.bindings)
|
||||
|
||||
proc put(c: var TCandidate, key, val: PType) {.inline.} =
|
||||
## Given: proc foo[T](x: T); foo(4)
|
||||
## key: 'T'
|
||||
## val: 'int' (typeof(4))
|
||||
when false:
|
||||
let old = PType(idTableGet(c.bindings, key))
|
||||
if old != nil:
|
||||
echo "Putting ", typeToString(key), " ", typeToString(val), " and old is ", typeToString(old)
|
||||
if typeToString(old) == "seq[string]":
|
||||
if typeToString(old) == "float32":
|
||||
writeStackTrace()
|
||||
if c.c.module.name.s == "temp3":
|
||||
echo "binding ", key, " -> ", val
|
||||
@@ -1086,7 +1089,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||
if x == isNone: return isNone
|
||||
if x < result: result = x
|
||||
return
|
||||
return result
|
||||
|
||||
of tyAnd:
|
||||
# XXX: deal with the current dual meaning of tyGenericParam
|
||||
@@ -1420,7 +1423,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
let ff = rootf.sons[i]
|
||||
let aa = roota.sons[i]
|
||||
let res = typeRel(c, ff, aa, nextFlags)
|
||||
if res != isEqual: result = isGeneric
|
||||
if res != isNone and res != isEqual: result = isGeneric
|
||||
if res notin {isEqual, isGeneric}:
|
||||
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||
let paramFlags = rootf.base.sons[i-1].flags
|
||||
@@ -1938,7 +1941,8 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
var call = newNodeI(nkCall, arg.info)
|
||||
call.add(f.n.copyTree)
|
||||
call.add(arg.copyTree)
|
||||
result = c.semExpr(c, call)
|
||||
result = c.semTryExpr(c, call)
|
||||
|
||||
if result != nil:
|
||||
if result.typ == nil: return nil
|
||||
# resulting type must be consistent with the other arguments:
|
||||
@@ -2551,13 +2555,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||
formal.name.s)
|
||||
if nfDefaultRefsParam in formal.ast.flags:
|
||||
m.call.flags.incl nfDefaultRefsParam
|
||||
var def = copyTree(formal.ast)
|
||||
if def.kind == nkNilLit:
|
||||
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
|
||||
var defaultValue = copyTree(formal.ast)
|
||||
if defaultValue.kind == nkNilLit:
|
||||
defaultValue = implicitConv(nkHiddenStdConv, formal.typ, defaultValue, m, c)
|
||||
# proc foo(x: T = 0.0)
|
||||
# foo()
|
||||
if {tfImplicitTypeParam, tfGenericTypeParam} * formal.typ.flags != {}:
|
||||
put(m, formal.typ, def.typ)
|
||||
def.flags.incl nfDefaultParam
|
||||
setSon(m.call, formal.position + 1, def)
|
||||
let existing = PType(idTableGet(m.bindings, formal.typ))
|
||||
if existing == nil or existing.kind == tyTypeDesc:
|
||||
# see bug #11600:
|
||||
put(m, formal.typ, defaultValue.typ)
|
||||
defaultValue.flags.incl nfDefaultParam
|
||||
setSon(m.call, formal.position + 1, defaultValue)
|
||||
inc(f)
|
||||
# forget all inferred types if the overload matching failed
|
||||
if m.state == csNoMatch:
|
||||
|
||||
@@ -138,12 +138,13 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a
|
||||
accum.offset = szUnknownSize
|
||||
accum.maxAlign = szUnknownSize
|
||||
else:
|
||||
# the union neds to be aligned first, before the offsets can be assigned
|
||||
# the union needs to be aligned first, before the offsets can be assigned
|
||||
accum.align(maxChildAlign)
|
||||
let accumRoot = accum # copy, because each branch should start af the same offset
|
||||
for i in 1 ..< len(n):
|
||||
var branchAccum = accumRoot
|
||||
var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1)
|
||||
computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, packed, branchAccum)
|
||||
discard finish(branchAccum)
|
||||
accum.mergeBranch(branchAccum)
|
||||
of nkRecList:
|
||||
for i, child in n.sons:
|
||||
@@ -171,9 +172,10 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var
|
||||
localError(conf, n.info, "Illegal use of ``case`` in union type.")
|
||||
of nkRecList:
|
||||
let accumRoot = accum # copy, because each branch should start af the same offset
|
||||
for i, child in n.sons:
|
||||
var branchAccum = accumRoot
|
||||
for child in n.sons:
|
||||
var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1)
|
||||
computeUnionObjectOffsetsFoldFunction(conf, child, branchAccum)
|
||||
discard finish(branchAccum)
|
||||
accum.mergeBranch(branchAccum)
|
||||
of nkSym:
|
||||
var size = szUnknownSize
|
||||
|
||||
@@ -65,7 +65,7 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: P
|
||||
vpart.sons[2] = if varInit.isNil: v else: vpart[1]
|
||||
varSection.add vpart
|
||||
if varInit != nil:
|
||||
if useShallowCopy and typeNeedsNoDeepCopy(typ) or optNimV2 in g.config.globalOptions:
|
||||
if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions:
|
||||
varInit.add newFastAsgnStmt(newSymNode(result), v)
|
||||
else:
|
||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||
|
||||
@@ -573,10 +573,19 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
case arg.kind
|
||||
of nkEmpty..nkNilLit:
|
||||
result = paDirectMapping
|
||||
of nkPar, nkTupleConstr, nkCurly, nkBracket:
|
||||
result = paFastAsgn
|
||||
for i in 0 ..< len(arg):
|
||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||
of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr:
|
||||
result = putArgInto(arg[0], formal)
|
||||
of nkCurly, nkBracket:
|
||||
for i in 0..<arg.len:
|
||||
if putArgInto(arg[i], formal) != paDirectMapping:
|
||||
return paFastAsgn
|
||||
result = paDirectMapping
|
||||
of nkPar, nkTupleConstr, nkObjConstr:
|
||||
for i in 0..<arg.len:
|
||||
let a = if arg[i].kind == nkExprColonExpr: arg[i][1]
|
||||
else: arg[0]
|
||||
if putArgInto(a, formal) != paDirectMapping:
|
||||
return paFastAsgn
|
||||
result = paDirectMapping
|
||||
else:
|
||||
if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
|
||||
@@ -663,7 +672,6 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
t = arg.typ
|
||||
# generate a temporary and produce an assignment statement:
|
||||
var temp = newTemp(c, t, formal.info)
|
||||
#temp.sym.flags.incl sfCursor
|
||||
addVar(v, temp)
|
||||
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
@@ -915,7 +923,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
oldDeferAnchor = c.deferAnchor
|
||||
c.deferAnchor = n
|
||||
if (n.typ != nil and tfHasAsgn in n.typ.flags) or
|
||||
optNimV2 in c.graph.config.globalOptions:
|
||||
optSeqDestructors in c.graph.config.globalOptions:
|
||||
c.needsDestroyPass = true
|
||||
case n.kind
|
||||
of nkSym:
|
||||
@@ -1096,15 +1104,15 @@ proc liftDeferAux(n: PNode) =
|
||||
if n.sons[i].kind == nkDefer:
|
||||
let deferPart = newNodeI(nkFinally, n.sons[i].info)
|
||||
deferPart.add n.sons[i].sons[0]
|
||||
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||
var body = newNodeI(n.kind, n.sons[i].info)
|
||||
var tryStmt = newNodeIT(nkTryStmt, n.sons[i].info, n.typ)
|
||||
var body = newNodeIT(n.kind, n.sons[i].info, n.typ)
|
||||
if i < last:
|
||||
body.sons = n.sons[(i+1)..last]
|
||||
tryStmt.addSon(body)
|
||||
tryStmt.addSon(deferPart)
|
||||
n.sons[i] = tryStmt
|
||||
n.sons.setLen(i+1)
|
||||
n.typ = n.sons[i].typ
|
||||
n.typ = tryStmt.typ
|
||||
goOn = true
|
||||
break
|
||||
for i in 0..n.safeLen-1:
|
||||
|
||||
@@ -87,7 +87,11 @@ proc isUnsigned*(t: PType): bool =
|
||||
t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}
|
||||
|
||||
proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
|
||||
case n.kind
|
||||
var k = n.kind
|
||||
if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}:
|
||||
k = nkUIntLit
|
||||
|
||||
case k
|
||||
of nkCharLit, nkUIntLit..nkUInt64Lit:
|
||||
# XXX: enable this assert
|
||||
#assert n.typ == nil or isUnsigned(n.typ), $n.typ
|
||||
|
||||
@@ -280,7 +280,7 @@ type
|
||||
ExceptionGotoUnhandled
|
||||
|
||||
proc findExceptionHandler(c: PCtx, f: PStackFrame, exc: PNode):
|
||||
tuple[why: ExceptionGoto, where: int] =
|
||||
tuple[why: ExceptionGoto, where: int] =
|
||||
let raisedType = exc.typ.skipTypes(abstractPtrs)
|
||||
|
||||
while f.safePoints.len > 0:
|
||||
@@ -471,7 +471,8 @@ template handleJmpBack() {.dirty.} =
|
||||
dec(c.loopIterations)
|
||||
|
||||
proc recSetFlagIsRef(arg: PNode) =
|
||||
arg.flags.incl(nfIsRef)
|
||||
if arg.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
arg.flags.incl(nfIsRef)
|
||||
for i in 0 ..< arg.safeLen:
|
||||
arg.sons[i].recSetFlagIsRef
|
||||
|
||||
@@ -1315,9 +1316,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcQuit:
|
||||
if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
|
||||
message(c.config, c.debug[pc], hintQuitCalled)
|
||||
msgQuit(int8(toInt(getOrdValue(regs[ra].regToNode))))
|
||||
msgQuit(int8(toInt(getOrdValue(regs[ra].regToNode, onError = toInt128(1)))))
|
||||
else:
|
||||
return TFullReg(kind: rkNone)
|
||||
of opcInvalidField:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & regs[ra].node.strVal)
|
||||
of opcSetLenStr:
|
||||
decodeB(rkNode)
|
||||
#createStrKeepNode regs[ra]
|
||||
|
||||
@@ -72,7 +72,7 @@ type
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcIsNil, opcOf, opcIs,
|
||||
opcSubStr, opcParseFloat, opcConv, opcCast,
|
||||
opcQuit,
|
||||
opcQuit, opcInvalidField,
|
||||
opcNarrowS, opcNarrowU,
|
||||
opcSignExtend,
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#
|
||||
|
||||
import ast, types, msgs, os, options, idents, lineinfos
|
||||
from pathutils import AbsoluteFile
|
||||
|
||||
proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string =
|
||||
try:
|
||||
@@ -17,6 +18,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str
|
||||
result = readFile(filename)
|
||||
# we produce a fake include statement for every slurped filename, so that
|
||||
# the module dependencies are accurate:
|
||||
discard conf.fileInfoIdx(AbsoluteFile filename)
|
||||
appendToModule(module, newNode(nkIncludeStmt, info, @[
|
||||
newStrNode(nkStrLit, filename)]))
|
||||
except IOError:
|
||||
|
||||
@@ -202,29 +202,41 @@ proc bestEffort(c: PCtx): TLineInfo =
|
||||
else:
|
||||
c.module.info
|
||||
|
||||
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||
let typ = tt.skipTypesOrNil({tyStatic})
|
||||
proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
|
||||
let c = cc.prc
|
||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||
# discardable return types we may not know the desired type. This can happen
|
||||
# for e.g. mNAdd[Multiple]:
|
||||
let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
|
||||
for i in 0 .. c.maxSlots-1:
|
||||
for i in start .. c.maxSlots-1:
|
||||
if c.slots[i].kind == k and not c.slots[i].inUse:
|
||||
c.slots[i].inUse = true
|
||||
return TRegister(i)
|
||||
|
||||
# if register pressure is high, we re-use more aggressively:
|
||||
if c.maxSlots >= HighRegisterPressure and false:
|
||||
for i in 0 .. c.maxSlots-1:
|
||||
if c.maxSlots >= high(TRegister):
|
||||
for i in start .. c.maxSlots-1:
|
||||
if not c.slots[i].inUse:
|
||||
c.slots[i] = (inUse: true, kind: k)
|
||||
return TRegister(i)
|
||||
if c.maxSlots >= high(TRegister):
|
||||
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
|
||||
result = TRegister(c.maxSlots)
|
||||
c.slots[c.maxSlots] = (inUse: true, kind: k)
|
||||
inc c.maxSlots
|
||||
result = TRegister(max(c.maxSlots, start))
|
||||
c.slots[result] = (inUse: true, kind: k)
|
||||
c.maxSlots = result + 1
|
||||
|
||||
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||
let typ = tt.skipTypesOrNil({tyStatic})
|
||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||
# discardable return types we may not know the desired type. This can happen
|
||||
# for e.g. mNAdd[Multiple]:
|
||||
let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
|
||||
result = getFreeRegister(cc, k, start = 0)
|
||||
when false:
|
||||
# enable this to find "register" leaks:
|
||||
if result == 4:
|
||||
echo "begin ---------------"
|
||||
writeStackTrace()
|
||||
echo "end ----------------"
|
||||
|
||||
proc freeTemp(c: PCtx; r: TRegister) =
|
||||
let c = c.prc
|
||||
@@ -235,6 +247,8 @@ proc freeTemp(c: PCtx; r: TRegister) =
|
||||
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
|
||||
# if register pressure is high, we re-use more aggressively:
|
||||
let c = cc.prc
|
||||
# we could also customize via the following (with proper caching in ConfigRef):
|
||||
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
|
||||
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
|
||||
for i in 0 .. c.maxSlots-n:
|
||||
if not c.slots[i].inUse:
|
||||
@@ -278,7 +292,9 @@ proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
|
||||
proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
|
||||
var tmp: TDest = -1
|
||||
gen(c, n, tmp, flags)
|
||||
#if n.typ.isEmptyType: InternalAssert tmp < 0
|
||||
if tmp >= 0:
|
||||
freeTemp(c, tmp)
|
||||
#if n.typ.isEmptyType: internalAssert tmp < 0
|
||||
|
||||
proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
||||
var tmp: TDest = -1
|
||||
@@ -335,7 +351,15 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.gen(n.sons[1], dest)
|
||||
|
||||
for i in oldRegisterCount ..< c.prc.maxSlots:
|
||||
if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
|
||||
#if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
|
||||
if i != dest:
|
||||
when not defined(release):
|
||||
if c.prc.slots[i].inUse and c.prc.slots[i].kind in {slotTempUnknown,
|
||||
slotTempInt,
|
||||
slotTempFloat,
|
||||
slotTempStr,
|
||||
slotTempComplex}:
|
||||
doAssert false, "leaking temporary " & $i & " " & $c.prc.slots[i].kind
|
||||
c.prc.slots[i] = (inUse: false, kind: slotEmpty)
|
||||
|
||||
c.clearDest(n, dest)
|
||||
@@ -752,6 +776,7 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
tmp = c.genx(n.sons[2])
|
||||
c.gABC(n, opc, dest, tmp, 0)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(dest)
|
||||
|
||||
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
var x = n.sons[1]
|
||||
@@ -762,6 +787,7 @@ proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
c.gABC(n, opc, dest, tmp, 0)
|
||||
#c.genAsgnPatch(n.sons[1], dest)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(dest)
|
||||
|
||||
proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||
let tmp = c.genx(n.sons[1])
|
||||
@@ -1085,6 +1111,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
|
||||
c.genAsgnPatch(n.sons[1], d)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(d)
|
||||
of mSwap:
|
||||
unused(c, n, dest)
|
||||
c.gen(lowerSwap(c.graph, n, if c.prc == nil: c.module else: c.prc.sym))
|
||||
@@ -1424,6 +1451,7 @@ proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||
assert n.typ != nil
|
||||
if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||
let tmp = c.genx(ri)
|
||||
@@ -1434,13 +1462,7 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||
proc setSlot(c: PCtx; v: PSym) =
|
||||
# XXX generate type initialization here?
|
||||
if v.position == 0:
|
||||
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
|
||||
if c.prc.maxSlots >= high(TRegister):
|
||||
globalError(c.config, v.info, "cannot generate code; too many registers required")
|
||||
v.position = c.prc.maxSlots
|
||||
c.prc.slots[v.position] = (inUse: true,
|
||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||
inc c.prc.maxSlots
|
||||
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
|
||||
|
||||
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
|
||||
globalError(c.config, n.info, "cannot evaluate at compile time: " &
|
||||
@@ -1463,7 +1485,10 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
if {sfCompileTime, sfGlobal} <= s.flags: return
|
||||
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
||||
not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
|
||||
cannotEval(c, n)
|
||||
# little hack ahead for bug #12612: assume gensym'ed variables
|
||||
# are in the right scope:
|
||||
if sfGenSym in s.flags and c.prc.sym == nil: discard
|
||||
else: cannotEval(c, n)
|
||||
elif s.kind in {skProc, skFunc, skConverter, skMethod,
|
||||
skIterator} and sfForward in s.flags:
|
||||
cannotEval(c, n)
|
||||
@@ -1501,6 +1526,8 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
else:
|
||||
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(idx)
|
||||
c.freeTemp(dest)
|
||||
of nkCheckedFieldExpr:
|
||||
var objR: TDest = -1
|
||||
genCheckedObjAccessAux(c, le, objR, {gfNode})
|
||||
@@ -1508,17 +1535,21 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
# c.freeTemp(idx) # BUGFIX, see nkDotExpr
|
||||
c.freeTemp(objR)
|
||||
of nkDotExpr:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let idx = genField(c, le.sons[1])
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
|
||||
# c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(dest)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(tmp)
|
||||
of nkSym:
|
||||
let s = le.sym
|
||||
@@ -1532,7 +1563,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
else:
|
||||
if s.kind == skForVar: c.setSlot s
|
||||
internalAssert c.config, s.position > 0 or (s.position == 0 and
|
||||
s.kind in {skParam,skResult})
|
||||
s.kind in {skParam, skResult})
|
||||
var dest: TRegister = s.position + ord(s.kind == skParam)
|
||||
assert le.typ != nil
|
||||
if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
|
||||
@@ -1545,6 +1576,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
else:
|
||||
let dest = c.genx(le, {gfNodeAddr})
|
||||
genAsgn(c, dest, ri, requiresCopy)
|
||||
c.freeTemp(dest)
|
||||
|
||||
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
||||
var n = newNode(nkType)
|
||||
@@ -1611,7 +1643,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
else:
|
||||
if s.kind == skForVar and c.mode == emRepl: c.setSlot(s)
|
||||
if s.position > 0 or (s.position == 0 and
|
||||
s.kind in {skParam,skResult}):
|
||||
s.kind in {skParam, skResult}):
|
||||
if dest < 0:
|
||||
dest = s.position + ord(s.kind == skParam)
|
||||
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
|
||||
@@ -1628,8 +1660,8 @@ template needsRegLoad(): untyped =
|
||||
{gfNode, gfNodeAddr} * flags == {} and
|
||||
fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
|
||||
|
||||
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
flags: TGenFlags) =
|
||||
proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
flags: TGenFlags) =
|
||||
let a = c.genx(n.sons[0], flags)
|
||||
let b = c.genIndex(n.sons[1], n.sons[0].typ)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -1682,12 +1714,18 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
|
||||
let setLit = c.genx(checkExpr[1])
|
||||
var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
|
||||
c.gABC(n, opcContainsSet, rs, setLit, discVal)
|
||||
c.freeTemp(discVal)
|
||||
c.freeTemp(setLit)
|
||||
# If the check fails let the user know
|
||||
let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
|
||||
c.freeTemp(rs)
|
||||
# Not ideal but will do for the moment
|
||||
c.gABC(n, opcQuit)
|
||||
let strType = getSysType(c.graph, n.info, tyString)
|
||||
var fieldNameRegister: TDest = c.getTemp(strType)
|
||||
let strLit = newStrNode($accessExpr[1], accessExpr[1].info)
|
||||
strLit.typ = strType
|
||||
c.genLit(strLit, fieldNameRegister)
|
||||
c.gABC(n, opcInvalidField, fieldNameRegister)
|
||||
c.freeTemp(fieldNameRegister)
|
||||
c.patch(lab1)
|
||||
|
||||
proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
@@ -1715,11 +1753,11 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||
if arrayType in {tyString, tyCString}:
|
||||
genArrAccess2(c, n, dest, opcLdStrIdx, {})
|
||||
genArrAccessOpcode(c, n, dest, opcLdStrIdx, {})
|
||||
elif arrayType == tyTypeDesc:
|
||||
c.genTypeLit(n.typ, dest)
|
||||
else:
|
||||
genArrAccess2(c, n, dest, opcLdArr, flags)
|
||||
genArrAccessOpcode(c, n, dest, opcLdArr, flags)
|
||||
|
||||
proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
|
||||
if t != nil and t.len > 0 and t.sons[0] != nil:
|
||||
@@ -1919,16 +1957,6 @@ proc genProc*(c: PCtx; s: PSym): int
|
||||
|
||||
proc matches(s: PSym; x: string): bool =
|
||||
let y = x.split('.')
|
||||
var s = s
|
||||
var L = y.len-1
|
||||
while L >= 0:
|
||||
if s == nil or (y[L].cmpIgnoreStyle(s.name.s) != 0 and y[L] != "*"):
|
||||
return false
|
||||
s = s.owner
|
||||
dec L
|
||||
result = true
|
||||
|
||||
proc matches(s: PSym; y: varargs[string]): bool =
|
||||
var s = s
|
||||
var L = y.len-1
|
||||
while L >= 0:
|
||||
@@ -1991,11 +2019,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
elif s.kind == skMethod:
|
||||
localError(c.config, n.info, "cannot call method " & s.name.s &
|
||||
" at compile time")
|
||||
elif matches(s, "stdlib", "marshal", "to"):
|
||||
elif matches(s, "stdlib.marshal.to"):
|
||||
# XXX marshal load&store should not be opcodes, but use the
|
||||
# general callback mechanisms.
|
||||
genMarshalLoad(c, n, dest)
|
||||
elif matches(s, "stdlib", "marshal", "$$"):
|
||||
elif matches(s, "stdlib.marshal.$$"):
|
||||
genMarshalStore(c, n, dest)
|
||||
else:
|
||||
genCall(c, n, dest)
|
||||
@@ -2099,7 +2127,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of nkComesFrom:
|
||||
discard "XXX to implement for better stack traces"
|
||||
else:
|
||||
globalError(c.config, n.info, "cannot generate VM code for " & $n)
|
||||
if n.typ != nil and n.typ.isCompileTimeOnly:
|
||||
genTypeLit(c, n.typ, dest)
|
||||
else:
|
||||
globalError(c.config, n.info, "cannot generate VM code for " & $n)
|
||||
|
||||
proc removeLastEof(c: PCtx) =
|
||||
let last = c.code.len-1
|
||||
|
||||
@@ -148,7 +148,11 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
systemop getCurrentException
|
||||
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
|
||||
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
|
||||
systemop gorgeEx
|
||||
|
||||
if defined(nimsuggest) or c.config.cmd == cmdCheck:
|
||||
discard "don't run staticExec for 'nim suggest'"
|
||||
else:
|
||||
systemop gorgeEx
|
||||
macrosop getProjectPath
|
||||
|
||||
registerCallback c, "stdlib.os.getCurrentCompilerExe", proc (a: VmArgs) {.nimcall.} =
|
||||
|
||||
@@ -37,8 +37,6 @@ type
|
||||
wMagic, wThread, wFinal, wProfiler, wMemTracker, wObjChecks,
|
||||
wIntDefine, wStrDefine, wBoolDefine
|
||||
|
||||
wCursor,
|
||||
|
||||
wImmediate, wConstructor, wDestructor, wDelegator, wOverride,
|
||||
wImportCpp, wImportObjC,
|
||||
wImportCompilerProc,
|
||||
@@ -125,8 +123,6 @@ const
|
||||
"magic", "thread", "final", "profiler", "memtracker", "objchecks",
|
||||
"intdefine", "strdefine", "booldefine",
|
||||
|
||||
"cursor",
|
||||
|
||||
"immediate", "constructor", "destructor", "delegator", "override",
|
||||
"importcpp", "importobjc",
|
||||
"importcompilerproc", "importc", "importjs", "exportc", "exportcpp", "exportnims",
|
||||
|
||||
@@ -76,6 +76,7 @@ path="$lib/pure"
|
||||
debugger:off
|
||||
line_dir:off
|
||||
opt:speed
|
||||
define:release
|
||||
@end
|
||||
|
||||
@if false: # not danger: # this does not work yet.
|
||||
|
||||
@@ -208,6 +208,7 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||
|
||||
<!-- Google fonts -->
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||
|
||||
@@ -99,6 +99,7 @@ Advanced options:
|
||||
--putenv:key=value set an environment variable
|
||||
--NimblePath:PATH add a path for Nimble support
|
||||
--noNimblePath deactivate the Nimble path
|
||||
--clearNimblePath empty the list of Nimble package search paths
|
||||
--noCppExceptions use default exception handling with C++ backend
|
||||
--cppCompileToNamespace:namespace
|
||||
use the provided namespace for the generated C++ code,
|
||||
|
||||
@@ -157,7 +157,7 @@ AST:
|
||||
|
||||
As a side note, if you choose to use infix operators in a prefix form, the AST
|
||||
behaves as a
|
||||
[parenthetical function call](./macros.html#calls-expressions-call-with) with
|
||||
[parenthetical function call](#callsslashexpressions-call-with) with
|
||||
``nnkAccQuoted``, as follows:
|
||||
|
||||
Concrete syntax:
|
||||
@@ -237,7 +237,7 @@ Call with raw string literal
|
||||
----------------------------
|
||||
|
||||
This is used, for example, in the ``bindSym`` examples
|
||||
[here](http://nim-lang.org/docs/manual.html#macros-bindsym) and with
|
||||
[here](manual.html#macros-bindsym) and with
|
||||
``re"some regexp"`` in the regular expression module.
|
||||
|
||||
Concrete syntax:
|
||||
@@ -902,7 +902,7 @@ as the compiler needs to know the type somehow (which it can infer from
|
||||
the given assignment).
|
||||
|
||||
This is not the same AST for all uses of ``var``. See
|
||||
[Procedure declaration](http://nim-lang.org/docs/macros.html#statements-procedure-declaration)
|
||||
[Procedure declaration](macros.html#statements-procedure-declaration)
|
||||
for details.
|
||||
|
||||
Let section
|
||||
@@ -1361,7 +1361,7 @@ Template declaration
|
||||
|
||||
Templates (as well as macros, as we'll see) have a slightly expanded AST when
|
||||
compared to procs and iterators. The reason for this is [term-rewriting
|
||||
macros](http://nim-lang.org/docs/manual.html#term-rewriting-macros). Notice
|
||||
macros](manual.html#term-rewriting-macros). Notice
|
||||
the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and
|
||||
``nnkIteratorDef`` above? That's where the term-rewriting macros go.
|
||||
|
||||
|
||||
@@ -107,12 +107,13 @@ Nim code calling the backend
|
||||
|
||||
Nim code can interface with the backend through the `Foreign function
|
||||
interface <manual.html#foreign-function-interface>`_ mainly through the
|
||||
`importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
|
||||
*generic* way of making backend symbols available in Nim and is available
|
||||
in all the target backends (JavaScript too). The C++ or Objective-C backends
|
||||
have their respective `ImportCpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ pragmas to call methods from
|
||||
classes.
|
||||
`importc pragma <manual.html#foreign-function-interface-importc-pragma>`_.
|
||||
The ``importc`` pragma is the *generic* way of making backend symbols available
|
||||
in Nim and is available in all the target backends (JavaScript too). The C++
|
||||
or Objective-C backends have their respective `ImportCpp
|
||||
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
|
||||
pragmas to call methods from classes.
|
||||
|
||||
Whenever you use any of these pragmas you need to integrate native code into
|
||||
your final binary. In the case of JavaScript this is no problem at all, the
|
||||
@@ -124,18 +125,18 @@ statically or dynamically. The preferred way of integrating native code is to
|
||||
use dynamic linking because it allows you to compile Nim programs without
|
||||
the need for having the related development libraries installed. This is done
|
||||
through the `dynlib pragma for import
|
||||
<manual.html#dynlib-pragma-for-import>`_, though more specific control can be
|
||||
gained using the `dynlib module <dynlib.html>`_.
|
||||
<manual.html#foreign-function-interface-dynlib-pragma-for-import>`_, though
|
||||
more specific control can be gained using the `dynlib module <dynlib.html>`_.
|
||||
|
||||
The `dynlibOverride <nimc.html#dynliboverride>`_ command line switch allows
|
||||
to avoid dynamic linking if you need to statically link something instead.
|
||||
Nim wrappers designed to statically link source files can use the `compile
|
||||
pragma <nimc.html#compile-pragma>`_ if there are few sources or providing
|
||||
them along the Nim code is easier than using a system library. Libraries
|
||||
installed on the host system can be linked in with the `PassL pragma
|
||||
<nimc.html#passl-pragma>`_.
|
||||
pragma <manual.html#implementation-specific-pragmas-compile-pragma>`_ if
|
||||
there are few sources or providing them along the Nim code is easier than using
|
||||
a system library. Libraries installed on the host system can be linked in with
|
||||
the `PassL pragma <manual.html#implementation-specific-pragmas-passl-pragma>`_.
|
||||
|
||||
To wrap native code, take a look at the `c2nim tool <https://nim-lang.org/docs/c2nim.html>`_ which helps
|
||||
To wrap native code, take a look at the `c2nim tool <https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst>`_ which helps
|
||||
with the process of scanning and transforming header files into a Nim
|
||||
interface.
|
||||
|
||||
@@ -215,12 +216,12 @@ Backend code calling Nim
|
||||
------------------------
|
||||
|
||||
Backend code can interface with Nim code exposed through the `exportc
|
||||
pragma <manual.html#exportc-pragma>`_. The ``exportc`` pragma is the *generic*
|
||||
way of making Nim symbols available to the backends. By default the Nim
|
||||
compiler will mangle all the Nim symbols to avoid any name collision, so
|
||||
the most significant thing the ``exportc`` pragma does is maintain the Nim
|
||||
symbol name, or if specified, use an alternative symbol for the backend in
|
||||
case the symbol rules don't match.
|
||||
pragma <manual.html#foreign-function-interface-exportc-pragma>`_. The
|
||||
``exportc`` pragma is the *generic* way of making Nim symbols available to
|
||||
the backends. By default the Nim compiler will mangle all the Nim symbols to
|
||||
avoid any name collision, so the most significant thing the ``exportc`` pragma
|
||||
does is maintain the Nim symbol name, or if specified, use an alternative
|
||||
symbol for the backend in case the symbol rules don't match.
|
||||
|
||||
The JavaScript target doesn't have any further interfacing considerations
|
||||
since it also has garbage collection, but the C targets require you to
|
||||
@@ -329,8 +330,8 @@ Nimcache naming logic
|
||||
The `nimcache`:idx: directory is generated during compilation and will hold
|
||||
either temporary or final files depending on your backend target. The default
|
||||
name for the directory depends on the used backend and on your OS but you can
|
||||
use the ``--nimcache`` `compiler switch <nimc.html#command-line-switches>`_ to
|
||||
change it.
|
||||
use the ``--nimcache`` `compiler switch
|
||||
<nimc.html#compiler-usage-command-line-switches>`_ to change it.
|
||||
|
||||
|
||||
Memory management
|
||||
@@ -349,14 +350,14 @@ Strings and C strings
|
||||
---------------------
|
||||
|
||||
The manual mentions that `Nim strings are implicitly convertible to
|
||||
cstrings <manual.html#cstring-type>`_ which makes interaction usually
|
||||
cstrings <manual.html#types-cstring-type>`_ which makes interaction usually
|
||||
painless. Most C functions accepting a Nim string converted to a
|
||||
``cstring`` will likely not need to keep this string around and by the time
|
||||
they return the string won't be needed any more. However, for the rare cases
|
||||
where a Nim string has to be preserved and made available to the C backend
|
||||
as a ``cstring``, you will need to manually prevent the string data from being
|
||||
freed with `GC_ref <system.html#GC_ref>`_ and `GC_unref
|
||||
<system.html#GC_unref>`_.
|
||||
freed with `GC_ref <system.html#GC_ref,string>`_ and `GC_unref
|
||||
<system.html#GC_unref,string>`_.
|
||||
|
||||
A similar thing happens with C code invoking Nim code which returns a
|
||||
``cstring``. Consider the following proc:
|
||||
@@ -382,10 +383,10 @@ Custom data types
|
||||
Just like strings, custom data types that are to be shared between Nim and
|
||||
the backend will need careful consideration of who controls who. If you want
|
||||
to hand a Nim reference to C code, you will need to use `GC_ref
|
||||
<system.html#GC_ref>`_ to mark the reference as used, so it does not get
|
||||
<system.html#GC_ref,ref.T>`_ to mark the reference as used, so it does not get
|
||||
freed. And for the C backend you will need to expose the `GC_unref
|
||||
<system.html#GC_unref>`_ proc to clean up this memory when it is not required
|
||||
any more.
|
||||
<system.html#GC_unref,ref.T>`_ proc to clean up this memory when it is not
|
||||
required any more.
|
||||
|
||||
Again, if you are wrapping a library which *mallocs* and *frees* data
|
||||
structures, you need to expose the appropriate *free* function to Nim so
|
||||
|
||||
@@ -191,7 +191,7 @@ the old name and introduce a new name:
|
||||
type Barz = enum baz0, baz1 {.deprecated.}, baz2
|
||||
|
||||
|
||||
See also `Deprecated <https://nim-lang.org/docs/manual.html#pragmas-deprecated-pragma>`_
|
||||
See also `Deprecated <manual.html#pragmas-deprecated-pragma>`_
|
||||
pragma in the manual.
|
||||
|
||||
|
||||
@@ -216,8 +216,7 @@ as well as ``testament`` and guarantee they stay in sync.
|
||||
assert "baz".addBar == "bazBar"
|
||||
result = a & "Bar"
|
||||
|
||||
See `parentDir <https://nim-lang.github.io/Nim/os.html#parentDir%2Cstring>`_
|
||||
example.
|
||||
See `parentDir <os.html#parentDir,string>`_ example.
|
||||
|
||||
The RestructuredText Nim uses has a special syntax for including code snippets
|
||||
embedded in documentation; these are not run by ``nim doc`` and therefore are
|
||||
@@ -360,7 +359,8 @@ General commit rules
|
||||
|
||||
2. If you introduce changes which affect backwards compatibility,
|
||||
make breaking changes, or have PR which is tagged as ``[feature]``,
|
||||
the changes should be mentioned in `<changelog.md>`_.
|
||||
the changes should be mentioned in `the changelog
|
||||
<https://github.com/nim-lang/Nim/blob/devel/changelog.md>`_.
|
||||
|
||||
3. All changes introduced by the commit (diff lines) must be related to the
|
||||
subject of the commit.
|
||||
|
||||
@@ -295,8 +295,8 @@ The relationship of type to suffix is made by the proc ``complexName`` in the
|
||||
``compiler/docgen.nim`` file. Here are some examples of complex names for
|
||||
symbols in the `system module <system.html>`_.
|
||||
|
||||
* ``type SignedInt = int | int8 | int16 | int32 | int64`` **=>**
|
||||
`#SignedInt <system.html#SignedInt>`_
|
||||
* ``type SomeSignedInt = int | int8 | int16 | int32 | int64`` **=>**
|
||||
`#SomeSignedInt <system.html#SomeSignedInt>`_
|
||||
* ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>**
|
||||
`#globalRaiseHook <system.html#globalRaiseHook>`_
|
||||
* ``const NimVersion = "0.0.0"`` **=>**
|
||||
@@ -307,23 +307,25 @@ symbols in the `system module <system.html>`_.
|
||||
`#len,seq[T] <system.html#len,seq[T]>`_
|
||||
* ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>**
|
||||
`#pairs.i,seq[T] <system.html#pairs.i,seq[T]>`_
|
||||
* ``template newException[](exceptn: type; message: string): expr`` **=>**
|
||||
`#newException.t,type,string
|
||||
<system.html#newException.t,type,string>`_
|
||||
* ``template newException[](exceptn: typedesc; message: string;
|
||||
parentException: ref Exception = nil): untyped`` **=>**
|
||||
`#newException.t,typedesc,string,ref.Exception
|
||||
<system.html#newException.t,typedesc,string,ref.Exception>`_
|
||||
|
||||
|
||||
Index (idx) file format
|
||||
=======================
|
||||
|
||||
Files with the ``.idx`` extension are generated when you use the `Index
|
||||
switch`_ along with commands to generate documentation from source or text
|
||||
files. You can programatically generate indices with the `setIndexTerm()
|
||||
<rstgen.html#setIndexTerm>`_ and `writeIndexFile()
|
||||
<rstgen.html#writeIndexFile>`_ procs. The purpose of ``idx`` files is to hold
|
||||
the interesting symbols and their HTML references so they can be later
|
||||
concatenated into a big index file with `mergeIndexes()
|
||||
<rstgen.html#mergeIndexes>`_. This section documents the file format in
|
||||
detail.
|
||||
switch <#related-options-index-switch>`_ along with commands to generate
|
||||
documentation from source or text files. You can programatically generate
|
||||
indices with the `setIndexTerm()
|
||||
<rstgen.html#setIndexTerm,RstGenerator,string,string,string,string,string>`_
|
||||
and `writeIndexFile() <rstgen.html#writeIndexFile,RstGenerator,string>`_ procs.
|
||||
The purpose of ``idx`` files is to hold the interesting symbols and their HTML
|
||||
references so they can be later concatenated into a big index file with
|
||||
`mergeIndexes() <rstgen.html#mergeIndexes,string>`_. This section documents
|
||||
the file format in detail.
|
||||
|
||||
Index files are line oriented and tab separated (newline and tab characters
|
||||
have to be escaped). Each line represents a record with at least two fields,
|
||||
@@ -368,7 +370,7 @@ final index, and TOC entries found in ``.nim`` files are discarded.
|
||||
Additional resources
|
||||
====================
|
||||
|
||||
`Nim Compiler User Guide <nimc.html#command-line-switches>`_
|
||||
`Nim Compiler User Guide <nimc.html#compiler-usage-command-line-switches>`_
|
||||
|
||||
`RST Quick Reference
|
||||
<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
|
||||
|
||||
@@ -162,9 +162,10 @@ you can pass ``--gc:`` on the compile command with the choosed garbage collector
|
||||
- ``--gc:regions`` `Stack <https://en.wikipedia.org/wiki/Memory_management#Stack_allocation>`_ based garbage collector.
|
||||
- ``--gc:none`` No garbage collector.
|
||||
|
||||
The same Nim code can compile to use any of the garbage collectors,
|
||||
the Nim syntax mostly wont change from one garbage collector to another.
|
||||
No garbage collector is used for `JavaScript and NodeJS <https://nim-lang.github.io/Nim/backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||
`NimScript <https://nim-lang.github.io/Nim/nims.html>`_ target uses Nim VM garbage collector.
|
||||
The same Nim code can be compiled to use any of the garbage collectors;
|
||||
the Nim syntax generally will not change from one garbage collector to another.
|
||||
No garbage collector is used for `JavaScript and NodeJS
|
||||
<backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||
`NimScript <nims.html>`_ target uses Nim VM garbage collector.
|
||||
|
||||
If you are new to Nim and just starting, the default garbage collector is balanced to fit most common use cases.
|
||||
|
||||
@@ -54,53 +54,52 @@ identOrLiteral = generalizedLit | symbol | literal
|
||||
| castExpr
|
||||
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
||||
primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
| doBlocks
|
||||
primarySuffix = '(' (exprColonEqExpr comma?)* ')'
|
||||
| '.' optInd symbol generalizedLit?
|
||||
| '[' optInd indexExprList optPar ']'
|
||||
| '{' optInd indexExprList optPar '}'
|
||||
| '[' optInd exprColonEqExprList optPar ']'
|
||||
| '{' optInd exprColonEqExprList optPar '}'
|
||||
| &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
|
||||
condExpr = expr colcom expr optInd
|
||||
('elif' expr colcom expr optInd)*
|
||||
'else' colcom expr
|
||||
ifExpr = 'if' condExpr
|
||||
whenExpr = 'when' condExpr
|
||||
pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
identVis = symbol opr? # postfix position
|
||||
identVisDot = symbol '.' optInd symbol opr?
|
||||
pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
||||
identVis = symbol OPR? # postfix position
|
||||
identVisDot = symbol '.' optInd symbol OPR?
|
||||
identWithPragma = identVis pragma?
|
||||
identWithPragmaDot = identVisDot pragma?
|
||||
declColonEquals = identWithPragma (comma identWithPragma)* comma?
|
||||
(':' optInd typeDesc)? ('=' optInd expr)?
|
||||
identColonEquals = ident (comma ident)* comma?
|
||||
identColonEquals = IDENT (comma IDENT)* comma?
|
||||
(':' optInd typeDesc)? ('=' optInd expr)?)
|
||||
inlTupleDecl = 'tuple'
|
||||
[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
'[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
extTupleDecl = 'tuple'
|
||||
COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
tupleClass = 'tuple'
|
||||
paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
paramListArrow = paramList? ('->' optInd typeDesc)?
|
||||
paramListColon = paramList? (':' optInd typeDesc)?
|
||||
doBlock = 'do' paramListArrow pragmas? colcom stmt
|
||||
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
doBlock = 'do' paramListArrow pragma? colcom stmt
|
||||
procExpr = 'proc' paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
distinct = 'distinct' optInd typeDesc
|
||||
forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
||||
forExpr = forStmt
|
||||
expr = (blockExpr
|
||||
| ifExpr
|
||||
| whenExpr
|
||||
| caseExpr
|
||||
| forExpr
|
||||
| caseStmt
|
||||
| forExpr
|
||||
| tryExpr)
|
||||
/ simpleExpr
|
||||
typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple'
|
||||
| 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
|
||||
primary = typeKeyw typeDescK
|
||||
primary = typeKeyw optInd typeDesc
|
||||
/ prefixOperator* identOrLiteral primarySuffix*
|
||||
/ 'bind' primary
|
||||
typeDesc = simpleExpr
|
||||
typeDefAux = simpleExpr
|
||||
typeDesc = simpleExpr ('not' expr)?
|
||||
typeDefAux = simpleExpr ('not' expr)?
|
||||
| 'concept' typeClass
|
||||
postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
| IND{=} 'of' exprList ':' stmt
|
||||
@@ -110,14 +109,16 @@ postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
exprStmt = simpleExpr
|
||||
(( '=' optInd expr colonBody? )
|
||||
/ ( expr ^+ comma
|
||||
doBlocks
|
||||
/ macroColon
|
||||
postExprBlocks
|
||||
))?
|
||||
importStmt = 'import' optInd expr
|
||||
((comma expr)*
|
||||
/ 'except' optInd (expr ^+ comma))
|
||||
exportStmt = 'export' optInd expr
|
||||
((comma expr)*
|
||||
/ 'except' optInd (expr ^+ comma))
|
||||
includeStmt = 'include' optInd expr ^+ comma
|
||||
fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
|
||||
fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
returnStmt = 'return' optInd expr?
|
||||
raiseStmt = 'raise' optInd expr?
|
||||
yieldStmt = 'yield' optInd expr?
|
||||
@@ -157,9 +158,8 @@ indAndComment = (IND{>} COMMENT)? | COMMENT?
|
||||
routine = optInd identVis pattern? genericParamList?
|
||||
paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
|
||||
commentStmt = COMMENT
|
||||
section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
|
||||
constant = identWithPragma (colon typeDesc)? '=' optInd expr indAndComment
|
||||
enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
section(RULE) = COMMENT? RULE / (IND{>} (RULE / COMMENT)^+IND{=} DED)
|
||||
enum = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
objectWhen = 'when' expr colcom objectPart COMMENT?
|
||||
('elif' expr colcom objectPart COMMENT?)*
|
||||
('else' colcom objectPart COMMENT?)?
|
||||
@@ -177,10 +177,12 @@ typeClassParam = ('var' | 'out')? symbol
|
||||
typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||
&IND{>} stmt
|
||||
typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
|
||||
indAndComment? / identVisDot genericParamList? pragma '=' optInd typeDefAux
|
||||
indAndComment?
|
||||
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
colonBody = colcom stmt doBlocks?
|
||||
colonBody = colcom stmt postExprBlocks?
|
||||
variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||
constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
|
||||
bindStmt = 'bind' optInd qualifiedIdent ^+ comma
|
||||
mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
|
||||
pragmaStmt = pragma (':' COMMENT? stmt)?
|
||||
|
||||
@@ -124,9 +124,9 @@ separators!).
|
||||
|
||||
The typical usage scenario for this option is to call it after the
|
||||
user has typed the dot character for `the object oriented call
|
||||
syntax <tut2.html#method-call-syntax>`_. Idetools will try to return
|
||||
the suggestions sorted first by scope (from innermost to outermost)
|
||||
and then by item name.
|
||||
syntax <tut2.html#object-oriented-programming-method-call-syntax>`_.
|
||||
Idetools will try to return the suggestions sorted first by scope
|
||||
(from innermost to outermost) and then by item name.
|
||||
|
||||
|
||||
Invocation context
|
||||
@@ -359,7 +359,8 @@ defined, since at that point in the file the parser hasn't processed
|
||||
the full line yet. The signature will be returned complete in
|
||||
posterior instances of the method.
|
||||
|
||||
Methods imply `dynamic dispatch <tut2.html#dynamic-dispatch>`_ and
|
||||
Methods imply `dynamic dispatch
|
||||
<tut2.html#object-oriented-programming-dynamic-dispatch>`_ and
|
||||
idetools performs a static analysis on the code. For this reason
|
||||
idetools may not return the definition of the correct method you
|
||||
are querying because it may be impossible to know until the code
|
||||
|
||||
@@ -216,7 +216,7 @@ The solution is to **re-play** the module's top level statements.
|
||||
This solves the problem without having to special case the logic
|
||||
that fills the internal seqs which are affected by the pragmas.
|
||||
|
||||
In fact, this decribes how the AST should be stored in the database,
|
||||
In fact, this describes how the AST should be stored in the database,
|
||||
as a "shallow" tree. Let's assume we compile module ``m`` with the
|
||||
following contents:
|
||||
|
||||
@@ -667,3 +667,91 @@ important the hidden formal param is ``void*`` and not something more
|
||||
specialized. However the more specialized env type needs to passed to the
|
||||
backend somehow. We deal with this by modifying ``s.ast[paramPos]`` to contain
|
||||
the formal hidden parameter, but not ``s.typ``!
|
||||
|
||||
|
||||
Integer literals:
|
||||
-----------------
|
||||
|
||||
In Nim, there is a redundant way to specify the type of an
|
||||
integer literal. First of all, it should be unsurprising that every
|
||||
node has a node kind. The node of an integer literal can be any of the
|
||||
following values:
|
||||
|
||||
nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit,
|
||||
nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit
|
||||
|
||||
On top of that, there is also the `typ` field for the type. It the
|
||||
kind of the `typ` field can be one of the following ones, and it
|
||||
should be matching the literal kind:
|
||||
|
||||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, tyUInt, tyUInt8,
|
||||
tyUInt16, tyUInt32, tyUInt64
|
||||
|
||||
Then there is also the integer literal type. This is a specific type
|
||||
that is implicitly convertible into the requested type if the
|
||||
requested type can hold the value. For this to work, the type needs to
|
||||
know the concrete value of the literal. For example an expression
|
||||
`321` will be of type `int literal(321)`. This type is implicitly
|
||||
convertible to all integer types and ranges that contain the value
|
||||
`321`. That would be all builtin integer types except `uint8` and
|
||||
`int8` where `321` would be out of range. When this literal type is
|
||||
assigned to a new `var` or `let` variable, it's type will be resolved
|
||||
to just `int`, not `int literal(321)` unlike constants. A constant
|
||||
keeps the full `int literal(321)` type. Here is an example where that
|
||||
difference matters.
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc foo(arg: int8) =
|
||||
echo "def"
|
||||
|
||||
const tmp1 = 123
|
||||
foo(tmp1) # OK
|
||||
|
||||
let tmp2 = 123
|
||||
foo(tmp2) # Error
|
||||
|
||||
In a context with multiple overloads, the integer literal kind will
|
||||
always prefer the `int` type over all other types. If none of the
|
||||
overloads is of type `int`, then there will be an error because of
|
||||
ambiguity.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc foo(arg: int) =
|
||||
echo "abc"
|
||||
proc foo(arg: int8) =
|
||||
echo "def"
|
||||
foo(123) # output: abc
|
||||
|
||||
proc bar(arg: int16) =
|
||||
echo "abc"
|
||||
proc bar(arg: int8) =
|
||||
echo "def"
|
||||
|
||||
bar(123) # Error ambiguous call
|
||||
|
||||
In the compiler these integer literal types are represented with the
|
||||
node kind `nkIntLit`, type kind `tyInt` and the member `n` of the type
|
||||
pointing back to the integer literal node in the ast containing the
|
||||
integer value. These are the properties that hold true for integer
|
||||
literal types.
|
||||
|
||||
n.kind == nkIntLit
|
||||
n.typ.kind == tyInt
|
||||
n.typ.n == n
|
||||
|
||||
Other literal types, such as `uint literal(123)` that would
|
||||
automatically convert to other integer types, but prefers to
|
||||
become a `uint` are not part of the Nim language.
|
||||
|
||||
In an unchecked AST, the `typ` field is nil. The type checker will set
|
||||
the `typ` field accordingly to the node kind. Nodes of kind `nkIntLit`
|
||||
will get the integer literal type (e.g. `int literal(123)`). Nodes of
|
||||
kind `nkUIntLit` will get type `uint` (kind `tyUint`), etc.
|
||||
|
||||
This also means that it is not possible to write a literal in an
|
||||
unchecked AST that will after sem checking just be of type `int` and
|
||||
not implicitly convertible to other integer types. This only works for
|
||||
all integer types that are not `int`.
|
||||
|
||||
@@ -40,14 +40,15 @@ options:
|
||||
|
||||
After compilation is finished you will hopefully end up with the nim
|
||||
compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to
|
||||
your ``$PATH`` or use the `install command`_ to place it where it will be
|
||||
your ``$PATH`` or use the install command to place it where it will be
|
||||
found.
|
||||
|
||||
csource command
|
||||
---------------
|
||||
|
||||
The `csource`:idx: command builds the C sources for installation. It accepts
|
||||
the same options as you would pass to the `boot command`_.
|
||||
the same options as you would pass to the `boot command
|
||||
<#commands-boot-command>`_.
|
||||
|
||||
temp command
|
||||
------------
|
||||
@@ -55,7 +56,7 @@ temp command
|
||||
The temp command builds the Nim compiler but with a different final name
|
||||
(``nim_temp``), so it doesn't overwrite your normal compiler. You can use
|
||||
this command to test different options, the same you would issue for the `boot
|
||||
command`_.
|
||||
command <#commands-boot-command>`_.
|
||||
|
||||
test command
|
||||
------------
|
||||
|
||||
14
doc/lib.rst
14
doc/lib.rst
@@ -208,6 +208,7 @@ Generic Operating System Services
|
||||
Its primary purpose is to produce output for Nimble packages,
|
||||
but it also contains the widely used **Distribution** enum
|
||||
that is useful for writing platform specific code.
|
||||
See `packaging <packaging.html>`_ for hints on distributing Nim using OS packages.
|
||||
|
||||
* `dynlib <dynlib.html>`_
|
||||
This module implements the ability to access symbols from shared libraries.
|
||||
@@ -248,7 +249,7 @@ Math libraries
|
||||
|
||||
* `fenv <fenv.html>`_
|
||||
Floating-point environment. Handling of floating-point rounding and
|
||||
exceptions (overflow, zero-devide, etc.).
|
||||
exceptions (overflow, zero-divide, etc.).
|
||||
|
||||
* `math <math.html>`_
|
||||
Mathematical operations like cosine, square root.
|
||||
@@ -329,7 +330,7 @@ Threading
|
||||
---------
|
||||
|
||||
* `threadpool <threadpool.html>`_
|
||||
Implements Nim's `spawn <manual.html#parallel-amp-spawn>`_.
|
||||
Implements Nim's `spawn <manual_experimental.html#parallel-amp-spawn>`_.
|
||||
|
||||
|
||||
Parsers
|
||||
@@ -441,8 +442,7 @@ Miscellaneous
|
||||
browser.
|
||||
|
||||
* `colors <colors.html>`_
|
||||
This module implements color handling for Nim. It is used by
|
||||
the ``graphics`` module.
|
||||
This module implements color handling for Nim.
|
||||
|
||||
* `coro <coro.html>`_
|
||||
This module implements experimental coroutines in Nim.
|
||||
@@ -472,6 +472,9 @@ Modules for JS backend
|
||||
* `dom <dom.html>`_
|
||||
Declaration of the Document Object Model for the JS backend.
|
||||
|
||||
* `jsconsole <jsconsole.html>`_
|
||||
Wrapper for the ``console`` object.
|
||||
|
||||
* `jscore <jscore.html>`_
|
||||
Wrapper of core JavaScript functions. For most purposes you should be using
|
||||
the ``math``, ``json``, and ``times`` stdlib modules instead of this module.
|
||||
@@ -528,7 +531,8 @@ UNIX specific
|
||||
|
||||
* `posix <posix.html>`_
|
||||
Contains a wrapper for the POSIX standard.
|
||||
|
||||
* `posix_utils <posix_utils.html>`_
|
||||
Contains helpers for the POSIX standard or specialized for Linux and BSDs.
|
||||
|
||||
Regular expressions
|
||||
-------------------
|
||||
|
||||
154
doc/manual.rst
154
doc/manual.rst
@@ -142,7 +142,7 @@ It is mostly accurate to picture semantic analysis proceeding top to bottom and
|
||||
left to right in the source code, with compile-time code execution interleaved
|
||||
when necessary to compute values that are required for subsequent semantic
|
||||
analysis. We will see much later in this document that macro invocation not only
|
||||
requires this interleaving, but also creates a situation where semantic analyis
|
||||
requires this interleaving, but also creates a situation where semantic analysis
|
||||
does not entirely proceed top to bottom and left to right.
|
||||
|
||||
|
||||
@@ -552,6 +552,9 @@ following characters::
|
||||
@ $ ~ & % |
|
||||
! ? ^ . : \
|
||||
|
||||
(The grammar uses the terminal OPR to refer to operator symbols as
|
||||
defined here.)
|
||||
|
||||
These keywords are also operators:
|
||||
``and or not xor shl shr div mod in notin is isnot of``.
|
||||
|
||||
@@ -780,7 +783,7 @@ features supported at compile time (as detailed in the next section below).
|
||||
Within such a code block, it is possible to declare variables and then later
|
||||
read and update them, or declare variables and pass them to procedures that
|
||||
modify them. However, the code in such a block must still adhere to the
|
||||
retrictions listed above for referencing values and operations outside the
|
||||
restrictions listed above for referencing values and operations outside the
|
||||
block.
|
||||
|
||||
The ability to access and modify compile-time variables adds flexibility to
|
||||
@@ -1284,7 +1287,7 @@ A parameter ``A`` may be an *open array*, in which case it is indexed by
|
||||
integers from 0 to ``len(A)-1``. An array expression may be constructed by the
|
||||
array constructor ``[]``. The element type of this array expression is
|
||||
inferred from the type of the first element. All other elements need to be
|
||||
implicitly convertable to this type.
|
||||
implicitly convertible to this type.
|
||||
|
||||
Sequences are similar to arrays but of dynamic length which may change
|
||||
during runtime (like strings). Sequences are implemented as growable arrays,
|
||||
@@ -1479,7 +1482,8 @@ order. The *names* of the fields also have to be identical.
|
||||
|
||||
The assignment operator for tuples copies each component.
|
||||
The default assignment operator for objects copies each component. Overloading
|
||||
of the assignment operator is described in `type-bound-operations-operator`_.
|
||||
of the assignment operator is described `here
|
||||
<manual_experimental.html#type-bound-operations>`_.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
@@ -1640,7 +1644,7 @@ object branch, the initialization is considered valid. This analysis only works
|
||||
for immutable discriminators of an ordinal type and disregards ``elif``
|
||||
branches. For discriminator values with a ``range`` type, the compiler
|
||||
checks if the entire range of possible values for the discriminator value is
|
||||
valid for the choosen object branch.
|
||||
valid for the chosen object branch.
|
||||
|
||||
A small example:
|
||||
|
||||
@@ -1786,7 +1790,7 @@ Mixing GC'ed memory with ``ptr``
|
||||
|
||||
Special care has to be taken if an untraced object contains traced objects like
|
||||
traced references, strings or sequences: in order to free everything properly,
|
||||
the built-in procedure ``GCunref`` has to be called before freeing the untraced
|
||||
the built-in procedure ``reset`` has to be called before freeing the untraced
|
||||
memory manually:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -1800,12 +1804,12 @@ memory manually:
|
||||
d.s = "abc"
|
||||
|
||||
# tell the GC that the string is not needed anymore:
|
||||
GCunref(d.s)
|
||||
reset(d.s)
|
||||
|
||||
# free the memory:
|
||||
dealloc(d)
|
||||
|
||||
Without the ``GCunref`` call the memory allocated for the ``d.s`` string would
|
||||
Without the ``reset`` call the memory allocated for the ``d.s`` string would
|
||||
never be freed. The example also demonstrates two important features for low
|
||||
level programming: the ``sizeof`` proc returns the size of a type or value
|
||||
in bytes. The ``cast`` operator can circumvent the type system: the compiler
|
||||
@@ -2129,7 +2133,7 @@ conversions from ``string`` to ``SQL`` are allowed:
|
||||
Now we have compile-time checking against SQL injection attacks. Since
|
||||
``"".SQL`` is transformed to ``SQL("")`` no new syntax is needed for nice
|
||||
looking ``SQL`` string literals. The hypothetical ``SQL`` type actually
|
||||
exists in the library as the `TSqlQuery type <db_sqlite.html#TSqlQuery>`_ of
|
||||
exists in the library as the `SqlQuery type <db_common.html#SqlQuery>`_ of
|
||||
modules like `db_sqlite <db_sqlite.html>`_.
|
||||
|
||||
|
||||
@@ -2346,7 +2350,7 @@ The convertible relation can be relaxed by a user-defined type
|
||||
# implicit conversion magic happens here
|
||||
x = chr
|
||||
echo x # => 97
|
||||
# you can use the explicit form too
|
||||
# one can use the explicit form too
|
||||
x = chr.toInt
|
||||
echo x # => 97
|
||||
|
||||
@@ -2640,7 +2644,7 @@ tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
||||
(analogous for objects)
|
||||
array[0..., T] [default(T), ...]
|
||||
range[T] default(T); this may be out of the valid range
|
||||
T = enum cast[T](0); this may be an invalid value
|
||||
T = enum cast[T]\(0); this may be an invalid value
|
||||
============================ ==============================================
|
||||
|
||||
|
||||
@@ -3184,6 +3188,7 @@ has lots of advantages:
|
||||
|
||||
Type conversions
|
||||
----------------
|
||||
|
||||
Syntactically a `type conversion` is like a procedure call, but a
|
||||
type name replaces the procedure name. A type conversion is always
|
||||
safe in the sense that a failure to convert a type to another
|
||||
@@ -3203,6 +3208,19 @@ A type conversion can also be used to disambiguate overloaded routines:
|
||||
let procVar = (proc(x: string))(p)
|
||||
procVar("a")
|
||||
|
||||
Since operations on unsigned numbers wrap around and are unchecked so are
|
||||
type conversion to unsigned integers and between unsigned integers. The
|
||||
rationale for this is mostly better interoperability with the C Programming
|
||||
language when algorithms are ported from C to Nim.
|
||||
|
||||
Exception: Values that are converted to an unsigned type at compile time
|
||||
are checked so that code like ``byte(-1)`` does not compile.
|
||||
|
||||
**Note**: Historically the operations
|
||||
were unchecked and the conversions were sometimes checked but starting with
|
||||
the revision 1.0.4 of this document and the language implementation the
|
||||
conversions too are now *always unchecked*.
|
||||
|
||||
|
||||
Type casts
|
||||
----------
|
||||
@@ -3422,14 +3440,14 @@ different; for this a special setter syntax is needed:
|
||||
## setter of hostAddr.
|
||||
## This accesses the 'host' field and is not a recursive call to
|
||||
## ``host=`` because the builtin dot access is preferred if it is
|
||||
## avaliable:
|
||||
## available:
|
||||
s.host = value
|
||||
|
||||
proc host*(s: Socket): int {.inline.} =
|
||||
## getter of hostAddr
|
||||
## This accesses the 'host' field and is not a recursive call to
|
||||
## ``host`` because the builtin dot access is preferred if it is
|
||||
## avaliable:
|
||||
## available:
|
||||
s.host
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -3481,8 +3499,8 @@ more argument in this case:
|
||||
assert x == y
|
||||
|
||||
The command invocation syntax also can't have complex expressions as arguments.
|
||||
For example: (`anonymous procs`_), ``if``, ``case`` or ``try``.
|
||||
Function calls with no arguments still needs () to
|
||||
For example: (`anonymous procs <#procedures-anonymous-procs>`_), ``if``,
|
||||
``case`` or ``try``. Function calls with no arguments still needs () to
|
||||
distinguish between a call and the function itself as a first class value.
|
||||
|
||||
|
||||
@@ -3502,8 +3520,8 @@ Creating closures in loops
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since closures capture local variables by reference it is often not wanted
|
||||
behavior inside loop bodies. See `closureScope <system.html#closureScope>`_
|
||||
for details on how to change this behavior.
|
||||
behavior inside loop bodies. See `closureScope
|
||||
<system.html#closureScope.t,untyped>`_ for details on how to change this behavior.
|
||||
|
||||
Anonymous Procs
|
||||
---------------
|
||||
@@ -3661,7 +3679,7 @@ a syntax like:
|
||||
proc foo(other: Y; container: var X): var T from container
|
||||
|
||||
Here ``var T from container`` explicitly exposes that the
|
||||
location is deviated from the second parameter (called
|
||||
location is derived from the second parameter (called
|
||||
'container' in this case). The syntax ``var T from p`` specifies a type
|
||||
``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``.
|
||||
|
||||
@@ -3796,7 +3814,7 @@ as there are components in the tuple. The i'th iteration variable's type is
|
||||
the type of the i'th component. In other words, implicit tuple unpacking in a
|
||||
for loop context is supported.
|
||||
|
||||
Implict items/pairs invocations
|
||||
Implicit items/pairs invocations
|
||||
-------------------------------
|
||||
|
||||
If the for loop expression ``e`` does not denote an iterator and the for loop
|
||||
@@ -4111,6 +4129,23 @@ error message from ``e``, and for such situations it is enough to use
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
Custom exceptions
|
||||
-----------------
|
||||
|
||||
Is it possible to create custom exceptions. These make it easy to distinguish between exceptions raised by nim and those from your own code.
|
||||
|
||||
A custom exception is a custom type:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
LoadError* = object of Exception
|
||||
|
||||
Ending the custom exception's name with ``Error`` is recommended.
|
||||
|
||||
Custom exceptions can be raised like any others, e.g.:
|
||||
|
||||
.. code-block:: nim
|
||||
raise newException(LoadError, "Failed to load data")
|
||||
|
||||
Defer statement
|
||||
---------------
|
||||
@@ -4458,8 +4493,8 @@ more complex type classes:
|
||||
|
||||
Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data
|
||||
types in ML-like languages, it should be understood that type classes are static
|
||||
constraints to be enforced at type instantations. Type classes are not really
|
||||
types in themsleves, but are instead a system of providing generic "checks" that
|
||||
constraints to be enforced at type instantiations. Type classes are not really
|
||||
types in themselves, but are instead a system of providing generic "checks" that
|
||||
ultimately *resolve* to some singular type. Type classes do not allow for
|
||||
runtime type dynamism, unlike object variants or methods.
|
||||
|
||||
@@ -4621,7 +4656,7 @@ instantiation. The following is not allowed:
|
||||
# not valid: 'T' is not inferred to be of type 'var int'
|
||||
g(v, i)
|
||||
|
||||
# also not allowed: explict instantiation via 'var int'
|
||||
# also not allowed: explicit instantiation via 'var int'
|
||||
g[var int](v, i)
|
||||
|
||||
|
||||
@@ -4777,7 +4812,7 @@ compiler. Explicit immediate templates are now deprecated.
|
||||
Passing a code block to a template
|
||||
----------------------------------
|
||||
|
||||
You can pass a block of statements as the last argument to a template
|
||||
One can pass a block of statements as the last argument to a template
|
||||
following the special ``:`` syntax:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -5092,7 +5127,7 @@ tree (AST) of the code that is passed to it. The macro can then do
|
||||
transformations on it and return the transformed AST. This can be used to
|
||||
add custom language features and implement `domain specific languages`:idx:.
|
||||
|
||||
Macro invocation is a case where semantic analyis does **not** entirely proceed
|
||||
Macro invocation is a case where semantic analysis does **not** entirely proceed
|
||||
top to bottom and left to right. Instead, semantic analysis happens at least
|
||||
twice:
|
||||
|
||||
@@ -5364,7 +5399,7 @@ generic type ``static[T]``. The type param can be omitted to obtain the type
|
||||
class of all constant expressions. A more specific type class can be created by
|
||||
instantiating ``static`` with another type class.
|
||||
|
||||
You can force an expression to be evaluated at compile time as a constant
|
||||
One can force an expression to be evaluated at compile time as a constant
|
||||
expression by coercing it to a corresponding ``static`` type:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -5372,20 +5407,20 @@ expression by coercing it to a corresponding ``static`` type:
|
||||
|
||||
echo static(fac(5)), " ", static[bool](16.isPowerOfTwo)
|
||||
|
||||
The complier will report any failure to evaluate the expression or a
|
||||
The compiler will report any failure to evaluate the expression or a
|
||||
possible type mismatch error.
|
||||
|
||||
typedesc[T]
|
||||
-----------
|
||||
|
||||
In many contexts, Nim allows you to treat the names of types as regular
|
||||
In many contexts, Nim allows to treat the names of types as regular
|
||||
values. These values exists only during the compilation phase, but since
|
||||
all values must have a type, ``typedesc`` is considered their special type.
|
||||
|
||||
``typedesc`` acts like a generic type. For instance, the type of the symbol
|
||||
``int`` is ``typedesc[int]``. Just like with regular generic types, when the
|
||||
generic param is ommited, ``typedesc`` denotes the type class of all types.
|
||||
As a syntactic convenience, you can also use ``typedesc`` as a modifier.
|
||||
generic param is omitted, ``typedesc`` denotes the type class of all types.
|
||||
As a syntactic convenience, one can also use ``typedesc`` as a modifier.
|
||||
|
||||
Procs featuring ``typedesc`` params are considered implicitly generic.
|
||||
They will be instantiated for each unique combination of supplied types
|
||||
@@ -5463,7 +5498,7 @@ typeof operator
|
||||
**Note**: ``typeof(x)`` can for historical reasons also be written as
|
||||
``type(x)`` but ``type(x)`` is discouraged.
|
||||
|
||||
You can obtain the type of a given expression by constructing a ``typeof``
|
||||
One can obtain the type of a given expression by constructing a ``typeof``
|
||||
value from it (in many other languages this is known as the `typeof`:idx:
|
||||
operator):
|
||||
|
||||
@@ -5676,9 +5711,9 @@ modules don't need to import a module's dependencies:
|
||||
echo $x
|
||||
|
||||
When the exported symbol is another module, all of its definitions will
|
||||
be forwarded. You can use an ``except`` list to exclude some of the symbols.
|
||||
be forwarded. One can use an ``except`` list to exclude some of the symbols.
|
||||
|
||||
Notice that when exporting, you need to specify only the module name:
|
||||
Notice that when exporting, one needs to specify only the module name:
|
||||
|
||||
.. code-block:: nim
|
||||
import foo/bar/baz
|
||||
@@ -5892,9 +5927,9 @@ or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
|
||||
As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
|
||||
pretends to be free of side effects, so that it can be used for debugging
|
||||
routines marked as ``noSideEffect``.
|
||||
As a special semantic rule, the built-in `debugEcho
|
||||
<system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects,
|
||||
so that it can be used for debugging routines marked as ``noSideEffect``.
|
||||
|
||||
``func`` is syntactic sugar for a proc with no side effects:
|
||||
|
||||
@@ -6165,7 +6200,8 @@ factor.
|
||||
immediate pragma
|
||||
----------------
|
||||
|
||||
The immediate pragma is obsolete. See `Typed vs untyped parameters`_.
|
||||
The immediate pragma is obsolete. See `Typed vs untyped parameters
|
||||
<#templates-typed-vs-untyped-parameters>`_.
|
||||
|
||||
|
||||
compilation option pragmas
|
||||
@@ -6347,12 +6383,18 @@ is uncertain (it may be removed any time).
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
import threadpool
|
||||
{.experimental: "parallel".}
|
||||
|
||||
proc threadedEcho(s: string, i: int) =
|
||||
echo(s, " ", $i)
|
||||
|
||||
proc useParallel() =
|
||||
parallel:
|
||||
for i in 0..4:
|
||||
echo "echo in parallel"
|
||||
spawn threadedEcho("echo in parallel", i)
|
||||
|
||||
useParallel()
|
||||
|
||||
|
||||
As a top level statement, the experimental pragma enables a feature for the
|
||||
@@ -6441,7 +6483,7 @@ and instead the generated code should contain an ``#include``:
|
||||
PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
|
||||
# import C's FILE* type; Nim will treat it as a new pointer type
|
||||
|
||||
The ``header`` pragma always expects a string constant. The string contant
|
||||
The ``header`` pragma always expects a string constant. The string constant
|
||||
contains the header file: As usual for C, a system header file is enclosed
|
||||
in angle brackets: ``<>``. If no angle brackets are given, Nim
|
||||
encloses the header file in ``""`` in the generated C code.
|
||||
@@ -6469,7 +6511,7 @@ with the project:
|
||||
{.compile: "myfile.cpp".}
|
||||
|
||||
**Note**: Nim computes a SHA1 checksum and only recompiles the file if it
|
||||
has changed. You can use the ``-f`` command line option to force recompilation
|
||||
has changed. One can use the ``-f`` command line option to force recompilation
|
||||
of the file.
|
||||
|
||||
|
||||
@@ -6489,7 +6531,7 @@ compiler like you would using the commandline switch ``--passC``:
|
||||
.. code-block:: Nim
|
||||
{.passC: "-Wall -Werror".}
|
||||
|
||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||
Note that one can use ``gorge`` from the `system module <system.html>`_ to
|
||||
embed parameters from an external command that will be executed
|
||||
during semantic analysis:
|
||||
|
||||
@@ -6499,12 +6541,12 @@ during semantic analysis:
|
||||
PassL pragma
|
||||
------------
|
||||
The ``passL`` pragma can be used to pass additional parameters to the linker
|
||||
like you would using the commandline switch ``--passL``:
|
||||
like one would using the commandline switch ``--passL``:
|
||||
|
||||
.. code-block:: Nim
|
||||
{.passL: "-lSDLmain -lSDL".}
|
||||
|
||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||
Note that one can use ``gorge`` from the `system module <system.html>`_ to
|
||||
embed parameters from an external command that will be executed
|
||||
during semantic analysis:
|
||||
|
||||
@@ -6616,15 +6658,6 @@ The compiler needs to be told to generate C++ (command ``cpp``) for
|
||||
this to work. The conditional symbol ``cpp`` is defined when the compiler
|
||||
emits C++ code.
|
||||
|
||||
|
||||
ImportJs pragma
|
||||
---------------
|
||||
|
||||
Similar to the `importcpp pragma for C++ <#foreign-function-interface-importc-pragma>`_,
|
||||
the ``importjs`` pragma can be used to import Javascript methods or
|
||||
symbols in general. The generated code then uses the Javascript method
|
||||
calling syntax: ``obj.method(arg)``.
|
||||
|
||||
Namespaces
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -6768,7 +6801,7 @@ Importcpp for objects
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Generic ``importcpp``'ed objects are mapped to C++ templates. This means that
|
||||
you can import C++'s templates rather easily without the need for a pattern
|
||||
one can import C++'s templates rather easily without the need for a pattern
|
||||
language for object types:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -6807,6 +6840,15 @@ Produces:
|
||||
std::vector<int>::iterator x;
|
||||
|
||||
|
||||
ImportJs pragma
|
||||
---------------
|
||||
|
||||
Similar to the `importcpp pragma for C++ <#foreign-function-interface-importc-pragma>`_,
|
||||
the ``importjs`` pragma can be used to import Javascript methods or
|
||||
symbols in general. The generated code then uses the Javascript method
|
||||
calling syntax: ``obj.method(arg)``.
|
||||
|
||||
|
||||
ImportObjC pragma
|
||||
-----------------
|
||||
Similar to the `importc pragma for C
|
||||
@@ -6980,9 +7022,9 @@ specified. It is possible to annotate procs, templates, type and variable
|
||||
definitions, statements, etc.
|
||||
|
||||
Macros module includes helpers which can be used to simplify custom pragma
|
||||
access `hasCustomPragma`, `getCustomPragmaVal`. Please consult macros module
|
||||
documentation for details. These macros are no magic, they don't do anything
|
||||
you cannot do yourself by walking AST object representation.
|
||||
access `hasCustomPragma`, `getCustomPragmaVal`. Please consult the macros module
|
||||
documentation for details. These macros are not magic, everything they do can
|
||||
also be achieved by walking the AST of the object representation.
|
||||
|
||||
More examples with custom pragmas:
|
||||
|
||||
@@ -7029,7 +7071,7 @@ is not set to C, other pragmas are available:
|
||||
|
||||
* `importcpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_
|
||||
* `importobjc <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
|
||||
* `importjs <manul.html#implementation-specific-pragmas-importjs-pragma>`_
|
||||
* `importjs <manual.html#implementation-specific-pragmas-importjs-pragma>`_
|
||||
|
||||
.. code-block:: Nim
|
||||
proc p(s: cstring) {.importc: "prefix$1".}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
Memory safety for returning by ``var T`` is ensured by a simple borrowing
|
||||
rule: If ``result`` does not refer to a location pointing to the heap
|
||||
(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access)
|
||||
then it has to be deviated by the routine's first parameter:
|
||||
then it has to be derived from the routine's first parameter:
|
||||
|
||||
.. code-block:: nim
|
||||
proc forward[T](x: var T): var T =
|
||||
result = x # ok, deviated from the first parameter.
|
||||
result = x # ok, derived from the first parameter.
|
||||
|
||||
proc p(param: var int): var int =
|
||||
var x: int
|
||||
# we know 'forward' provides a view into the location deviated by
|
||||
# we know 'forward' provides a view into the location derived from
|
||||
# its first argument 'x'.
|
||||
result = forward(x) # Error: location is derived from ``x``
|
||||
# which is not p's first parameter and lives
|
||||
|
||||
@@ -27,7 +27,7 @@ Package level objects
|
||||
Every Nim module resides in a (nimble) package. An object type can be attached
|
||||
to the package it resides in. If that is done, the type can be referenced from
|
||||
other modules as an `incomplete`:idx: object type. This feature allows to
|
||||
break up recursive type dependencies accross module boundaries. Incomplete
|
||||
break up recursive type dependencies across module boundaries. Incomplete
|
||||
object types are always passed ``byref`` and can only be used in pointer like
|
||||
contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does
|
||||
not yet know the size of the object. To complete an incomplete object
|
||||
@@ -203,9 +203,10 @@ useful only when interfacing with imported types having such semantics.
|
||||
Automatic dereferencing
|
||||
=======================
|
||||
|
||||
If the `experimental mode <#pragmas-experimental-pragma>`_ is active and no other match
|
||||
is found, the first argument ``a`` is dereferenced automatically if it's a
|
||||
pointer type and overloading resolution is tried with ``a[]`` instead.
|
||||
If the `experimental mode <manual.html#pragmas-experimental-pragma>`_ is active
|
||||
and no other match is found, the first argument ``a`` is dereferenced
|
||||
automatically if it's a pointer type and overloading resolution is tried
|
||||
with ``a[]`` instead.
|
||||
|
||||
|
||||
Automatic self insertions
|
||||
@@ -266,7 +267,7 @@ calls can use the ``do`` keyword:
|
||||
``do`` is written after the parentheses enclosing the regular proc params.
|
||||
The proc expression represented by the do block is appended to them.
|
||||
In calls using the command syntax, the do block will bind to the immediately
|
||||
preceeding expression, transforming it in a call.
|
||||
preceding expression, transforming it in a call.
|
||||
|
||||
``do`` with parentheses is an anonymous ``proc``; however a ``do`` without
|
||||
parentheses is just a block of code. The ``do`` notation can be used to
|
||||
@@ -814,7 +815,7 @@ This mechanism will be used by most data structures that support shared memory
|
||||
like channels to implement thread safe automatic memory management.
|
||||
|
||||
The builtin ``deepCopy`` can even clone closures and their environments. See
|
||||
the documentation of `spawn`_ for details.
|
||||
the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details.
|
||||
|
||||
|
||||
Case statement macros
|
||||
@@ -1617,7 +1618,7 @@ Aliasing restrictions in parameter passing
|
||||
==========================================
|
||||
|
||||
**Note**: The aliasing restrictions are currently not enforced by the
|
||||
implementation and need to be fleshed out futher.
|
||||
implementation and need to be fleshed out further.
|
||||
|
||||
"Aliasing" here means that the underlying storage locations overlap in memory
|
||||
at runtime. An "output parameter" is a parameter of type ``var T``, an input
|
||||
|
||||
21
doc/nimc.rst
21
doc/nimc.rst
@@ -114,7 +114,8 @@ Level Description
|
||||
===== ============================================
|
||||
0 Minimal output level for the compiler.
|
||||
1 Displays compilation of all the compiled files, including those imported
|
||||
by other modules or through the `compile pragma<#compile-pragma>`_.
|
||||
by other modules or through the `compile pragma
|
||||
<manual.html#implementation-specific-pragmas-compile-pragma>`_.
|
||||
This is the default level.
|
||||
2 Displays compilation statistics, enumerates the dynamic
|
||||
libraries that will be loaded by the final binary and dumps to
|
||||
@@ -130,9 +131,10 @@ Compile time symbols
|
||||
|
||||
Through the ``-d:x`` or ``--define:x`` switch you can define compile time
|
||||
symbols for conditional compilation. The defined switches can be checked in
|
||||
source code with the `when statement <manual.html#when-statement>`_ and
|
||||
`defined proc <system.html#defined>`_. The typical use of this switch is to
|
||||
enable builds in release mode (``-d:release``) where optimizations are
|
||||
source code with the `when statement
|
||||
<manual.html#statements-and-expressions-when-statement>`_ and
|
||||
`defined proc <system.html#defined,untyped>`_. The typical use of this switch is
|
||||
to enable builds in release mode (``-d:release``) where optimizations are
|
||||
enabled for better performance. Another common use is the ``-d:ssl`` switch to
|
||||
activate SSL sockets.
|
||||
|
||||
@@ -215,7 +217,7 @@ The ``_r`` suffix is used for release builds, ``_d`` is for debug builds.
|
||||
This makes it easy to delete all generated files.
|
||||
|
||||
The ``--nimcache``
|
||||
`compiler switch <nimc.html#command-line-switches>`_ can be used to
|
||||
`compiler switch <#compiler-usage-command-line-switches>`_ can be used to
|
||||
to change the ``nimcache`` directory.
|
||||
|
||||
However, the generated C code is not platform independent. C code generated for
|
||||
@@ -483,7 +485,6 @@ number information are given if the program crashes or an uncaught exception
|
||||
is raised.
|
||||
|
||||
|
||||
|
||||
DynlibOverride
|
||||
==============
|
||||
|
||||
@@ -497,14 +498,6 @@ on Linux::
|
||||
nim c --dynlibOverride:lua --passL:liblua.lib program.nim
|
||||
|
||||
|
||||
Cursor pragma
|
||||
=============
|
||||
|
||||
The ``.cursor`` pragma is a temporary tool for optimization purposes
|
||||
and this property will be computed by Nim's optimizer eventually. Thus it
|
||||
remains undocumented.
|
||||
|
||||
|
||||
Backend language options
|
||||
========================
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ completion symbols at some point in the file.
|
||||
|
||||
The typical usage scenario for this option is to call it after the
|
||||
user has typed the dot character for `the object oriented call
|
||||
syntax <tut2.html#method-call-syntax>`_. Nimsuggest will try to return
|
||||
the suggestions sorted first by scope (from innermost to outermost)
|
||||
and then by item name.
|
||||
syntax <tut2.html#object-oriented-programming-method-call-syntax>`_.
|
||||
Nimsuggest will try to return the suggestions sorted first by scope
|
||||
(from innermost to outermost) and then by item name.
|
||||
|
||||
|
||||
Invocation context
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Packaging Nim
|
||||
=============
|
||||
|
||||
This page provide hints on distributing Nim using OS packages.
|
||||
|
||||
See `distros <distros.html>`_ for tools to detect Linux distribution at runtime.
|
||||
|
||||
Supported architectures
|
||||
-----------------------
|
||||
|
||||
@@ -83,4 +83,4 @@ Note how the set turns enum values into powers of 2.
|
||||
If using enums and sets with C, use distinct cint.
|
||||
|
||||
For interoperability with C see also the
|
||||
`bitsize pragma <#implementation-specific-pragmas-bitsize-pragma>`_.
|
||||
`bitsize pragma <manual.html#implementation-specific-pragmas-bitsize-pragma>`_.
|
||||
|
||||
@@ -20,7 +20,7 @@ The standard distribution ships with the following tools:
|
||||
- | `C2nim <https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst>`_
|
||||
| C to Nim source converter. Translates C header files to Nim.
|
||||
|
||||
- | `niminst <https://nim-lang.org/docs/niminst.html>`_
|
||||
- | `niminst <niminst.html>`_
|
||||
| niminst is a tool to generate an installer for a Nim program.
|
||||
|
||||
- | `nimgrep <nimgrep.html>`_
|
||||
@@ -29,3 +29,11 @@ The standard distribution ships with the following tools:
|
||||
- | nimpretty
|
||||
| ``nimpretty`` is a Nim source code beautifier,
|
||||
to format code according to the official style guide.
|
||||
|
||||
- | testament
|
||||
| ``testament`` is an advanced automatic *unittests runner* for Nim tests,
|
||||
is used for the development of Nim itself, offers process isolation for your tests,
|
||||
it can generate statistics about test cases, supports multiple targets (C, JS, etc),
|
||||
`simulated Dry-Runs <https://en.wikipedia.org/wiki/Dry_run_(testing)>`_,
|
||||
has logging, can generate HTML reports, skip tests from a file and more,
|
||||
so can be useful to run your tests, even the most complex ones.
|
||||
|
||||
107
doc/tut1.rst
107
doc/tut1.rst
@@ -67,8 +67,8 @@ done with spaces only, tabulators are not allowed.
|
||||
|
||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||
a new variable named ``name`` of type ``string`` with the value that is
|
||||
returned by the `readLine <system.html#readLine,File>`_ procedure. Since the
|
||||
compiler knows that `readLine <system.html#readLine,File>`_ returns a string,
|
||||
returned by the `readLine <io.html#readLine,File>`_ procedure. Since the
|
||||
compiler knows that `readLine <io.html#readLine,File>`_ returns a string,
|
||||
you can leave out the type in the declaration (this is called `local type
|
||||
inference`:idx:). So this will work too:
|
||||
|
||||
@@ -80,7 +80,7 @@ Note that this is basically the only form of type inference that exists in
|
||||
Nim: it is a good compromise between brevity and readability.
|
||||
|
||||
The "hello world" program contains several identifiers that are already known
|
||||
to the compiler: ``echo``, `readLine <system.html#readLine,File>`_, etc.
|
||||
to the compiler: ``echo``, `readLine <io.html#readLine,File>`_, etc.
|
||||
These built-ins are declared in the system_ module which is implicitly
|
||||
imported by any other module.
|
||||
|
||||
@@ -326,10 +326,11 @@ the compiler that for every other value nothing should be done:
|
||||
of 3, 8: echo "The number is 3 or 8"
|
||||
else: discard
|
||||
|
||||
The empty `discard statement`_ is a *do nothing* statement. The compiler knows
|
||||
that a case statement with an else part cannot fail and thus the error
|
||||
disappears. Note that it is impossible to cover all possible string values:
|
||||
that is why string cases always need an ``else`` branch.
|
||||
The empty `discard statement <#procedures-discard-statement>`_ is a *do
|
||||
nothing* statement. The compiler knows that a case statement with an else part
|
||||
cannot fail and thus the error disappears. Note that it is impossible to cover
|
||||
all possible string values: that is why string cases always need an ``else``
|
||||
branch.
|
||||
|
||||
In general the case statement is used for subrange types or enumerations where
|
||||
it is of great help that the compiler checks that you covered any possible
|
||||
@@ -359,8 +360,8 @@ For statement
|
||||
-------------
|
||||
|
||||
The ``for`` statement is a construct to loop over any element an *iterator*
|
||||
provides. The example uses the built-in `countup <system.html#countup>`_
|
||||
iterator:
|
||||
provides. The example uses the built-in `countup
|
||||
<system.html#countup.i,T,T,Positive>`_ iterator:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -371,8 +372,8 @@ iterator:
|
||||
|
||||
The variable ``i`` is implicitly declared by the
|
||||
``for`` loop and has the type ``int``, because that is what `countup
|
||||
<system.html#countup>`_ returns. ``i`` runs through the values 1, 2, .., 10.
|
||||
Each value is ``echo``-ed. This code does the same:
|
||||
<system.html#countup.i,T,T,Positive>`_ returns. ``i`` runs through the values
|
||||
1, 2, .., 10. Each value is ``echo``-ed. This code does the same:
|
||||
|
||||
.. code-block:: nim
|
||||
echo "Counting to 10: "
|
||||
@@ -391,7 +392,7 @@ Counting down can be achieved as easily (but is less often needed):
|
||||
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
|
||||
|
||||
Since counting up occurs so often in programs, Nim also has a `..
|
||||
<system.html#...i,S,T>`_ iterator that does the same:
|
||||
<system.html#...i,T,T>`_ iterator that does the same:
|
||||
|
||||
.. code-block:: nim
|
||||
for i in 1..10:
|
||||
@@ -570,10 +571,10 @@ an expression is allowed:
|
||||
Procedures
|
||||
==========
|
||||
|
||||
To define new commands like `echo <system.html#echo>`_ and `readLine
|
||||
<system.html#readLine,File>`_ in the examples, the concept of a `procedure`
|
||||
is needed. (Some languages call them *methods* or *functions*.) In Nim new
|
||||
procedures are defined with the ``proc`` keyword:
|
||||
To define new commands like `echo <system.html#echo,varargs[typed,]>`_
|
||||
and `readLine <io.html#readLine,File>`_ in the examples, the concept of a
|
||||
`procedure` is needed. (Some languages call them *methods* or *functions*.)
|
||||
In Nim new procedures are defined with the ``proc`` keyword:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -644,7 +645,7 @@ is possible, and actually an idiom:
|
||||
:test: "nim c $1"
|
||||
proc printSeq(s: seq, nprinted: int = -1) =
|
||||
var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
|
||||
for i in 0 .. <nprinted:
|
||||
for i in 0 ..< nprinted:
|
||||
echo s[i]
|
||||
|
||||
If the procedure needs to modify the argument for the
|
||||
@@ -688,9 +689,6 @@ been declared with the ``discardable`` pragma:
|
||||
|
||||
p(3, 4) # now valid
|
||||
|
||||
The ``discard`` statement can also be used to create block comments as
|
||||
described in the `Comments`_ section.
|
||||
|
||||
|
||||
Named arguments
|
||||
---------------
|
||||
@@ -745,15 +743,21 @@ Overloaded procedures
|
||||
Nim provides the ability to overload procedures similar to C++:
|
||||
|
||||
.. code-block:: nim
|
||||
proc toString(x: int): string = ...
|
||||
proc toString(x: int): string =
|
||||
result =
|
||||
if x < 0: "negative"
|
||||
elif x > 0: "positive"
|
||||
else: "zero"
|
||||
|
||||
proc toString(x: bool): string =
|
||||
if x: result = "true"
|
||||
else: result = "false"
|
||||
result =
|
||||
if x: "yep"
|
||||
else: "nope"
|
||||
|
||||
echo toString(13) # calls the toString(x: int) proc
|
||||
echo toString(true) # calls the toString(x: bool) proc
|
||||
assert toString(13) == "positive" # calls the toString(x: int) proc
|
||||
assert toString(true) == "yep" # calls the toString(x: bool) proc
|
||||
|
||||
(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
|
||||
(Note that ``toString`` is usually the `$ <dollars.html>`_ operator in
|
||||
Nim.) The compiler chooses the most appropriate proc for the ``toString``
|
||||
calls. How this overloading resolution algorithm works exactly is not
|
||||
discussed here (it will be specified in the manual soon). However, it does
|
||||
@@ -845,8 +849,8 @@ Let's return to the simple counting example:
|
||||
for i in countup(1, 10):
|
||||
echo i
|
||||
|
||||
Can a `countup <system.html#countup>`_ proc be written that supports this
|
||||
loop? Lets try:
|
||||
Can a `countup <system.html#countup.i,T,T,Positive>`_ proc be written that
|
||||
supports this loop? Lets try:
|
||||
|
||||
.. code-block:: nim
|
||||
proc countup(a, b: int): int =
|
||||
@@ -1010,8 +1014,8 @@ floats and follow the IEEE-754 standard.
|
||||
Automatic type conversion in expressions with different kinds of floating
|
||||
point types is performed: the smaller type is converted to the larger. Integer
|
||||
types are **not** converted to floating point types automatically, nor vice
|
||||
versa. Use the `toInt <system.html#toInt>`_ and `toFloat <system.html#toFloat>`_
|
||||
procs for these conversions.
|
||||
versa. Use the `toInt <system.html#toInt,float>`_ and
|
||||
`toFloat <system.html#toFloat,int>`_ procs for these conversions.
|
||||
|
||||
|
||||
Type Conversion
|
||||
@@ -1031,13 +1035,13 @@ type as a function:
|
||||
Internal type representation
|
||||
============================
|
||||
|
||||
As mentioned earlier, the built-in `$ <system.html#$>`_ (stringify) operator
|
||||
As mentioned earlier, the built-in `$ <dollars.html>`_ (stringify) operator
|
||||
turns any basic type into a string, which you can then print to the console
|
||||
using the ``echo`` proc. However, advanced types, and your own custom types,
|
||||
won't work with the ``$`` operator until you define it for them.
|
||||
Sometimes you just want to debug the current value of a complex type without
|
||||
having to write its ``$`` operator. You can use then the `repr
|
||||
<system.html#repr>`_ proc which works with any type and even complex data
|
||||
<system.html#repr,T>`_ proc which works with any type and even complex data
|
||||
graphs with cycles. The following example shows that even for basic types
|
||||
there is a difference between the ``$`` and ``repr`` outputs:
|
||||
|
||||
@@ -1127,9 +1131,9 @@ Operation Comment
|
||||
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
||||
----------------- --------------------------------------------------------
|
||||
|
||||
The `inc <system.html#inc>`_, `dec <system.html#dec>`_, `succ
|
||||
<system.html#succ>`_ and `pred <system.html#pred>`_ operations can fail by
|
||||
raising an `EOutOfRange` or `EOverflow` exception. (If the code has been
|
||||
The `inc <system.html#inc,T,int>`_, `dec <system.html#dec,T,int>`_, `succ
|
||||
<system.html#succ,T,int>`_ and `pred <system.html#pred,T,int>`_ operations can
|
||||
fail by raising an `EOutOfRange` or `EOverflow` exception. (If the code has been
|
||||
compiled with the proper runtime checks turned on.)
|
||||
|
||||
|
||||
@@ -1150,8 +1154,8 @@ compile-time or runtime error. Assignments from the base type to one of its
|
||||
subrange types (and vice versa) are allowed.
|
||||
|
||||
The ``system`` module defines the important `Natural <system.html#Natural>`_
|
||||
type as ``range[0..high(int)]`` (`high <system.html#high>`_ returns the
|
||||
maximal value). Other programming languages may suggest the use of unsigned
|
||||
type as ``range[0..high(int)]`` (`high <system.html#high,typedesc[T]>`_ returns
|
||||
the maximal value). Other programming languages may suggest the use of unsigned
|
||||
integers for natural numbers. This is often **unwise**: you don't want unsigned
|
||||
arithmetic (which wraps around) just because the numbers cannot be negative.
|
||||
Nim's ``Natural`` type helps to avoid this common programming error.
|
||||
@@ -1189,8 +1193,9 @@ Arrays are value types, like any other Nim type. The assignment operator
|
||||
copies the whole array contents.
|
||||
|
||||
The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's
|
||||
length. `low(a) <system.html#low>`_ returns the lowest valid index for the
|
||||
array `a` and `high(a) <system.html#high>`_ the highest valid index.
|
||||
length. `low(a) <system.html#low,openArray[T]>`_ returns the lowest valid index
|
||||
for the array `a` and `high(a) <system.html#high,openArray[T]>`_ the highest
|
||||
valid index.
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -1265,9 +1270,9 @@ during runtime (like strings). Since sequences are resizable they are always
|
||||
allocated on the heap and garbage collected.
|
||||
|
||||
Sequences are always indexed with an ``int`` starting at position 0. The `len
|
||||
<system.html#len,seq[T]>`_, `low <system.html#low>`_ and `high
|
||||
<system.html#high>`_ operations are available for sequences too. The notation
|
||||
``x[i]`` can be used to access the i-th element of ``x``.
|
||||
<system.html#len,seq[T]>`_, `low <system.html#low,openArray[T]>`_ and `high
|
||||
<system.html#high,openArray[T]>`_ operations are available for sequences too.
|
||||
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
||||
|
||||
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
||||
with the array to sequence operator ``@``. Another way to allocate space for
|
||||
@@ -1318,10 +1323,10 @@ Open arrays
|
||||
Often fixed size arrays turn out to be too inflexible; procedures should be
|
||||
able to deal with arrays of different sizes. The `openarray`:idx: type allows
|
||||
this. Openarrays are always indexed with an ``int`` starting at position 0.
|
||||
The `len <system.html#len,TOpenArray>`_, `low <system.html#low>`_ and `high
|
||||
<system.html#high>`_ operations are available for open arrays too. Any array
|
||||
with a compatible base type can be passed to an openarray parameter, the index
|
||||
type does not matter.
|
||||
The `len <system.html#len,TOpenArray>`_, `low <system.html#low,openArray[T]>`_
|
||||
and `high <system.html#high,openArray[T]>`_ operations are available for open
|
||||
arrays too. Any array with a compatible base type can be passed to an
|
||||
openarray parameter, the index type does not matter.
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -1377,8 +1382,8 @@ type conversions in this context:
|
||||
# is transformed by the compiler to:
|
||||
myWriteln(stdout, [$123, $"abc", $4.0])
|
||||
|
||||
In this example `$ <system.html#$>`_ is applied to any argument that is passed
|
||||
to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
|
||||
In this example `$ <dollars.html>`_ is applied to any argument that is passed
|
||||
to the parameter ``a``. Note that `$ <dollars.html>`_ applied to strings is a
|
||||
nop.
|
||||
|
||||
|
||||
@@ -1394,7 +1399,7 @@ define operators which accept Slice objects to define ranges.
|
||||
:test: "nim c $1"
|
||||
|
||||
var
|
||||
a = "Nim is a progamming language"
|
||||
a = "Nim is a programming language"
|
||||
b = "Slices are useless."
|
||||
|
||||
echo a[7..12] # --> 'a prog'
|
||||
@@ -1561,8 +1566,8 @@ having the same field types.
|
||||
|
||||
Tuples can be *unpacked* during variable assignment (and only then!). This can
|
||||
be handy to assign directly the fields of the tuples to individually named
|
||||
variables. An example of this is the `splitFile <os.html#splitFile>`_ proc
|
||||
from the `os module <os.html>`_ which returns the directory, name and
|
||||
variables. An example of this is the `splitFile <os.html#splitFile,string>`_
|
||||
proc from the `os module <os.html>`_ which returns the directory, name and
|
||||
extension of a path at the same time. For tuple unpacking to work you must
|
||||
use parentheses around the values you want to assign the unpacking to,
|
||||
otherwise you will be assigning the same value to all the individual
|
||||
|
||||
@@ -28,7 +28,7 @@ Examples of things that can be implemented in macros:
|
||||
|
||||
* Symbolic differentiation of an expression.
|
||||
``diff(a*pow(x,3) + b*pow(x,2) + c*x + d, x)`` is converted to
|
||||
``3*a*pow(x,2) + 2*a*x + c``
|
||||
``3*a*pow(x,2) + 2*b*x + c``
|
||||
|
||||
|
||||
Macro Arguments
|
||||
|
||||
64
koch.nim
64
koch.nim
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
const
|
||||
NimbleStableCommit = "4007b2a778429a978e12307bf13a038029b4c4d9" # master
|
||||
NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master
|
||||
|
||||
when defined(gcc) and defined(windows):
|
||||
when defined(x86):
|
||||
@@ -27,6 +27,7 @@ import
|
||||
os, strutils, parseopt, osproc, streams
|
||||
|
||||
import tools / kochdocs
|
||||
import tools / deps
|
||||
|
||||
const VersionAsString = system.NimVersion
|
||||
|
||||
@@ -115,6 +116,7 @@ proc copyExe(source, dest: string) =
|
||||
|
||||
const
|
||||
compileNimInst = "tools/niminst/niminst"
|
||||
distDir = "dist"
|
||||
|
||||
proc csource(args: string) =
|
||||
nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " &
|
||||
@@ -122,45 +124,17 @@ proc csource(args: string) =
|
||||
[args, VersionAsString, compileNimInst])
|
||||
|
||||
proc bundleC2nim(args: string) =
|
||||
if not dirExists("dist/c2nim/.git"):
|
||||
exec("git clone https://github.com/nim-lang/c2nim.git dist/c2nim")
|
||||
cloneDependency(distDir, "https://github.com/nim-lang/c2nim.git")
|
||||
nimCompile("dist/c2nim/c2nim",
|
||||
options = "--noNimblePath --path:. " & args)
|
||||
|
||||
proc bundleNimbleExe(latest: bool, args: string) =
|
||||
if not dirExists("dist/nimble/.git"):
|
||||
exec("git clone https://github.com/nim-lang/nimble.git dist/nimble")
|
||||
if not latest:
|
||||
withDir("dist/nimble"):
|
||||
exec("git fetch")
|
||||
exec("git checkout " & NimbleStableCommit)
|
||||
let commit = if latest: "HEAD" else: NimbleStableCommit
|
||||
cloneDependency(distDir, "https://github.com/nim-lang/nimble.git",
|
||||
commit = commit, allowBundled = true)
|
||||
# installer.ini expects it under $nim/bin
|
||||
nimCompile("dist/nimble/src/nimble.nim",
|
||||
options = "-d:release --nilseqs:on " & args)
|
||||
|
||||
proc buildNimble(latest: bool, args: string) =
|
||||
# if koch is used for a tar.xz, build the dist/nimble we shipped
|
||||
# with the tarball:
|
||||
var installDir = "dist/nimble"
|
||||
if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"):
|
||||
discard "don't do the git dance"
|
||||
else:
|
||||
if not dirExists("dist/nimble/.git"):
|
||||
if dirExists(installDir):
|
||||
var id = 0
|
||||
while dirExists("dist/nimble" & $id):
|
||||
inc id
|
||||
installDir = "dist/nimble" & $id
|
||||
exec("git clone https://github.com/nim-lang/nimble.git " & installDir)
|
||||
withDir(installDir):
|
||||
if latest:
|
||||
exec("git checkout -f master")
|
||||
exec("git pull")
|
||||
else:
|
||||
exec("git fetch")
|
||||
exec("git checkout " & NimbleStableCommit)
|
||||
nimCompile(installDir / "src/nimble.nim",
|
||||
options = "--noNimblePath --nilseqs:on -d:release " & args)
|
||||
options = "-d:release --noNimblePath --nilseqs:on " & args)
|
||||
|
||||
proc bundleNimsuggest(args: string) =
|
||||
nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim",
|
||||
@@ -258,7 +232,7 @@ when false:
|
||||
|
||||
proc pdf(args="") =
|
||||
exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
|
||||
[findNim(), args, VersionAsString], additionalPATH=findNim().splitFile.dir)
|
||||
[findNim().quoteShell(), args, VersionAsString], additionalPATH=findNim().splitFile.dir)
|
||||
|
||||
# -------------- boot ---------------------------------------------------------
|
||||
|
||||
@@ -296,7 +270,7 @@ proc boot(args: string) =
|
||||
let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") &
|
||||
hostOS & "_" & hostCPU
|
||||
|
||||
let nimStart = findStartNim()
|
||||
let nimStart = findStartNim().quoteShell()
|
||||
for i in 0..2:
|
||||
let defaultCommand = if useCpp: "cpp" else: "c"
|
||||
let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: ""
|
||||
@@ -318,10 +292,10 @@ proc boot(args: string) =
|
||||
# in order to use less memory, we split the build into two steps:
|
||||
# --compileOnly produces a $project.json file and does not run GCC/Clang.
|
||||
# jsonbuild then uses the $project.json file to build the Nim binary.
|
||||
exec "$# $# $# $# --nimcache:$# --compileOnly compiler" / "nim.nim" %
|
||||
[nimi, bootOptions, extraOption, args, smartNimcache]
|
||||
exec "$# jsonscript $# --nimcache:$# compiler" / "nim.nim" %
|
||||
[nimi, args, smartNimcache]
|
||||
exec "$# $# $# --nimcache:$# $# --compileOnly compiler" / "nim.nim" %
|
||||
[nimi, bootOptions, extraOption, smartNimcache, args]
|
||||
exec "$# jsonscript --nimcache:$# $# compiler" / "nim.nim" %
|
||||
[nimi, smartNimcache, args]
|
||||
|
||||
if sameFileContent(output, i.thVersion):
|
||||
copyExe(output, finalDest)
|
||||
@@ -454,7 +428,7 @@ proc temp(args: string) =
|
||||
"threads" notin programArgs and
|
||||
"js" notin programArgs:
|
||||
bootArgs.add " -d:leanCompiler"
|
||||
let nimexec = findNim()
|
||||
let nimexec = findNim().quoteShell()
|
||||
exec(nimexec & " c -d:debug --debugger:native -d:nimBetterRun " & bootArgs & " " & (d / "compiler" / "nim"), 125)
|
||||
copyExe(output, finalDest)
|
||||
setCurrentDir(origDir)
|
||||
@@ -479,7 +453,7 @@ proc runCI(cmd: string) =
|
||||
when defined(posix): # appveyor (on windows) didn't run this
|
||||
kochExecFold("Boot", "boot")
|
||||
# boot without -d:nimHasLibFFI to make sure this still works
|
||||
kochExecFold("Boot in release mode", "boot -d:release -d:danger")
|
||||
kochExecFold("Boot in release mode", "boot -d:release")
|
||||
|
||||
## build nimble early on to enable remainder to depend on it if needed
|
||||
kochExecFold("Build Nimble", "nimble")
|
||||
@@ -491,7 +465,7 @@ proc runCI(cmd: string) =
|
||||
if getEnv("NIM_TEST_PACKAGES", "false") == "true":
|
||||
execFold("Test selected Nimble packages", "nim c -r testament/testament cat nimble-packages")
|
||||
else:
|
||||
buildTools() # altenatively, kochExec "tools --toolsNoNimble"
|
||||
buildTools()
|
||||
|
||||
## run tests
|
||||
execFold("Test nimscript", "nim e tests/test_nimscript.nims")
|
||||
@@ -628,13 +602,13 @@ when isMainModule:
|
||||
of "temp": temp(op.cmdLineRest)
|
||||
of "xtemp": xtemp(op.cmdLineRest)
|
||||
of "wintools": bundleWinTools(op.cmdLineRest)
|
||||
of "nimble": buildNimble(latest, op.cmdLineRest)
|
||||
of "nimble": bundleNimbleExe(latest, op.cmdLineRest)
|
||||
of "nimsuggest": bundleNimsuggest(op.cmdLineRest)
|
||||
of "toolsnonimble":
|
||||
buildTools(op.cmdLineRest)
|
||||
of "tools":
|
||||
buildTools(op.cmdLineRest)
|
||||
buildNimble(latest, op.cmdLineRest)
|
||||
bundleNimbleExe(latest, op.cmdLineRest)
|
||||
of "pushcsource", "pushcsources": pushCsources()
|
||||
of "valgrind": valgrind(op.cmdLineRest)
|
||||
of "c2nim": bundleC2nim(op.cmdLineRest)
|
||||
|
||||
@@ -13,8 +13,8 @@ include "system/inclrtl"
|
||||
## tree (`AST`:idx:). Macros operate on this tree.
|
||||
##
|
||||
## See also:
|
||||
## * `macros tutorial <https://nim-lang.github.io/Nim/tut3.html>`_
|
||||
## * `macros section in Nim manual <https://nim-lang.github.io/Nim/manual.html#macros>`_
|
||||
## * `macros tutorial <tut3.html>`_
|
||||
## * `macros section in Nim manual <manual.html#macros>`_
|
||||
|
||||
## .. include:: ../../doc/astspec.txt
|
||||
|
||||
@@ -720,6 +720,11 @@ proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||
## Produces a new boolean literal node.
|
||||
result = if b: bindSym"true" else: bindSym"false"
|
||||
|
||||
proc newLit*(s: string): NimNode {.compileTime.} =
|
||||
## Produces a new string literal node.
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
when false:
|
||||
# the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
|
||||
proc newLit*(f: float): NimNode {.compileTime.} =
|
||||
@@ -787,11 +792,6 @@ proc newLit*(arg: tuple): NimNode {.compileTime.} =
|
||||
for a,b in arg.fieldPairs:
|
||||
result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b))
|
||||
|
||||
proc newLit*(s: string): NimNode {.compileTime.} =
|
||||
## Produces a new string literal node.
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} =
|
||||
## Nests the list `pack` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
|
||||
@@ -1620,9 +1620,29 @@ macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped =
|
||||
result.add args[i]
|
||||
|
||||
proc getProjectPath*(): string = discard
|
||||
## Returns the path to the currently compiling project, not to
|
||||
## be confused with ``system.currentSourcePath`` which returns
|
||||
## the path of the current module.
|
||||
## Returns the path to the currently compiling project.
|
||||
##
|
||||
## This is not to be confused with `system.currentSourcePath <system.html#currentSourcePath.t>`_
|
||||
## which returns the path of the source file containing that template
|
||||
## call.
|
||||
##
|
||||
## For example, assume a ``dir1/foo.nim`` that imports a ``dir2/bar.nim``,
|
||||
## have the ``bar.nim`` print out both ``getProjectPath`` and
|
||||
## ``currentSourcePath`` outputs.
|
||||
##
|
||||
## Now when ``foo.nim`` is compiled, the ``getProjectPath`` from
|
||||
## ``bar.nim`` will return the ``dir1/`` path, while the ``currentSourcePath``
|
||||
## will return the path to the ``bar.nim`` source file.
|
||||
##
|
||||
## Now when ``bar.nim`` is compiled directly, the ``getProjectPath``
|
||||
## will now return the ``dir2/`` path, and the ``currentSourcePath``
|
||||
## will still return the same path, the path to the ``bar.nim`` source
|
||||
## file.
|
||||
##
|
||||
## The path returned by this proc is set at compile time.
|
||||
##
|
||||
## See also:
|
||||
## * `getCurrentDir proc <os.html#getCurrentDir>`_
|
||||
|
||||
when defined(nimMacrosSizealignof):
|
||||
proc getSize*(arg: NimNode): int {.magic: "NSizeOf", noSideEffect.} =
|
||||
|
||||
@@ -233,7 +233,7 @@ proc lcs(dataA: var DiffData; lowerA, upperA: int; dataB: var DiffData; lowerB,
|
||||
inc lowerA
|
||||
|
||||
else:
|
||||
# Find the middle snakea and length of an optimal path for A and B
|
||||
# Find the middle snake and length of an optimal path for A and B
|
||||
let smsrd = sms(dataA, lowerA, upperA, dataB, lowerB, upperB, downVector, upVector)
|
||||
# Debug.Write(2, "MiddleSnakeData", String.Format("{0},{1}", smsrd.x, smsrd.y))
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ proc tryExec*(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]): bool
|
||||
try:
|
||||
db.prepareFetchDirect(query, args)
|
||||
var
|
||||
rCnt = -1
|
||||
rCnt:TSqlLen = -1
|
||||
res = SQLRowCount(db.stmt, rCnt)
|
||||
properFreeResult(SQL_HANDLE_STMT, db.stmt)
|
||||
if res != SQL_SUCCESS: dbError(db)
|
||||
@@ -461,10 +461,10 @@ proc execAffectedRows*(db: var DbConn, query: SqlQuery,
|
||||
var q = dbFormat(query, args)
|
||||
db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
|
||||
rawExec(db, query, args)
|
||||
var rCnt = -1
|
||||
var rCnt:TSqlLen = -1
|
||||
db.sqlCheck(SQLRowCount(db.hDb, rCnt))
|
||||
properFreeResult(SQL_HANDLE_STMT, db.stmt)
|
||||
result = rCnt
|
||||
result = rCnt.int64
|
||||
|
||||
proc close*(db: var DbConn) {.
|
||||
tags: [WriteDbEffect], raises: [].} =
|
||||
@@ -489,7 +489,7 @@ proc open*(connection, user, password, database: string): DbConn {.
|
||||
## Currently the database parameter is ignored,
|
||||
## but included to match ``open()`` in the other db_xxxxx library modules.
|
||||
var
|
||||
val: TSqlInteger = SQL_OV_ODBC3
|
||||
val = SQL_OV_ODBC3
|
||||
resLen = 0
|
||||
result = (hDb: nil, env: nil, stmt: nil)
|
||||
# allocate environment handle
|
||||
@@ -497,7 +497,7 @@ proc open*(connection, user, password, database: string): DbConn {.
|
||||
if res != SQL_SUCCESS: dbError("Error: unable to initialise ODBC environment.")
|
||||
res = SQLSetEnvAttr(result.env,
|
||||
SQL_ATTR_ODBC_VERSION.TSqlInteger,
|
||||
val, resLen.TSqlInteger)
|
||||
cast[SqlPointer](val.addr), resLen.TSqlInteger)
|
||||
if res != SQL_SUCCESS: dbError("Error: unable to set ODBC driver version.")
|
||||
# allocate hDb handle
|
||||
res = SQLAllocHandle(SQL_HANDLE_DBC, result.env, result.hDb)
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
when defined(js):
|
||||
{.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".}
|
||||
|
||||
## What is NRE?
|
||||
## ============
|
||||
##
|
||||
@@ -215,7 +218,7 @@ type
|
||||
pattern*: string ## the pattern that caused the problem
|
||||
|
||||
StudyError* = ref object of RegexError
|
||||
## Thrown when studying the regular expression failes
|
||||
## Thrown when studying the regular expression fails
|
||||
## for whatever reason. The message contains the error
|
||||
## code.
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
when defined(js):
|
||||
{.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".}
|
||||
|
||||
## Regular expression support for Nim.
|
||||
##
|
||||
## This module is implemented by providing a wrapper around the
|
||||
@@ -97,7 +100,7 @@ proc bufSubstr(b: cstring, sPos, ePos: int): string {.inline.} =
|
||||
## Don't assume cstring is '\0' terminated
|
||||
let sz = ePos - sPos
|
||||
result = newString(sz+1)
|
||||
copyMem(addr(result[0]), unsafeaddr(b[sPos]), sz)
|
||||
copyMem(addr(result[0]), unsafeAddr(b[sPos]), sz)
|
||||
result.setLen(sz)
|
||||
|
||||
proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||
@@ -665,4 +668,3 @@ when isMainModule:
|
||||
doAssert replace("bar", re"^", "foo") == "foobar"
|
||||
doAssert replace("foo", re"", "-") == "-foo"
|
||||
doAssert replace("foo", re"$", "bar") == "foobar"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## Declaration of the Document Object Model for the `JavaScript backend
|
||||
## <backends.html#the-javascript-target>`_.
|
||||
## <backends.html#backends-the-javascript-target>`_.
|
||||
|
||||
when not defined(js) and not defined(Nimdoc):
|
||||
{.error: "This module only works on the JavaScript platform".}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## Wrapper for the `console` object for the `JavaScript backend
|
||||
## <backends.html#the-javascript-target>`_.
|
||||
## <backends.html#backends-the-javascript-target>`_.
|
||||
|
||||
when not defined(js) and not defined(Nimdoc):
|
||||
{.error: "This module only works on the JavaScript platform".}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
## var document {.importc, nodecl.}: JsObject
|
||||
## var console {.importc, nodecl.}: JsObject
|
||||
## # import the "$" function
|
||||
## proc jq(selector: JsObject): JsObject {.importcpp: "$(#)".}
|
||||
## proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".}
|
||||
##
|
||||
## # Use jQuery to make the following code run, after the document is ready.
|
||||
## # This uses an experimental ``.()`` operator for ``JsObject``, to emit
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
# - named `performCodeReload`, requires the hotcodereloading module
|
||||
# - explicitly called by the user - the current active callstack shouldn't contain
|
||||
# any functions which are defined in modules that will be reloaded (or crash!).
|
||||
# The reason is that old dynalic libraries get unloaded.
|
||||
# The reason is that old dynamic libraries get unloaded.
|
||||
# Example:
|
||||
# if A is the main module and it imports B, then only B is reloadable and only
|
||||
# if when calling hcrPerformCodeReload there is no function defined in B in the
|
||||
@@ -549,7 +549,7 @@ when defined(createNimHcr):
|
||||
# problems when the GC is executed while the reload is underway.
|
||||
# Future versions of NIMHCR won't use the GC, because all globals and the
|
||||
# metadata needed to access them will be placed in shared memory, so they
|
||||
# can be manipulted from external programs without reloading.
|
||||
# can be manipulated from external programs without reloading.
|
||||
GC_disable()
|
||||
defer: GC_enable()
|
||||
|
||||
|
||||
@@ -32,4 +32,4 @@ when not defined(createNimRtl):
|
||||
|
||||
import
|
||||
parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes,
|
||||
os, osproc, times
|
||||
os, osproc, times, cstrutils
|
||||
|
||||
@@ -1605,7 +1605,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode =
|
||||
## <http://docutils.sourceforge.net/docs/ref/rst/directives.html#code>`_ and
|
||||
## the nim extension ``.. code-block::``. If the block is an extension, we
|
||||
## want the default language syntax highlighting to be Nim, so we create a
|
||||
## fake internal field to comminicate with the generator. The field is named
|
||||
## fake internal field to communicate with the generator. The field is named
|
||||
## ``default-language``, which is unlikely to collide with a field specified
|
||||
## by any random rst input file.
|
||||
##
|
||||
|
||||
@@ -154,7 +154,8 @@ proc writeIndexFile*(g: var RstGenerator, outfile: string) =
|
||||
## Writes the current index buffer to the specified output file.
|
||||
##
|
||||
## You previously need to add entries to the index with the `setIndexTerm()
|
||||
## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
|
||||
## <#setIndexTerm,RstGenerator,string,string,string,string,string>`_ proc.
|
||||
## If the index is empty the file won't be created.
|
||||
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
|
||||
|
||||
proc addXmlChar(dest: var string, c: char) =
|
||||
@@ -308,7 +309,7 @@ proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string,
|
||||
## The `id` will be appended with a hash character only if its length is not
|
||||
## zero, otherwise no specific anchor will be generated. In general you
|
||||
## should only pass an empty `id` value for the title of standalone rst
|
||||
## documents (they are special for the `mergeIndexes() <#mergeIndexes>`_
|
||||
## documents (they are special for the `mergeIndexes() <#mergeIndexes,string>`_
|
||||
## proc, see `Index (idx) file format <docgen.html#index-idx-file-format>`_
|
||||
## for more information). Unlike other index terms, title entries are
|
||||
## inserted at the beginning of the accumulated buffer to maintain a logical
|
||||
@@ -318,8 +319,9 @@ proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string,
|
||||
## columns with their contents will be added.
|
||||
##
|
||||
## The index won't be written to disk unless you call `writeIndexFile()
|
||||
## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
|
||||
## tools guide <docgen.html#index-switch>`_.
|
||||
## <#writeIndexFile,RstGenerator,string>`_. The purpose of the index is
|
||||
## documented in the `docgen tools guide
|
||||
## <docgen.html#related-options-index-switch>`_.
|
||||
var
|
||||
entry = term
|
||||
isTitle = false
|
||||
@@ -469,8 +471,8 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
|
||||
proc isDocumentationTitle(hyperlink: string): bool =
|
||||
## Returns true if the hyperlink is actually a documentation title.
|
||||
##
|
||||
## Documentation titles lack the hash. See `mergeIndexes() <#mergeIndexes>`_
|
||||
## for a more detailed explanation.
|
||||
## Documentation titles lack the hash. See `mergeIndexes()
|
||||
## <#mergeIndexes,string>`_ for a more detailed explanation.
|
||||
result = hyperlink.find('#') < 0
|
||||
|
||||
proc stripTocLevel(s: string): tuple[level: int, text: string] =
|
||||
@@ -647,13 +649,15 @@ proc mergeIndexes*(dir: string): string =
|
||||
## This proc will first scan `dir` for index files with the ``.idx``
|
||||
## extension previously created by commands like ``nim doc|rst2html``
|
||||
## which use the ``--index:on`` switch. These index files are the result of
|
||||
## calls to `setIndexTerm() <#setIndexTerm>`_ and `writeIndexFile()
|
||||
## <#writeIndexFile>`_, so they are simple tab separated files.
|
||||
## calls to `setIndexTerm()
|
||||
## <#setIndexTerm,RstGenerator,string,string,string,string,string>`_
|
||||
## and `writeIndexFile() <#writeIndexFile,RstGenerator,string>`_, so they are
|
||||
## simple tab separated files.
|
||||
##
|
||||
## As convention this proc will split index files into two categories:
|
||||
## documentation and API. API indices will be all joined together into a
|
||||
## single big sorted index, making the bulk of the final index. This is good
|
||||
## for API documentation because many symbols are repated in different
|
||||
## for API documentation because many symbols are repeated in different
|
||||
## modules. On the other hand, documentation indices are essentially table of
|
||||
## contents plus a few special markers. These documents will be rendered in a
|
||||
## separate section which tries to maintain the order and hierarchy of the
|
||||
|
||||
@@ -584,7 +584,7 @@ proc fchmod*(a1: cint, a2: Mode): cint {.importc, header: "<sys/stat.h>".}
|
||||
proc fstat*(a1: cint, a2: var Stat): cint {.importc, header: "<sys/stat.h>".}
|
||||
proc lstat*(a1: cstring, a2: var Stat): cint {.importc, header: "<sys/stat.h>".}
|
||||
proc mkdir*(a1: cstring, a2: Mode): cint {.importc, header: "<sys/stat.h>".}
|
||||
## Use `os.createDir() <os.html#createDir>`_ and similar.
|
||||
## Use `os.createDir() <os.html#createDir,string>`_ and similar.
|
||||
|
||||
proc mkfifo*(a1: cstring, a2: Mode): cint {.importc, header: "<sys/stat.h>".}
|
||||
proc mknod*(a1: cstring, a2: Mode, a3: Dev): cint {.
|
||||
|
||||
@@ -562,7 +562,7 @@ when defined(macosx):
|
||||
var
|
||||
SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
|
||||
elif defined(solaris):
|
||||
# Solaris dont have MSG_NOSIGNAL
|
||||
# Solaris doesn't have MSG_NOSIGNAL
|
||||
const
|
||||
MSG_NOSIGNAL* = 0'i32
|
||||
else:
|
||||
|
||||
@@ -34,7 +34,12 @@ type
|
||||
SocketHandle* = distinct cint # The type used to represent socket descriptors
|
||||
|
||||
type
|
||||
Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
|
||||
Time* {.importc: "time_t", header: "<time.h>".} = distinct (
|
||||
when defined(nimUse64BitCTime):
|
||||
int64
|
||||
else:
|
||||
clong
|
||||
)
|
||||
|
||||
Timespec* {.importc: "struct timespec",
|
||||
header: "<time.h>", final, pure.} = object ## struct timespec
|
||||
@@ -572,7 +577,7 @@ when defined(macosx):
|
||||
var
|
||||
SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
|
||||
elif defined(solaris):
|
||||
# Solaris dont have MSG_NOSIGNAL
|
||||
# Solaris doesn't have MSG_NOSIGNAL
|
||||
const
|
||||
MSG_NOSIGNAL* = 0'i32
|
||||
else:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user