mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
133 Commits
pr_holey_e
...
v1.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
193b3c66bb | ||
|
|
0b134412f8 | ||
|
|
1526ae8791 | ||
|
|
b914573d18 | ||
|
|
f579d29b68 | ||
|
|
f79f7fed98 | ||
|
|
e0c4015bbe | ||
|
|
7b500cbfad | ||
|
|
53e4692665 | ||
|
|
b0e595b3cf | ||
|
|
4e3c997d40 | ||
|
|
f16bb4d85b | ||
|
|
8f1dea614e | ||
|
|
63d710f5a1 | ||
|
|
2ebd47089a | ||
|
|
535f0b9c9d | ||
|
|
813b371758 | ||
|
|
a09379f5fd | ||
|
|
e9f7455bd6 | ||
|
|
e03b1b79ae | ||
|
|
0ea770c8f0 | ||
|
|
8a0012de42 | ||
|
|
1d4916b481 | ||
|
|
2de758e68a | ||
|
|
c8c9699850 | ||
|
|
5df7f3fd5c | ||
|
|
44d45b763c | ||
|
|
f7c150766a | ||
|
|
4ae143ca60 | ||
|
|
0a8dcd5e11 | ||
|
|
929aa99665 | ||
|
|
bae10d44fa | ||
|
|
4632e8b26e | ||
|
|
97e2e06b00 | ||
|
|
b827431499 | ||
|
|
99d448deeb | ||
|
|
9afd19b236 | ||
|
|
0d0cf86401 | ||
|
|
5785444520 | ||
|
|
1b3f5eed70 | ||
|
|
517538dcf8 | ||
|
|
59916007cc | ||
|
|
a5bcbe6dff | ||
|
|
cd3d4b5e05 | ||
|
|
ac2181c5b9 | ||
|
|
4675aae90b | ||
|
|
a0402b2012 | ||
|
|
cbdc48ec66 | ||
|
|
f19edae1b8 | ||
|
|
c5b9a44894 | ||
|
|
3009eafc89 | ||
|
|
1e97abec96 | ||
|
|
95a655a975 | ||
|
|
39f5a2b218 | ||
|
|
6c1f389d72 | ||
|
|
1ae9cac3a4 | ||
|
|
fa7f5742d3 | ||
|
|
c8314b7c9c | ||
|
|
52ea15cc24 | ||
|
|
7926440ae3 | ||
|
|
bda6e071cd |
@@ -51,6 +51,8 @@ addons:
|
||||
- libsdl1.2-dev
|
||||
- libgc-dev
|
||||
- libsfml-dev
|
||||
- libc6-dbg
|
||||
- valgrind
|
||||
homebrew:
|
||||
packages:
|
||||
- boehmgc
|
||||
|
||||
148
azure-pipelines.yml
Normal file
148
azure-pipelines.yml
Normal file
@@ -0,0 +1,148 @@
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
CPU: amd64
|
||||
Linux_i386:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-10.14'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-10.14'
|
||||
CPU: amd64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64:
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
Windows_amd64_pkg:
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
NIM_TEST_PACKAGES: true
|
||||
|
||||
pool:
|
||||
vmImage: $(vmImage)
|
||||
|
||||
workspace:
|
||||
clean: all
|
||||
|
||||
steps:
|
||||
- bash: git config --global core.autocrlf false
|
||||
displayName: 'Disable auto conversion to CRLF by git (Windows-only)'
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- checkout: self
|
||||
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
displayName: 'Checkout csources'
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '8.x'
|
||||
displayName: 'Install node.js 8.x'
|
||||
|
||||
- bash: |
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
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++:
|
||||
# - 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
|
||||
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
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
|
||||
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
|
||||
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386
|
||||
|
||||
cat << EOF > bin/gcc
|
||||
#!/bin/bash
|
||||
|
||||
exec $(which gcc) -m32 "\$@"
|
||||
EOF
|
||||
cat << EOF > bin/g++
|
||||
#!/bin/bash
|
||||
|
||||
exec $(which g++) -m32 "\$@"
|
||||
EOF
|
||||
|
||||
chmod 755 bin/gcc
|
||||
chmod 755 bin/g++
|
||||
|
||||
displayName: 'Install dependencies (i386 Linux)'
|
||||
condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386'))
|
||||
|
||||
- bash: brew install boehmgc make sfml
|
||||
displayName: 'Install dependencies (OSX)'
|
||||
condition: eq(variables['Agent.OS'], 'Darwin')
|
||||
|
||||
- bash: |
|
||||
mkdir dist
|
||||
curl -L https://nim-lang.org/download/mingw64-6.3.0.7z -o dist/mingw64.7z
|
||||
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
|
||||
7z x dist/mingw64.7z -odist
|
||||
7z x dist/dlls.zip -obin
|
||||
echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin'
|
||||
|
||||
displayName: 'Install dependencies (Windows)'
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin'
|
||||
displayName: 'Add build binaries to PATH'
|
||||
|
||||
- bash: |
|
||||
echo 'PATH:' "$PATH"
|
||||
echo '##[section]gcc version'
|
||||
gcc -v
|
||||
echo '##[section]nodejs version'
|
||||
node -v
|
||||
echo '##[section]make version'
|
||||
make -v
|
||||
displayName: 'System information'
|
||||
|
||||
- bash: |
|
||||
ncpu=
|
||||
case '$(Agent.OS)' in
|
||||
'Linux')
|
||||
ncpu=$(nproc)
|
||||
;;
|
||||
'Darwin')
|
||||
ncpu=$(sysctl -n hw.ncpu)
|
||||
;;
|
||||
'Windows_NT')
|
||||
ncpu=$NUMBER_OF_PROCESSORS
|
||||
;;
|
||||
esac
|
||||
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
|
||||
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU)
|
||||
displayName: 'Build 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]'
|
||||
displayName: 'Run CI'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
16
build_all.bat
Normal file
16
build_all.bat
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
rem build development version of the compiler; can be rerun safely
|
||||
if not exist csources (
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
)
|
||||
if not exist bin\nim.exe (
|
||||
cd csources
|
||||
if PROCESSOR_ARCHITECTURE == AMD64 (
|
||||
SET ARCH=64
|
||||
)
|
||||
CALL build.bat
|
||||
cd ..
|
||||
)
|
||||
bin\nim.exe c --skipUserCfg --skipParentCfg koch
|
||||
koch.exe boot -d:release
|
||||
koch.exe tools
|
||||
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)
|
||||
@@ -71,7 +71,7 @@ iterator parseTableCells*(s: string, delim = '\t'): Cell =
|
||||
proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string =
|
||||
## formats a `delim`-delimited `s` representing a table; each cell is aligned
|
||||
## to a width that's computed for each column; consecutive columns are
|
||||
## delimted by `sep`, and alignment space is filled using `fill`.
|
||||
## delimited by `sep`, and alignment space is filled using `fill`.
|
||||
## More customized formatting can be done by calling `parseTableCells` directly.
|
||||
for cell in parseTableCells(s, delim):
|
||||
result.add cell.text
|
||||
|
||||
@@ -185,7 +185,7 @@ type
|
||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||
# to allow powerful multi-line templates
|
||||
nkBlockExpr, # a statement block ending in an expr; this is used
|
||||
# to allowe powerful multi-line templates that open a
|
||||
# to allow powerful multi-line templates that open a
|
||||
# temporary scope
|
||||
nkStmtListType, # a statement list ending in a type; for macros
|
||||
nkBlockType, # a statement block ending in a type; for macros
|
||||
@@ -272,7 +272,7 @@ type
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
sfDiscardable, # returned value may be discarded implicitly
|
||||
sfOverriden, # proc is overriden
|
||||
sfOverriden, # proc is overridden
|
||||
sfCallsite # A flag for template symbols to tell the
|
||||
# compiler it should use line information from
|
||||
# the calling side of the macro, not from the
|
||||
@@ -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
|
||||
|
||||
@@ -535,8 +531,8 @@ type
|
||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||
# implicitly '.compiletime'
|
||||
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
||||
tfCovariant # covariant generic param mimicing a ptr type
|
||||
tfWeakCovariant # covariant generic param mimicing a seq/array type
|
||||
tfCovariant # covariant generic param mimicking a ptr type
|
||||
tfWeakCovariant # covariant generic param mimicking a seq/array type
|
||||
tfContravariant # contravariant generic param
|
||||
tfCheckedForDestructor # type was checked for having a destructor.
|
||||
# If it has one, t.destructor is not nil.
|
||||
@@ -1250,7 +1246,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
|
||||
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
|
||||
# this is dirty. abstractVarRange isn't defined yet and therefor it
|
||||
# this is dirty. abstractVarRange isn't defined yet and therefore it
|
||||
# is duplicated here.
|
||||
const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned}
|
||||
|
||||
@@ -1027,7 +1027,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
dec p.splitDecls
|
||||
|
||||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# this unusual way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# is threadsafe.
|
||||
internalAssert p.config, n.kind == nkBracket
|
||||
if p.config.target.targetOS == osGenode:
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -784,7 +784,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
var branches: seq[Rope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in 1 ..< len(t):
|
||||
inc(p.labels)
|
||||
@@ -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])
|
||||
|
||||
@@ -61,7 +61,7 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
|
||||
var res = s.name.s.mangle
|
||||
# Take into account if HCR is on because of the following scenario:
|
||||
# if a module gets imported and it has some more importc symbols in it,
|
||||
# some param names might recieve the "_0" suffix to distinguish from what
|
||||
# some param names might receive the "_0" suffix to distinguish from what
|
||||
# is newly available. That might lead to changes in the C code in nimcache
|
||||
# that contain only a parameter name change, but that is enough to mandate
|
||||
# recompilation of that source file and thus a new shared object will be
|
||||
@@ -287,6 +287,7 @@ proc fillResult(conf: ConfigRef; param: PNode) =
|
||||
|
||||
proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
|
||||
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
|
||||
useHeader(m, t.sym)
|
||||
result = t.sym.loc.r
|
||||
else:
|
||||
result = rope(literal)
|
||||
@@ -1364,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:
|
||||
@@ -997,13 +997,14 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: Rope
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if sfNoReturn in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
@@ -1011,7 +1012,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
addf(m.s[cfsProcHeaders], "$1;\n", [header])
|
||||
generatedProc = ropecg(p.module, "$N$1 {$N", [header])
|
||||
generatedProc.add ropecg(p.module, "$1 {", [header])
|
||||
add(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
@@ -1255,7 +1256,7 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var preMainCode: Rope
|
||||
@@ -1514,7 +1515,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
|
||||
proc genDatInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var moduleDatInitRequired = m.hcrOn
|
||||
@@ -1558,7 +1559,7 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
var moduleInitRequired = m.hcrOn
|
||||
let initname = getInitName(m)
|
||||
@@ -1746,7 +1747,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
# don't generate a TFrame which can confuse the stack bottom initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
|
||||
@@ -58,7 +58,7 @@ type
|
||||
id*: int # the ID of the label; positive means that it
|
||||
label*: Rope # generated text for the label
|
||||
# nil if label is not used
|
||||
sections*: TCProcSections # the code beloging
|
||||
sections*: TCProcSections # the code belonging
|
||||
isLoop*: bool # whether block is a loop
|
||||
nestedTryStmts*: int16 # how many try statements is it nested into
|
||||
nestedExceptStmts*: int16 # how many except statements is it nested into
|
||||
@@ -150,7 +150,7 @@ type
|
||||
initProc*: BProc # code for init procedure
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
|
||||
inHcrInitGuard*: bool # We are currently withing a HCR reloading guard.
|
||||
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
|
||||
@@ -683,7 +683,8 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
n[0] = ex
|
||||
result.add(n)
|
||||
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv:
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv,
|
||||
nkDerefExpr, nkHiddenDeref:
|
||||
var ns = false
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.lowerStmtListExprs(n[i], ns)
|
||||
@@ -757,7 +758,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true"))
|
||||
n[1] = newBody
|
||||
|
||||
of nkDotExpr:
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
var ns = false
|
||||
n[0] = ctx.lowerStmtListExprs(n[0], ns)
|
||||
if ns:
|
||||
@@ -1288,7 +1289,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
if getEnvParam(fn).isNil:
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which will
|
||||
# be handled specially by lambda lifting. Local temp vars (if needed)
|
||||
# should folllow the same logic.
|
||||
# should follow the same logic.
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
|
||||
ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
|
||||
@@ -1309,7 +1310,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
# Optimize empty states away
|
||||
ctx.deleteEmptyStates()
|
||||
|
||||
# Make new body by concating the list of states
|
||||
# Make new body by concatenating the list of states
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for s in ctx.states:
|
||||
assert(s.len == 2)
|
||||
|
||||
@@ -87,7 +87,7 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
discard
|
||||
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars(conf)
|
||||
self.processCmdLine(passCmd2, "", conf)
|
||||
if conf.command == "":
|
||||
|
||||
@@ -380,6 +380,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)
|
||||
@@ -614,22 +617,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 +759,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")
|
||||
|
||||
@@ -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. :-/
|
||||
@@ -513,7 +513,7 @@ proc genTry(c: var Con; n: PNode) =
|
||||
let f = c.tryStmtFixups[i]
|
||||
c.patch(f)
|
||||
# we also need to produce join instructions
|
||||
# for the 'fork' that might preceed the goto instruction
|
||||
# for the 'fork' that might precede the goto instruction
|
||||
if f.int-1 >= 0 and c.code[f.int-1].kind == fork:
|
||||
c.joinI(TPosition(f.int-1), n)
|
||||
|
||||
|
||||
@@ -592,7 +592,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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -135,7 +135,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
|
||||
else:
|
||||
addSon(result, default.copyTree)
|
||||
|
||||
# add any generic paramaters
|
||||
# add any generic parameters
|
||||
for i in 1 .. genericParams:
|
||||
result.addSon n.sons[givenRegularParams + i]
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ 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",
|
||||
@@ -404,7 +404,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
if result.len == 0:
|
||||
# not overriden for this cross compilation setting?
|
||||
# not overridden for this cross compilation setting?
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
else:
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
@@ -757,7 +757,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
|
||||
# way of being able to debug and rebuild the program at the same time. This
|
||||
# is accomplished using the /PDB:<filename> flag (there also exists the
|
||||
# /PDBALTPATH:<filename> flag). The only downside is that the .pdb files are
|
||||
# atleast 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# at least 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# and will quickly accumulate. There is a hacky solution: we could try to
|
||||
# delete all .pdb files with a pattern and swallow exceptions.
|
||||
#
|
||||
@@ -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:
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
info: TLineInfo
|
||||
indent, emitPar: int
|
||||
x: string # the current input line
|
||||
outp: PLLStream # the ouput will be parsed by pnimsyn
|
||||
outp: PLLStream # the output will be parsed by pnimsyn
|
||||
subsChar, nimDirective: char
|
||||
emit, conc, toStr: string
|
||||
curly, bracket, par: int
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,7 @@ proc hlo(c: PContext, n: PNode): PNode
|
||||
proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
|
||||
# we need to ensure that the resulting AST is semchecked. However, it's
|
||||
# aweful to semcheck before macro invocation, so we don't and treat
|
||||
# awful to semcheck before macro invocation, so we don't and treat
|
||||
# templates and macros as immediate in this context.
|
||||
var rule: string
|
||||
if optHints in c.config.options and hintPattern in c.config.notes:
|
||||
|
||||
@@ -27,7 +27,7 @@ proc importPureEnumField*(c: PContext; s: PSym) =
|
||||
if checkB == nil:
|
||||
strTableAdd(c.pureEnumFields, s)
|
||||
else:
|
||||
# mark as ambigous:
|
||||
# mark as ambiguous:
|
||||
incl(c.ambiguousSymbols, checkB.id)
|
||||
incl(c.ambiguousSymbols, s.id)
|
||||
|
||||
@@ -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,46 +95,9 @@ 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 accross all code paths
|
||||
## Computes the set of definitely initialized variables across all code paths
|
||||
## as an IntSet of IDs.
|
||||
var pc = pc
|
||||
while pc < code.len:
|
||||
@@ -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
|
||||
@@ -492,11 +371,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
elif arg.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
# sink parameter (bug #11524). Note that the string implemenation is
|
||||
# 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
|
||||
|
||||
@@ -73,6 +73,15 @@ proc toInt64*(arg: Int128): int64 =
|
||||
|
||||
cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc toInt64Checked*(arg: Int128; onError: int64): int64 =
|
||||
if isNegative(arg):
|
||||
if arg.sdata(3) != -1 or arg.sdata(2) != -1:
|
||||
return onError
|
||||
else:
|
||||
if arg.sdata(3) != 0 or arg.sdata(2) != 0:
|
||||
return onError
|
||||
return cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc toInt32*(arg: Int128): int32 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
@@ -398,11 +407,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
|
||||
|
||||
@@ -427,7 +442,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
|
||||
result.quotient = -quotient
|
||||
else:
|
||||
result.quotient = quotient
|
||||
if isNegativeB:
|
||||
if isNegativeA:
|
||||
result.remainder = -dividend
|
||||
else:
|
||||
result.remainder = dividend
|
||||
@@ -534,8 +549,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)
|
||||
@@ -667,3 +680,22 @@ when isMainModule:
|
||||
|
||||
doAssert $high(Int128) == "170141183460469231731687303715884105727"
|
||||
doAssert $low(Int128) == "-170141183460469231731687303715884105728"
|
||||
|
||||
var ma = 100'i64
|
||||
var mb = 13
|
||||
|
||||
# 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:
|
||||
@@ -1295,12 +1295,16 @@ proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
|
||||
return
|
||||
owner = owner.up
|
||||
|
||||
proc genVarInit(p: PProc, v: PSym, n: PNode)
|
||||
|
||||
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var s = n.sym
|
||||
case s.kind
|
||||
of skVar, skLet, skParam, skTemp, skResult, skForVar:
|
||||
if s.loc.r == nil:
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
if sfCompileTime in s.flags:
|
||||
genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info))
|
||||
if s.kind == skParam:
|
||||
genCopyForParamIfNeeded(p, n)
|
||||
let k = mapType(p, s.typ)
|
||||
@@ -1732,7 +1736,11 @@ proc genVarStmt(p: PProc, n: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
|
||||
genLineDir(p, a)
|
||||
genVarInit(p, v, a.sons[2])
|
||||
if sfCompileTime notin v.flags:
|
||||
genVarInit(p, v, a.sons[2])
|
||||
else:
|
||||
# lazy emit, done when it's actually used.
|
||||
if v.ast == nil: v.ast = a[2]
|
||||
|
||||
proc genConstant(p: PProc, c: PSym) =
|
||||
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
|
||||
@@ -2147,7 +2155,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
|
||||
@@ -477,7 +482,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
w = up
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt:
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
|
||||
discard
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
@@ -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")
|
||||
@@ -760,6 +765,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c)
|
||||
else:
|
||||
n.sons[0] = liftCapturedVars(n[0], owner, d, c)
|
||||
of nkTypeOfExpr:
|
||||
result = n
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
@@ -921,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:
|
||||
|
||||
@@ -499,7 +499,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of openPars:
|
||||
if tok.strongSpaceA > 0 and not em.endsInWhite and not em.wasExportMarker:
|
||||
if tok.strongSpaceA > 0 and not em.endsInWhite and
|
||||
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
|
||||
wrSpace em
|
||||
wr(em, TokTypeToStr[tok.tokType], ltSomeParLe)
|
||||
rememberSplit(splitParLe)
|
||||
|
||||
@@ -134,7 +134,7 @@ type
|
||||
TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
|
||||
TLexer* = object of TBaseLexer
|
||||
fileIdx*: FileIndex
|
||||
indentAhead*: int # if > 0 an indendation has already been read
|
||||
indentAhead*: int # if > 0 an indentation has already been read
|
||||
# this is needed because scanning comments
|
||||
# needs so much look-ahead
|
||||
currLineIndent*: int
|
||||
|
||||
@@ -411,7 +411,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
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)
|
||||
|
||||
@@ -233,7 +233,7 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addInterfaceDeclAux(c, sym)
|
||||
|
||||
when defined(nimfix):
|
||||
# when we cannot find the identifier, retry with a changed identifer:
|
||||
# when we cannot find the identifier, retry with a changed identifier:
|
||||
proc altSpelling(x: PIdent): PIdent =
|
||||
case x.s[0]
|
||||
of 'A'..'Z': result = getIdent(toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
|
||||
@@ -64,7 +64,7 @@ type
|
||||
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
|
||||
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
|
||||
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
|
||||
cacheSeqs*: Table[string, PNode] # state that is shared to suppor the 'macrocache' API
|
||||
cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API
|
||||
cacheCounters*: Table[string, BiggestInt]
|
||||
cacheTables*: Table[string, BTree[string, PNode]]
|
||||
passes*: seq[TPass]
|
||||
@@ -215,7 +215,7 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
||||
addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
|
||||
if g.suggestMode:
|
||||
g.deps.incl m.position.dependsOn(dep.int)
|
||||
# we compute the transitive closure later when quering the graph lazily.
|
||||
# we compute the transitive closure later when querying the graph lazily.
|
||||
# this improves efficiency quite a lot:
|
||||
#invalidTransitiveClosure = true
|
||||
|
||||
|
||||
@@ -190,6 +190,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 +207,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
|
||||
|
||||
@@ -46,7 +46,7 @@ proc selectUniqueSymbol*(i: Interpreter; name: string;
|
||||
s = nextIdentIter(it, i.mainModule.tab)
|
||||
|
||||
proc selectRoutine*(i: Interpreter; name: string): PSym =
|
||||
## Selects a declared rountine (proc/func/etc) from the main module.
|
||||
## Selects a declared routine (proc/func/etc) from the main module.
|
||||
## The routine needs to have the export marker ``*``. The only matching
|
||||
## routine is returned and ``nil`` if it is overloaded.
|
||||
result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
|
||||
|
||||
@@ -98,7 +98,7 @@ proc handleCmdLine(config: ConfigRef) =
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig, config) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "", config)
|
||||
mainCommand()
|
||||
|
||||
@@ -15,6 +15,6 @@ const
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
NimCompilerApiVersion* = 3 ## Check for the existance of this before accessing it
|
||||
NimCompilerApiVersion* = 3 ## Check for the existence of this before accessing it
|
||||
## as older versions of the compiler API do not
|
||||
## declare this.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -138,8 +142,12 @@ type
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
## Allows to modify a NimNode where the type has already been
|
||||
## flaged with nfSem. If you actually do this, it will cause
|
||||
## 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 =
|
||||
@@ -727,7 +738,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
if conf.target.targetCPU == cpuI386:
|
||||
if conf != nil and conf.target.targetCPU == cpuI386:
|
||||
#on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
|
||||
if conf.target.targetOS != osWindows:
|
||||
# on i386 for all known POSIX systems, 64bits ints are aligned
|
||||
|
||||
@@ -40,19 +40,16 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
|
||||
proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
# foo-#head/../bar becomes @foo-@hhead@s..@sbar
|
||||
result = "@m" & relativeTo(path, conf.projectPath, '/').string.multiReplace({"/": "@s", "#": "@h", "@": "@@"})
|
||||
result = "@m" & relativeTo(path, conf.projectPath, '/').string.multiReplace({"/": "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
|
||||
proc demanglePackageName*(path: string): string =
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": ""})
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
if x.len == 0:
|
||||
result = path
|
||||
let (p, file, ext) = path.splitFile
|
||||
if x == "stdlib":
|
||||
# Hot code reloading now relies on 'stdlib_system' names etc.
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
if x == "stdlib":
|
||||
# Hot code reloading now relies on 'stdlib_system' names etc.
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
else:
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
|
||||
@@ -710,7 +710,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
result = parseCast(p)
|
||||
else:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p) # we must consume a token here to prevend endless loops!
|
||||
getTok(p) # we must consume a token here to prevent endless loops!
|
||||
result = p.emptyNode
|
||||
|
||||
proc namedParams(p: var TParser, callee: PNode,
|
||||
|
||||
@@ -66,7 +66,7 @@ const
|
||||
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
|
||||
|
||||
@@ -720,7 +710,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||
proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||
var callNode: PNode
|
||||
|
||||
if n.kind == nkIdent:
|
||||
if n.kind in {nkIdent, nkSym}:
|
||||
# pragma -> pragma()
|
||||
callNode = newTree(nkCall, n)
|
||||
elif n.kind == nkExprColonExpr:
|
||||
@@ -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)
|
||||
|
||||
@@ -29,7 +29,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||
result = true
|
||||
|
||||
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
# Searchs for a forward declaration or a "twin" symbol of fn
|
||||
# Searches for a forward declaration or a "twin" symbol of fn
|
||||
# in the symbol table. If the parameter lists are exactly
|
||||
# the same the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
@@ -108,7 +108,7 @@ when false:
|
||||
result = true
|
||||
|
||||
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# Searches for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
for scope in walkScopes(startScope):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -640,7 +640,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = explicitGenericInstError(c, n)
|
||||
|
||||
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# Searches for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
# New approach: generate fn(x, y, z) where x, y, z have the proper types
|
||||
# and use the overloading resolution mechanism:
|
||||
|
||||
@@ -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 = @[]
|
||||
|
||||
@@ -2038,7 +2038,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
let oldErrorMax = c.config.errorMax
|
||||
let oldCompilesId = c.compilesContextId
|
||||
# if this is a nested 'when compiles', do not increase the ID so that
|
||||
# generic instantations can still be cached for this level.
|
||||
# generic instantiations can still be cached for this level.
|
||||
if c.compilesContextId == 0:
|
||||
inc c.compilesContextIdGenerator
|
||||
c.compilesContextId = c.compilesContextIdGenerator
|
||||
@@ -2563,7 +2563,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)
|
||||
|
||||
@@ -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
|
||||
@@ -449,9 +446,10 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
result = newIntNodeT(BiggestInt(getFloat(a)), n, g)
|
||||
of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
|
||||
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
|
||||
|
||||
@@ -211,7 +211,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
param.typ = makeTypeDesc(c, header[i+1])
|
||||
|
||||
# this scope was not created by the user,
|
||||
# unused params shoudn't be reported.
|
||||
# unused params shouldn't be reported.
|
||||
param.flags.incl sfUsed
|
||||
addDecl(c, param)
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
|
||||
a.setResult opBindSym(c, scope, a.getNode(0), a.getInt(1).int, a.getNode(2))
|
||||
|
||||
let
|
||||
# altough we use VM callback here, it is not
|
||||
# although we use VM callback here, it is not
|
||||
# executed like 'normal' VM callback
|
||||
idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
|
||||
# dummy node to carry idx information to VM
|
||||
|
||||
@@ -339,7 +339,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
result = initPartial
|
||||
if discriminatorVal.kind == nkIntLit:
|
||||
# When the discriminator is a compile-time value, we also know
|
||||
# which brach will be selected:
|
||||
# which branch will be selected:
|
||||
let matchedBranch = recNode.pickCaseBranch discriminatorVal
|
||||
if matchedBranch != nil: checkMissingFields matchedBranch
|
||||
else:
|
||||
@@ -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.
|
||||
|
||||
@@ -575,7 +575,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode)
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
# sematic check doesn't allow statements after raise, break, return or
|
||||
# semantic check doesn't allow statements after raise, break, return or
|
||||
# call to noreturn proc, so it is safe to check just the last statements
|
||||
var it = n
|
||||
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||
@@ -751,7 +751,9 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
discard
|
||||
else:
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[1].typ.lastSon, n.info)
|
||||
# check required for 'nim check':
|
||||
if n[1].typ.len > 0:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[1].typ.lastSon, n.info)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
|
||||
@@ -1449,8 +1449,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 +1531,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 +1568,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 +1960,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:
|
||||
|
||||
@@ -635,6 +635,12 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
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")
|
||||
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:
|
||||
localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
|
||||
|
||||
for i in 1 ..< len(n):
|
||||
var b = copyTree(n.sons[i])
|
||||
addSon(a, b)
|
||||
@@ -871,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
|
||||
@@ -1638,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:
|
||||
|
||||
@@ -76,13 +76,13 @@ type
|
||||
c*: PContext
|
||||
typeMap*: ptr LayeredIdTable # map PType to PType
|
||||
symMap*: TIdTable # map PSym to PSym
|
||||
localCache*: TIdTable # local cache for remembering alraedy replaced
|
||||
localCache*: TIdTable # local cache for remembering already replaced
|
||||
# types during instantiation of meta types
|
||||
# (they are not stored in the global cache)
|
||||
info*: TLineInfo
|
||||
allowMetaTypes*: bool # allow types such as seq[Number]
|
||||
# i.e. the result contains unresolved generics
|
||||
skipTypedesc*: bool # wether we should skip typeDescs
|
||||
skipTypedesc*: bool # whether we should skip typeDescs
|
||||
isReturnType*: bool
|
||||
owner*: PSym # where this instantiation comes from
|
||||
recursionLimit: int
|
||||
@@ -249,7 +249,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||
return s
|
||||
|
||||
# XXX: Bound symbols in default parameter expressions may reach here.
|
||||
# We cannot process them, becase `sym.n` may point to a proc body with
|
||||
# We cannot process them, because `sym.n` may point to a proc body with
|
||||
# cyclic references that will lead to an infinite recursion.
|
||||
# Perhaps we should not use a black-list here, but a whitelist instead
|
||||
# (e.g. skGenericParam and skType).
|
||||
@@ -589,7 +589,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
for i in 0 ..< len(result):
|
||||
if result.sons[i] != nil:
|
||||
if result.sons[i].kind == tyGenericBody:
|
||||
localError(cl.c.config, t.sym.info,
|
||||
localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
|
||||
"cannot instantiate '" &
|
||||
typeToString(result.sons[i], preferDesc) &
|
||||
"' inside of type definition: '" &
|
||||
|
||||
@@ -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
|
||||
@@ -2551,13 +2554,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:
|
||||
|
||||
@@ -16,11 +16,12 @@ proc align(address, alignment: int): int =
|
||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||
|
||||
const
|
||||
## a size is concidered "unknown" when it is an imported type from C
|
||||
## a size is considered "unknown" when it is an imported type from C
|
||||
## or C++.
|
||||
szUnknownSize* = -3
|
||||
szIllegalRecursion* = -2
|
||||
szUncomputedSize* = -1
|
||||
szTooBigSize* = -4
|
||||
|
||||
type IllegalTypeRecursionError = object of Exception
|
||||
|
||||
@@ -33,14 +34,14 @@ type
|
||||
offset: int
|
||||
|
||||
proc inc(arg: var OffsetAccum; value: int) =
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if value == szUnknownSize or arg.offset == szUnknownSize:
|
||||
arg.offset = szUnknownSize
|
||||
else:
|
||||
arg.offset += value
|
||||
|
||||
proc alignmentMax(a,b: int): int =
|
||||
if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if a == szUnknownSize or b == szUnknownSize:
|
||||
szUnknownSize
|
||||
else:
|
||||
@@ -57,7 +58,7 @@ proc align(arg: var OffsetAccum; value: int) =
|
||||
|
||||
proc mergeBranch(arg: var OffsetAccum; value: OffsetAccum) =
|
||||
if value.maxAlign == szUnknownSize or arg.maxAlign == szUnknownSize or
|
||||
value.offset == szUnknownSize or arg.offset == szUnknownSize:
|
||||
value.offset == szUnknownSize or arg.offset == szUnknownSize:
|
||||
arg.maxAlign = szUnknownSize
|
||||
arg.offset = szUnknownSize
|
||||
else:
|
||||
@@ -111,7 +112,7 @@ proc setOffsetsToUnknown(n: PNode) =
|
||||
for i in 0 ..< safeLen(n):
|
||||
setOffsetsToUnknown(n[i])
|
||||
|
||||
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum): void =
|
||||
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum) =
|
||||
## ``offset`` is the offset within the object, after the node has been written, no padding bytes added
|
||||
## ``align`` maximum alignment from all sub nodes
|
||||
assert n != nil
|
||||
@@ -256,7 +257,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
typ.size = elemSize
|
||||
typ.align = int16(elemSize)
|
||||
else:
|
||||
typ.size = toInt64(lengthOrd(conf, typ.sons[0]) * int32(elemSize))
|
||||
typ.size = toInt64Checked(lengthOrd(conf, typ.sons[0]) * int32(elemSize), szTooBigSize)
|
||||
typ.align = typ.sons[1].align
|
||||
|
||||
of tyUncheckedArray:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -663,7 +663,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)
|
||||
@@ -877,7 +876,7 @@ proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNo
|
||||
# The recursion may confuse you. It performs two duties:
|
||||
#
|
||||
# 1) extracting all referenced params from default expressions
|
||||
# into a let section preceeding the call
|
||||
# into a let section preceding the call
|
||||
#
|
||||
# 2) replacing the "references" within the default expression
|
||||
# with these extracted skLet symbols.
|
||||
@@ -915,7 +914,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:
|
||||
@@ -1140,7 +1139,7 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
|
||||
|
||||
let cache = cache or prc.typ.callConv == ccInline
|
||||
if cache:
|
||||
# genProc for inline procs will be called multiple times from diffrent modules,
|
||||
# genProc for inline procs will be called multiple times from different modules,
|
||||
# it is important to transform exactly once to get sym ids and locations right
|
||||
prc.transformedBody = result
|
||||
else:
|
||||
|
||||
@@ -303,7 +303,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
|
||||
|
||||
proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult =
|
||||
# this does a complex analysis whether a call to ``objectInit`` needs to be
|
||||
# made or intializing of the type field suffices or if there is no type field
|
||||
# made or initializing of the type field suffices or if there is no type field
|
||||
# at all in this type.
|
||||
var marker = initIntSet()
|
||||
result = analyseObjectWithTypeFieldAux(t, marker)
|
||||
@@ -814,11 +814,8 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
|
||||
false
|
||||
|
||||
proc lengthOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
case t.skipTypes(tyUserTypeClasses).kind
|
||||
of tyInt64, tyInt32, tyInt:
|
||||
# XXX: this is just wrong
|
||||
result = lastOrd(conf, t)
|
||||
of tyDistinct: result = lengthOrd(conf, t.sons[0])
|
||||
if t.skipTypes(tyUserTypeClasses).kind == tyDistinct:
|
||||
result = lengthOrd(conf, t.sons[0])
|
||||
else:
|
||||
let last = lastOrd(conf, t)
|
||||
let first = firstOrd(conf, t)
|
||||
|
||||
@@ -156,7 +156,7 @@ proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
||||
x.node = newNode(nkStrLit)
|
||||
# It not only hackey, it is also wrong for tgentemplate. The primary
|
||||
# cause of bugs like these is that the VM does not properly distinguish
|
||||
# between variable defintions (var foo = e) and variable updates (foo = e).
|
||||
# between variable definitions (var foo = e) and variable updates (foo = e).
|
||||
|
||||
include vmhooks
|
||||
|
||||
@@ -357,7 +357,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||
result = -1
|
||||
|
||||
# Traverse the stack starting from the end in order to execute the blocks in
|
||||
# the inteded order
|
||||
# the intended order
|
||||
for i in 1 .. f.safePoints.len:
|
||||
var pc = f.safePoints[^i]
|
||||
# Skip the `except` blocks
|
||||
@@ -436,12 +436,8 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
|
||||
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
|
||||
|
||||
var value = cast[BiggestUInt](src.intVal)
|
||||
when system.cpuEndian == bigEndian:
|
||||
value = (value shr srcDist) shl srcDist
|
||||
value = (value shr destDist) shl destDist
|
||||
else:
|
||||
value = (value shl srcDist) shr srcDist
|
||||
value = (value shl destDist) shr destDist
|
||||
value = (value shl srcDist) shr srcDist
|
||||
value = (value shl destDist) shr destDist
|
||||
dest.intVal = cast[BiggestInt](value)
|
||||
of tyFloat..tyFloat64:
|
||||
if dest.kind != rkFloat:
|
||||
@@ -475,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
|
||||
|
||||
@@ -714,7 +711,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of rkNode:
|
||||
if regs[ra].node.kind == nkNilLit:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
assert nfIsRef in regs[ra].node.flags
|
||||
regs[ra].node[] = regs[rc].regToNode[]
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
else: stackTrace(c, tos, pc, errNilAccess)
|
||||
@@ -1189,7 +1185,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
tos.pushSafePoint(pc + rbx)
|
||||
assert c.code[pc+rbx].opcode in {opcExcept, opcFinally}
|
||||
of opcExcept:
|
||||
# This opcode is never executed, it only holds informations for the
|
||||
# This opcode is never executed, it only holds information for the
|
||||
# exception handling routines.
|
||||
doAssert(false)
|
||||
of opcFinally:
|
||||
@@ -1275,7 +1271,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
|
||||
# opcLdNull really is the gist of the VM's problems: should it load
|
||||
# a fresh null to regs[ra].node or to regs[ra].node[]? This really
|
||||
# depends on whether regs[ra] represents the variable itself or wether
|
||||
# depends on whether regs[ra] represents the variable itself or whether
|
||||
# it holds the indirection! Due to the way registers are re-used we cannot
|
||||
# say for sure here! --> The codegen has to deal with it
|
||||
# via 'genAsgnPatch'.
|
||||
@@ -1567,19 +1563,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
|
||||
c.module, c.config)
|
||||
of opcGorge:
|
||||
decodeBC(rkNode)
|
||||
inc pc
|
||||
let rd = c.code[pc].regA
|
||||
createStr regs[ra]
|
||||
if defined(nimsuggest) or c.config.cmd == cmdCheck:
|
||||
discard "don't run staticExec for 'nim suggest'"
|
||||
regs[ra].node.strVal = ""
|
||||
else:
|
||||
when defined(nimcore):
|
||||
decodeBC(rkNode)
|
||||
inc pc
|
||||
let rd = c.code[pc].regA
|
||||
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
|
||||
regs[rc].node.strVal, regs[rd].node.strVal,
|
||||
c.debug[pc], c.config)[0]
|
||||
else:
|
||||
regs[ra].node.strVal = ""
|
||||
globalError(c.config, c.debug[pc], "VM is not built with 'gorge' support")
|
||||
of opcNError, opcNWarning, opcNHint:
|
||||
decodeB(rkNode)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -127,7 +127,7 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||
ctx.debug.add(n.info)
|
||||
|
||||
proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
|
||||
# Takes the `b` register and the immediate `imm`, appies the operation `opc`,
|
||||
# Takes the `b` register and the immediate `imm`, applies the operation `opc`,
|
||||
# and stores the output value into `a`.
|
||||
# `imm` is signed and must be within [-128, 127]
|
||||
if imm >= -128 and imm <= 127:
|
||||
@@ -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
|
||||
@@ -278,7 +290,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 +349,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 +774,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 +785,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])
|
||||
@@ -948,9 +972,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.genAddSubInt(n, dest, opcAddInt)
|
||||
of mInc, mDec:
|
||||
unused(c, n, dest)
|
||||
let opc = if m == mInc: opcAddInt else: opcSubInt
|
||||
let isUnsigned = n.sons[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64}
|
||||
let opc = if not isUnsigned:
|
||||
if m == mInc: opcAddInt else: opcSubInt
|
||||
else:
|
||||
if m == mInc: opcAddu else: opcSubu
|
||||
let d = c.genx(n.sons[1])
|
||||
if n.sons[2].isInt8Lit:
|
||||
if n.sons[2].isInt8Lit and not isUnsigned:
|
||||
c.gABI(n, succ(opc), d, d, n.sons[2].intVal)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[2])
|
||||
@@ -1081,6 +1109,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))
|
||||
@@ -1316,7 +1345,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mMove:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
assert dest >= 0
|
||||
if dest < 0: dest = c.getTemp(arg.typ)
|
||||
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a)
|
||||
# XXX use ldNullOpcode() here?
|
||||
@@ -1421,6 +1449,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)
|
||||
@@ -1431,13 +1460,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: " &
|
||||
@@ -1460,7 +1483,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)
|
||||
@@ -1498,6 +1524,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})
|
||||
@@ -1505,17 +1533,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)
|
||||
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)
|
||||
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
|
||||
@@ -1529,7 +1561,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}:
|
||||
@@ -1542,6 +1574,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)
|
||||
@@ -1608,7 +1641,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)
|
||||
@@ -1625,8 +1658,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)
|
||||
@@ -1679,6 +1712,7 @@ 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)
|
||||
@@ -1712,11 +1746,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:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# Unforunately this cannot be a module yet:
|
||||
# Unfortunately this cannot be a module yet:
|
||||
#import vmdeps, vm
|
||||
from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
|
||||
arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
|
||||
@@ -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",
|
||||
|
||||
@@ -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>`_
|
||||
|
||||
31
doc/gc.rst
31
doc/gc.rst
@@ -119,9 +119,12 @@ procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them
|
||||
being freed by the GC. Other useful procs from `system <system.html>`_ you can
|
||||
use to keep track of memory are:
|
||||
|
||||
* getTotalMem(): returns the amount of total memory managed by the GC.
|
||||
* getOccupiedMem(): bytes reserved by the GC and used by objects.
|
||||
* getFreeMem(): bytes reserved by the GC and not in use.
|
||||
* ``getTotalMem()`` Returns the amount of total memory managed by the GC.
|
||||
* ``getOccupiedMem()`` Bytes reserved by the GC and used by objects.
|
||||
* ``getFreeMem()`` Bytes reserved by the GC and not in use.
|
||||
|
||||
These numbers are usually only for the running thread, not for the whole heap,
|
||||
with the exception of ``--gc:boehm`` and ``--gc:go``.
|
||||
|
||||
In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually
|
||||
allocating memory with procs like ``alloc``, ``allocShared``, or
|
||||
@@ -144,3 +147,25 @@ The numbers count the number of objects in all GC heaps, they refer to
|
||||
all running threads, not only to the current thread. (The current thread
|
||||
would be the thread that calls ``dumpNumberOfInstances``.) This might
|
||||
change in later versions.
|
||||
|
||||
|
||||
Garbage collector options
|
||||
-------------------------
|
||||
|
||||
You can choose which garbage collector to use when compiling source code,
|
||||
you can pass ``--gc:`` on the compile command with the choosed garbage collector.
|
||||
|
||||
- ``--gc:refc`` Deferred `reference counting <https://en.wikipedia.org/wiki/Reference_counting>`_ with cycle detection, `thread local heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_, default.
|
||||
- ``--gc:markAndSweep`` `Mark-And-Sweep <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Copying_vs._mark-and-sweep_vs._mark-and-don't-sweep>`_ based garbage collector, `thread local heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--gc:boehm`` `Boehm <https://en.wikipedia.org/wiki/Boehm_garbage_collector>`_ based garbage collector, `stop-the-world <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Stop-the-world_vs._incremental_vs._concurrent>`_, `shared heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--gc:go`` Go lang like garbage collector, `stop-the-world <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Stop-the-world_vs._incremental_vs._concurrent>`_, `shared heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--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 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -450,9 +450,6 @@ Miscellaneous
|
||||
* `logging <logging.html>`_
|
||||
This module implements a simple logger.
|
||||
|
||||
* `quitprocs <quitprocs>`_
|
||||
Better implementation of ``system.addQuitProc``.
|
||||
|
||||
* `segfaults <segfaults.html>`_
|
||||
Turns access violations or segfaults into a ``NilAccessError`` exception.
|
||||
|
||||
@@ -531,7 +528,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
|
||||
-------------------
|
||||
|
||||
@@ -1479,7 +1479,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
|
||||
|
||||
@@ -2129,7 +2130,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>`_.
|
||||
|
||||
|
||||
@@ -2640,7 +2641,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 +3185,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 +3205,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
|
||||
----------
|
||||
@@ -3481,8 +3496,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,14 +3517,14 @@ 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
|
||||
---------------
|
||||
|
||||
Procs can also be treated as expressions, in which case it's allowed to omit
|
||||
the proc's name.
|
||||
Unnamed procedures can be used as lambda expressions to pass into other
|
||||
procedures:
|
||||
|
||||
.. code-block:: nim
|
||||
var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"]
|
||||
@@ -3519,7 +3534,9 @@ the proc's name.
|
||||
|
||||
|
||||
Procs as expressions can appear both as nested procs and inside top level
|
||||
executable code.
|
||||
executable code. The `sugar <sugar.html>`_ module contains the `=>` macro
|
||||
which enables a more succinct syntax for anonymous procedures resembling
|
||||
lambdas as they are in languages like JavaScript, C#, etc.
|
||||
|
||||
|
||||
Func
|
||||
@@ -3691,7 +3708,7 @@ type.
|
||||
|
||||
method eval(e: Expression): int {.base.} =
|
||||
# override this base method
|
||||
quit "to override!"
|
||||
raise newException(CatchableError, "Method without implementation override")
|
||||
|
||||
method eval(e: Literal): int = return e.x
|
||||
|
||||
@@ -5890,9 +5907,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:
|
||||
|
||||
@@ -6163,7 +6180,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
|
||||
@@ -6219,6 +6237,25 @@ but are used to override the settings temporarily. Example:
|
||||
# ... some code ...
|
||||
{.pop.} # restore old settings
|
||||
|
||||
`push/pop`:idx: can switch on/off some standard library pragmas, example:
|
||||
|
||||
.. code-block:: nim
|
||||
{.push inline.}
|
||||
proc thisIsInlined(): int = 42
|
||||
func willBeInlined(): float = 42.0
|
||||
{.pop.}
|
||||
proc notInlined(): int = 9
|
||||
|
||||
{.push discardable, boundChecks: off, compileTime, noSideEffect, experimental.}
|
||||
template example(): string = "https://nim-lang.org"
|
||||
{.pop.}
|
||||
|
||||
{.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.}
|
||||
proc sample(): bool = true
|
||||
{.pop.}
|
||||
|
||||
For third party pragmas it depends on its implementation, but uses the same syntax.
|
||||
|
||||
|
||||
register pragma
|
||||
---------------
|
||||
@@ -6326,12 +6363,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
|
||||
@@ -6595,15 +6638,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
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -6786,6 +6820,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
|
||||
@@ -7008,7 +7051,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".}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
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>`_
|
||||
|
||||
93
doc/tut1.rst
93
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.
|
||||
|
||||
@@ -142,15 +142,6 @@ comments can also be nested.
|
||||
]#
|
||||
]#
|
||||
|
||||
You can also use the `discard statement <#procedures-discard-statement>`_ together with *long string
|
||||
literals* to create block comments:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
discard """ You can have any Nim code text commented
|
||||
out inside this with no indentation restrictions.
|
||||
yes("May I ask a pointless question?") """
|
||||
|
||||
|
||||
Numbers
|
||||
-------
|
||||
@@ -335,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
|
||||
@@ -368,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"
|
||||
@@ -380,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: "
|
||||
@@ -400,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:
|
||||
@@ -579,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"
|
||||
@@ -762,7 +754,7 @@ Nim provides the ability to overload procedures similar to C++:
|
||||
echo toString(13) # calls the toString(x: int) proc
|
||||
echo toString(true) # 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
|
||||
@@ -854,8 +846,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 =
|
||||
@@ -1019,8 +1011,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
|
||||
@@ -1040,13 +1032,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:
|
||||
|
||||
@@ -1136,9 +1128,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.)
|
||||
|
||||
|
||||
@@ -1159,8 +1151,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.
|
||||
@@ -1198,8 +1190,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"
|
||||
@@ -1274,9 +1267,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
|
||||
@@ -1327,10 +1320,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"
|
||||
@@ -1386,8 +1379,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.
|
||||
|
||||
|
||||
@@ -1570,8 +1563,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
|
||||
|
||||
12
koch.nim
12
koch.nim
@@ -169,6 +169,10 @@ proc bundleNimsuggest(args: string) =
|
||||
proc buildVccTool(args: string) =
|
||||
nimCompileFold("Compile Vcc", "tools/vccexe/vccexe.nim ", options = args)
|
||||
|
||||
proc bundleNimpretty(args: string) =
|
||||
nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim",
|
||||
options = "-d:release " & args)
|
||||
|
||||
proc bundleWinTools(args: string) =
|
||||
nimCompile("tools/finish.nim", outputDir = "", options = args)
|
||||
|
||||
@@ -185,6 +189,7 @@ proc bundleWinTools(args: string) =
|
||||
proc zip(latest: bool; args: string) =
|
||||
bundleNimbleExe(latest, args)
|
||||
bundleNimsuggest(args)
|
||||
bundleNimpretty(args)
|
||||
bundleWinTools(args)
|
||||
nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
|
||||
[VersionAsString, compileNimInst])
|
||||
@@ -214,8 +219,7 @@ proc buildTools(args: string = "") =
|
||||
nimCompileFold("Compile nimgrep", "tools/nimgrep.nim",
|
||||
options = "-d:release " & args)
|
||||
when defined(windows): buildVccTool(args)
|
||||
nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim",
|
||||
options = "-d:release " & args)
|
||||
bundleNimpretty(args)
|
||||
nimCompileFold("Compile nimfind", "tools/nimfind.nim",
|
||||
options = "-d:release " & args)
|
||||
nimCompileFold("Compile testament", "testament/testament.nim",
|
||||
@@ -316,8 +320,8 @@ proc boot(args: string) =
|
||||
# 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, smartNimcache]
|
||||
exec "$# jsonscript $# --nimcache:$# compiler" / "nim.nim" %
|
||||
[nimi, args, smartNimcache]
|
||||
|
||||
if sameFileContent(output, i.thVersion):
|
||||
copyExe(output, finalDest)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -121,13 +121,13 @@ type
|
||||
|
||||
type
|
||||
NimIdent* {.deprecated.} = object of RootObj
|
||||
## represents a Nim identifier in the AST. **Note**: This is only
|
||||
## Represents a Nim identifier in the AST. **Note**: This is only
|
||||
## rarely useful, for identifier construction from a string
|
||||
## use ``ident"abc"``.
|
||||
|
||||
NimSymObj = object # hidden
|
||||
NimSym* {.deprecated.} = ref NimSymObj
|
||||
## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## Represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## *ident*.
|
||||
|
||||
|
||||
@@ -141,45 +141,46 @@ const
|
||||
|
||||
proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".}
|
||||
## constructs an identifier from the string `s`
|
||||
## Constructs an identifier from the string `s`.
|
||||
|
||||
proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".}
|
||||
## constructs an identifier from the string `s`
|
||||
## Constructs an identifier from the string `s`.
|
||||
|
||||
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use '==' on 'NimNode' instead.".}
|
||||
## compares two Nim identifiers
|
||||
## Compares two Nim identifiers.
|
||||
|
||||
proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
||||
## compares two Nim nodes
|
||||
## Compare two Nim nodes. Return true if nodes are structurally
|
||||
## equivalent. This means two independently created nodes can be equal.
|
||||
|
||||
proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use '==(NimNode, NimNode)' instead.".}
|
||||
## compares two Nim symbols
|
||||
## Compares two Nim symbols.
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
|
||||
## compares two Nim nodes' types. Return true if the types are the same,
|
||||
## Compares two Nim nodes' types. Return true if the types are the same,
|
||||
## eg. true when comparing alias with original type.
|
||||
discard
|
||||
|
||||
proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
|
||||
## returns the number of children of `n`.
|
||||
## Returns the number of children of `n`.
|
||||
|
||||
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
|
||||
## get `n`'s `i`'th child.
|
||||
## Get `n`'s `i`'th child.
|
||||
|
||||
proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
|
||||
## get `n`'s `i`'th child.
|
||||
## Get `n`'s `i`'th child.
|
||||
|
||||
template `^^`(n: NimNode, i: untyped): untyped =
|
||||
(when i is BackwardsIndex: n.len - int(i) else: int(i))
|
||||
|
||||
proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
|
||||
## slice operation for NimNode.
|
||||
## returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
|
||||
## Slice operation for NimNode.
|
||||
## Returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
|
||||
let xa = n ^^ x.a
|
||||
let L = (n ^^ x.b) - xa + 1
|
||||
result = newSeq[NimNode](L)
|
||||
@@ -188,10 +189,10 @@ proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
|
||||
|
||||
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
|
||||
noSideEffect.}
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
## Set `n`'s `i`'th child to `child`.
|
||||
|
||||
proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
## Set `n`'s `i`'th child to `child`.
|
||||
n[n.len - i.int] = child
|
||||
|
||||
template `or`*(x, y: NimNode): NimNode =
|
||||
@@ -220,10 +221,10 @@ proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
|
||||
## Returns the `father` node so that calls can be nested.
|
||||
|
||||
proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
|
||||
## deletes `n` children of `father` starting at index `idx`.
|
||||
## Deletes `n` children of `father` starting at index `idx`.
|
||||
|
||||
proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
|
||||
## returns the `kind` of the node `n`.
|
||||
## Returns the `kind` of the node `n`.
|
||||
|
||||
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
|
||||
## Returns an integer value from any integer literal or enum field symbol.
|
||||
@@ -244,17 +245,20 @@ proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated:
|
||||
when defined(nimSymKind):
|
||||
proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.}
|
||||
proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.}
|
||||
## Returns a copy of the declaration of a symbol or `nil`.
|
||||
proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
|
||||
## retrieve the implementation of `symbol`. `symbol` can be a
|
||||
## routine or a const.
|
||||
## Returns the string value of an identifier, symbol, comment, or string literal.
|
||||
##
|
||||
## See also:
|
||||
## * `strVal= proc<#strVal=,NimNode,string>`_ for setting the string value.
|
||||
|
||||
proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use 'strVal' instead.".}
|
||||
## converts a Nim identifier to a string
|
||||
## Converts a Nim identifier to a string.
|
||||
|
||||
proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use 'strVal' instead.".}
|
||||
## converts a Nim symbol to a string
|
||||
## Converts a Nim symbol to a string.
|
||||
|
||||
else: # bootstrapping substitute
|
||||
proc getImpl*(symbol: NimNode): NimNode =
|
||||
@@ -278,22 +282,28 @@ else: # bootstrapping substitute
|
||||
|
||||
when defined(nimSymImplTransform):
|
||||
proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.}
|
||||
## for a typed proc returns the AST after transformation pass
|
||||
## For a typed proc returns the AST after transformation pass.
|
||||
|
||||
when defined(nimHasSymOwnerInMacro):
|
||||
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
||||
## accepts node of kind nnkSym and returns its owner's symbol.
|
||||
## result is also mnde of kind nnkSym if owner exists otherwise
|
||||
## nnkNilLit is returned
|
||||
## Accepts a node of kind `nnkSym` and returns its owner's symbol.
|
||||
## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration
|
||||
## context. For top level declarations this is an `nskModule` symbol,
|
||||
## for proc local variables an `nskProc` symbol, for enum/object fields an
|
||||
## `nskType` symbol, etc. For symbols without an owner, `nil` is returned.
|
||||
##
|
||||
## See also:
|
||||
## * `symKind proc<#symKind,NimNode>`_ to get the kind of a symbol
|
||||
## * `getImpl proc<#getImpl,NimNode>`_ to get the declaration of a symbol
|
||||
|
||||
when defined(nimHasInstantiationOfInMacro):
|
||||
proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.}
|
||||
## check if proc symbol is instance of the generic proc symbol
|
||||
## useful to check proc symbols against generic symbols
|
||||
## returned by `bindSym`
|
||||
## Checks if a proc symbol is an instance of the generic proc symbol.
|
||||
## Useful to check proc symbols against generic symbols
|
||||
## returned by `bindSym`.
|
||||
|
||||
proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## with 'getType' you can access the node's `type`:idx:. A Nim type is
|
||||
## With 'getType' you can access the node's `type`:idx:. A Nim type is
|
||||
## mapped to a Nim AST too, so it's slightly confusing but it means the same
|
||||
## API can be used to traverse types. Recursive types are flattened for you
|
||||
## so there is no danger of infinite recursions during traversal. To
|
||||
@@ -301,10 +311,7 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## kind of type it is, call `typeKind` on getType's result.
|
||||
|
||||
proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## Returns the Nim type node for given type. This can be used to turn macro
|
||||
## typedesc parameter into proper NimNode representing type, since typedesc
|
||||
## are an exception in macro calls - they are not mapped implicitly to
|
||||
## NimNode like any other arguments.
|
||||
## Version of ``getType`` which takes a ``typedesc``.
|
||||
|
||||
proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
|
||||
## Returns the type kind of the node 'n' that should represent a type, that
|
||||
@@ -333,8 +340,8 @@ proc getTypeInst*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
|
||||
proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} =
|
||||
## Returns the `type`:idx: of a node in a form matching the implementation
|
||||
## of the type. Any intermediate aliases are expanded to arrive at the final
|
||||
## type implementation. You can instead use ``getImpl`` on a symbol if you
|
||||
## of the type. Any intermediate aliases are expanded to arrive at the final
|
||||
## type implementation. You can instead use ``getImpl`` on a symbol if you
|
||||
## want to find the intermediate aliases.
|
||||
runnableExamples:
|
||||
type
|
||||
@@ -364,7 +371,7 @@ when defined(nimHasSignatureHashInMacro):
|
||||
|
||||
proc symBodyHash*(s: NimNode): string {.noSideEffect.} =
|
||||
## Returns a stable digest for symbols derived not only from type signature
|
||||
## and owning module, but also implementation body. All procs/varibles used in
|
||||
## and owning module, but also implementation body. All procs/variables used in
|
||||
## the implementation of this symbol are hashed recursively as well, including
|
||||
## magics from system module.
|
||||
discard
|
||||
@@ -393,6 +400,14 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, de
|
||||
# bracket[0] = fake # constructs a mixed array with ints and floats!
|
||||
|
||||
proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
|
||||
## Sets the string value of a string literal or comment.
|
||||
## Setting `strVal` is disallowed for `nnkIdent` and `nnkSym` nodes; a new node
|
||||
## must be created using `ident` or `bindSym` instead.
|
||||
##
|
||||
## See also:
|
||||
## * `strVal proc<#strVal,NimNode>`_ for getting the string value.
|
||||
## * `ident proc<#ident,string>`_ for creating an identifier.
|
||||
## * `bindSym proc<#bindSym%2C%2CBindSymRule>`_ for binding a symbol.
|
||||
|
||||
proc newNimNode*(kind: NimNodeKind,
|
||||
lineInfoFrom: NimNode = nil): NimNode
|
||||
@@ -407,47 +422,47 @@ proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
|
||||
proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
|
||||
|
||||
proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
|
||||
## writes an error message at compile time. The optional ``n: NimNode``
|
||||
## Writes an error message at compile time. The optional ``n: NimNode``
|
||||
## parameter is used as the source for file and line number information in
|
||||
## the compilation error message.
|
||||
|
||||
proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.}
|
||||
## writes a warning message at compile time
|
||||
## Writes a warning message at compile time.
|
||||
|
||||
proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.}
|
||||
## writes a hint message at compile time
|
||||
## Writes a hint message at compile time.
|
||||
|
||||
proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||
## creates a string literal node from `s`
|
||||
## Creates a string literal node from `s`.
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||
## creates a comment statement node
|
||||
## Creates a comment statement node.
|
||||
result = newNimNode(nnkCommentStmt)
|
||||
result.strVal = s
|
||||
|
||||
proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
|
||||
## creates a int literal node from `i`
|
||||
## Creates an int literal node from `i`.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} =
|
||||
## creates a float literal node from `f`
|
||||
## Creates a float literal node from `f`.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
result.floatVal = f
|
||||
|
||||
{.push warnings: off.}
|
||||
|
||||
proc newIdentNode*(i: NimIdent): NimNode {.compileTime, deprecated.} =
|
||||
## creates an identifier node from `i`
|
||||
## Creates an identifier node from `i`.
|
||||
result = newNimNode(nnkIdent)
|
||||
result.ident = i
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect, compilerproc.}
|
||||
## creates an identifier node from `i`. It is simply an alias for
|
||||
## Creates an identifier node from `i`. It is simply an alias for
|
||||
## ``ident(string)``. Use that, it's shorter.
|
||||
|
||||
|
||||
@@ -463,35 +478,35 @@ type
|
||||
|
||||
proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
|
||||
magic: "NBindSym", noSideEffect.}
|
||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## Ceates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## may be an overloaded symbol.
|
||||
## if `ident` is a NimNode, it must have nkIdent kind.
|
||||
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||
## if `ident` is a NimNode, it must have ``nnkIdent`` kind.
|
||||
## If ``rule == brClosed`` either an ``nnkClosedSymChoice`` tree is
|
||||
## returned or ``nnkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brOpen`` either an ``nnkOpenSymChoice`` tree is
|
||||
## returned or ``nnkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brForceOpen`` always an ``nnkOpenSymChoice`` tree is
|
||||
## returned even if the symbol is not ambiguous.
|
||||
##
|
||||
## experimental feature:
|
||||
## use {.experimental: "dynamicBindSym".} to activate it
|
||||
## if called from template / regular code, `ident` and `rule` must be
|
||||
## Experimental feature:
|
||||
## use {.experimental: "dynamicBindSym".} to activate it.
|
||||
## If called from template / regular code, `ident` and `rule` must be
|
||||
## constant expression / literal value.
|
||||
## if called from macros / compile time procs / static blocks,
|
||||
## If called from macros / compile time procs / static blocks,
|
||||
## `ident` and `rule` can be VM computed value.
|
||||
|
||||
proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
|
||||
magic: "NGenSym", noSideEffect.}
|
||||
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## Generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## needs to occur in a declaration context.
|
||||
|
||||
proc callsite*(): NimNode {.magic: "NCallSite", benign, deprecated:
|
||||
"Deprecated since v0.18.1; use varargs[untyped] in the macro prototype instead".}
|
||||
## returns the AST of the invocation expression that invoked this macro.
|
||||
## Returns the AST of the invocation expression that invoked this macro.
|
||||
|
||||
proc toStrLit*(n: NimNode): NimNode {.compileTime.} =
|
||||
## converts the AST `n` to the concrete Nim code and wraps that
|
||||
## in a string literal node
|
||||
## Converts the AST `n` to the concrete Nim code and wraps that
|
||||
## in a string literal node.
|
||||
return newStrLitNode(repr(n))
|
||||
|
||||
type
|
||||
@@ -500,27 +515,29 @@ type
|
||||
line*,column*: int
|
||||
|
||||
proc `$`*(arg: LineInfo): string =
|
||||
## Return a string representation in the form `filepath(line, column)`.
|
||||
# BUG: without `result = `, gives compile error
|
||||
result = arg.filename & "(" & $arg.line & ", " & $arg.column & ")"
|
||||
|
||||
#proc lineinfo*(n: NimNode): LineInfo {.magic: "NLineInfo", noSideEffect.}
|
||||
## returns the position the node appears in the original source file
|
||||
## in the form filename(line, col)
|
||||
# ## returns the position the node appears in the original source file
|
||||
# ## in the form filename(line, col)
|
||||
|
||||
proc getLine(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||
proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||
proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
|
||||
|
||||
proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
|
||||
## copy lineinfo from info node
|
||||
## Copy lineinfo from ``info``.
|
||||
|
||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
||||
## returns ``LineInfo`` of ``n``, using absolute path for ``filename``
|
||||
## Returns ``LineInfo`` of ``n``, using absolute path for ``filename``.
|
||||
result.filename = n.getFile
|
||||
result.line = n.getLine
|
||||
result.column = n.getColumn
|
||||
|
||||
proc lineInfo*(arg: NimNode): string {.compileTime.} =
|
||||
## Return line info in the form `filepath(line, column)`.
|
||||
$arg.lineInfoObj
|
||||
|
||||
proc internalParseExpr(s: string): NimNode {.
|
||||
@@ -586,25 +603,25 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
|
||||
## echo `info` & ": Check failed: " & `expString`
|
||||
|
||||
proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## Checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind, n)
|
||||
|
||||
proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
|
||||
## checks that `n` has at least `min` children. If this is not the case,
|
||||
## Checks that `n` has at least `min` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len < min: error("macro expects a node with " & $min & " children", n)
|
||||
|
||||
proc expectLen*(n: NimNode, len: int) {.compileTime.} =
|
||||
## checks that `n` has exactly `len` children. If this is not the case,
|
||||
## Checks that `n` has exactly `len` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len != len: error("macro expects a node with " & $len & " children", n)
|
||||
|
||||
proc expectLen*(n: NimNode, min, max: int) {.compileTime.} =
|
||||
## checks that `n` has a number of children in the range ``min..max``.
|
||||
## Checks that `n` has a number of children in the range ``min..max``.
|
||||
## If this is not the case, compilation aborts with an error message.
|
||||
## This is useful for writing macros that check its number of arguments.
|
||||
if n.len < min or n.len > max:
|
||||
@@ -612,13 +629,13 @@ proc expectLen*(n: NimNode, min, max: int) {.compileTime.} =
|
||||
|
||||
proc newTree*(kind: NimNodeKind,
|
||||
children: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new node with children.
|
||||
## Produces a new node with children.
|
||||
result = newNimNode(kind)
|
||||
result.add(children)
|
||||
|
||||
proc newCall*(theProc: NimNode,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(theProc)
|
||||
@@ -628,7 +645,7 @@ proc newCall*(theProc: NimNode,
|
||||
|
||||
proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, deprecated:
|
||||
"Deprecated since v0.18.1; use 'newCall(string, ...)' or 'newCall(NimNode, ...)' instead".} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
@@ -638,91 +655,96 @@ proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime,
|
||||
|
||||
proc newCall*(theProc: string,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
result.add(args)
|
||||
|
||||
proc newLit*(c: char): NimNode {.compileTime.} =
|
||||
## produces a new character literal node.
|
||||
## Produces a new character literal node.
|
||||
result = newNimNode(nnkCharLit)
|
||||
result.intVal = ord(c)
|
||||
|
||||
proc newLit*(i: int): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int8): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt8Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int16): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt16Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int32): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt32Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int64): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt64Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: uint): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUIntLit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint8): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt8Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint16): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt16Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint32): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt32Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint64): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt64Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||
## produces a new boolean literal node.
|
||||
## 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.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
result.floatVal = f
|
||||
|
||||
proc newLit*(f: float32): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat32Lit)
|
||||
result.floatVal = f
|
||||
|
||||
proc newLit*(f: float64): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat64Lit)
|
||||
result.floatVal = f
|
||||
|
||||
when declared(float128):
|
||||
proc newLit*(f: float128): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat128Lit)
|
||||
result.floatVal = f
|
||||
|
||||
@@ -770,13 +792,8 @@ 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:
|
||||
## Nests the list `pack` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
|
||||
## This is also known as fold expression.
|
||||
if pack.len < 1:
|
||||
@@ -786,7 +803,7 @@ proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} =
|
||||
result = newCall(op, pack[i], result)
|
||||
|
||||
proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} =
|
||||
## nests the list `pack` into a tree of call expressions:
|
||||
## Nests the list `pack` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
|
||||
## This is also known as fold expression.
|
||||
result = init
|
||||
@@ -973,37 +990,37 @@ macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
|
||||
## Deprecated. Use `dumpLisp` instead.
|
||||
|
||||
proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
|
||||
## Create a new empty node
|
||||
## Create a new empty node.
|
||||
result = newNimNode(nnkEmpty)
|
||||
|
||||
proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}=
|
||||
## Create a new statement list
|
||||
## Create a new statement list.
|
||||
result = newNimNode(nnkStmtList).add(stmts)
|
||||
|
||||
proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}=
|
||||
## Create a new parentheses-enclosed expression
|
||||
## Create a new parentheses-enclosed expression.
|
||||
newNimNode(nnkPar).add(exprs)
|
||||
|
||||
proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new block statement with label
|
||||
## Create a new block statement with label.
|
||||
return newNimNode(nnkBlockStmt).add(label, body)
|
||||
|
||||
proc newBlockStmt*(body: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new block: stmt
|
||||
## Create a new block: stmt.
|
||||
return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
|
||||
|
||||
proc newVarStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new var stmt
|
||||
## Create a new var stmt.
|
||||
return newNimNode(nnkVarSection).add(
|
||||
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
proc newLetStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new let stmt
|
||||
## Create a new let stmt.
|
||||
return newNimNode(nnkLetSection).add(
|
||||
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new const stmt
|
||||
## Create a new const stmt.
|
||||
newNimNode(nnkConstSection).add(
|
||||
newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
@@ -1011,13 +1028,13 @@ proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} =
|
||||
return newNimNode(nnkAsgn).add(lhs, rhs)
|
||||
|
||||
proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} =
|
||||
## Create new dot expression
|
||||
## a.dot(b) -> `a.b`
|
||||
## Create new dot expression.
|
||||
## a.dot(b) -> `a.b`
|
||||
return newNimNode(nnkDotExpr).add(a, b)
|
||||
|
||||
proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} =
|
||||
## Create new colon expression
|
||||
## newColonExpr(a, b) -> `a: b`
|
||||
## Create new colon expression.
|
||||
## newColonExpr(a, b) -> `a: b`
|
||||
newNimNode(nnkExprColonExpr).add(a, b)
|
||||
|
||||
proc newIdentDefs*(name, kind: NimNode;
|
||||
@@ -1053,11 +1070,11 @@ proc newIdentDefs*(name, kind: NimNode;
|
||||
newNimNode(nnkIdentDefs).add(name, kind, default)
|
||||
|
||||
proc newNilLit*(): NimNode {.compileTime.} =
|
||||
## New nil literal shortcut
|
||||
## New nil literal shortcut.
|
||||
result = newNimNode(nnkNilLit)
|
||||
|
||||
proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1]
|
||||
## Return the last item in nodes children. Same as `node[^1]`
|
||||
## Return the last item in nodes children. Same as `node[^1]`.
|
||||
|
||||
|
||||
const
|
||||
@@ -1068,7 +1085,7 @@ const
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
|
||||
proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## Checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind notin k: error("Expected one of " & $k & ", got " & $n.kind, n)
|
||||
@@ -1078,7 +1095,7 @@ proc newProc*(name = newEmptyNode();
|
||||
body: NimNode = newStmtList();
|
||||
procType = nnkProcDef;
|
||||
pragmas: NimNode = newEmptyNode()): NimNode {.compileTime.} =
|
||||
## shortcut for creating a new proc
|
||||
## Shortcut for creating a new proc.
|
||||
##
|
||||
## The ``params`` array must start with the return type of the proc,
|
||||
## followed by a list of IdentDefs which specify the params.
|
||||
@@ -1156,7 +1173,7 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode],
|
||||
return typeSect
|
||||
|
||||
proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
|
||||
## Copy all children from `src` to `dest`
|
||||
## Copy all children from `src` to `dest`.
|
||||
for i in 0 ..< src.len:
|
||||
dest.add src[i].copyNimTree
|
||||
|
||||
@@ -1189,15 +1206,15 @@ proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
|
||||
someProc[3] = params
|
||||
|
||||
proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
|
||||
## Get the pragma of a proc type
|
||||
## These will be expanded
|
||||
## Get the pragma of a proc type.
|
||||
## These will be expanded.
|
||||
if someProc.kind == nnkProcTy:
|
||||
result = someProc[1]
|
||||
else:
|
||||
someProc.expectRoutine
|
||||
result = someProc[4]
|
||||
proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}=
|
||||
## Set the pragma of a proc type
|
||||
## Set the pragma of a proc type.
|
||||
expectKind(val, {nnkEmpty, nnkPragma})
|
||||
if someProc.kind == nnkProcTy:
|
||||
someProc[1] = val
|
||||
@@ -1206,7 +1223,7 @@ proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}=
|
||||
someProc[4] = val
|
||||
|
||||
proc addPragma*(someProc, pragma: NimNode) {.compileTime.} =
|
||||
## Adds pragma to routine definition
|
||||
## Adds pragma to routine definition.
|
||||
someProc.expectKind(RoutineNodes + {nnkProcTy})
|
||||
var pragmaNode = someProc.pragma
|
||||
if pragmaNode.isNil or pragmaNode.kind == nnkEmpty:
|
||||
@@ -1242,7 +1259,7 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
|
||||
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
|
||||
|
||||
proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
## Get the string of an identifier node
|
||||
## Get the string of an identifier node.
|
||||
case node.kind
|
||||
of nnkPostfix:
|
||||
result = node.basename.strVal & "*"
|
||||
@@ -1256,7 +1273,7 @@ proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
badNodeKind node, "$"
|
||||
|
||||
proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.}
|
||||
## Create a new ident node from a string
|
||||
## Create a new ident node from a string.
|
||||
|
||||
iterator items*(n: NimNode): NimNode {.inline.} =
|
||||
## Iterates over the children of the NimNode ``n``.
|
||||
@@ -1288,22 +1305,22 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} =
|
||||
res
|
||||
|
||||
proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
|
||||
## Insert node B into A at pos
|
||||
## Insert node ``b`` into node ``a`` at ``pos``.
|
||||
if len(a)-1 < pos:
|
||||
## add some empty nodes first
|
||||
# add some empty nodes first
|
||||
for i in len(a)-1..pos-2:
|
||||
a.add newEmptyNode()
|
||||
a.add b
|
||||
else:
|
||||
## push the last item onto the list again
|
||||
## and shift each item down to pos up one
|
||||
# push the last item onto the list again
|
||||
# and shift each item down to pos up one
|
||||
a.add(a[a.len-1])
|
||||
for i in countdown(len(a) - 3, pos):
|
||||
a[i + 1] = a[i]
|
||||
a[pos] = b
|
||||
|
||||
proc basename*(a: NimNode): NimNode =
|
||||
## Pull an identifier from prefix/postfix expressions
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: return a
|
||||
of nnkPostfix, nnkPrefix: return a[1]
|
||||
@@ -1347,7 +1364,7 @@ proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
|
||||
result = (node[1], $node[0], node[2])
|
||||
|
||||
proc copy*(node: NimNode): NimNode {.compileTime.} =
|
||||
## An alias for copyNimTree().
|
||||
## An alias for `copyNimTree<#copyNimTree,NimNode>`_.
|
||||
return node.copyNimTree()
|
||||
|
||||
when defined(nimVmEqIdent):
|
||||
@@ -1388,7 +1405,7 @@ else:
|
||||
|
||||
|
||||
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||
## Check if two idents are identical.
|
||||
## Check if two idents are equal.
|
||||
|
||||
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
|
||||
## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.)
|
||||
@@ -1403,7 +1420,7 @@ else:
|
||||
result = false
|
||||
|
||||
proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}=
|
||||
## Search nnkFormalParams for an argument.
|
||||
## Search ``nnkFormalParams`` for an argument.
|
||||
expectKind(params, nnkFormalParams)
|
||||
for i in 1 ..< params.len:
|
||||
template node: untyped = params[i]
|
||||
@@ -1411,7 +1428,7 @@ proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}=
|
||||
return true
|
||||
|
||||
proc addIdentIfAbsent*(dest: NimNode, ident: string) {.compileTime.} =
|
||||
## Add ident to dest if it is not present. This is intended for use
|
||||
## Add ``ident`` to ``dest`` if it is not present. This is intended for use
|
||||
## with pragmas.
|
||||
for node in dest.children:
|
||||
case node.kind
|
||||
@@ -1585,7 +1602,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
|
||||
|
||||
when not defined(booting):
|
||||
template emit*(e: static[string]): untyped {.deprecated.} =
|
||||
## accepts a single string argument and treats it as nim code
|
||||
## Accepts a single string argument and treats it as nim code
|
||||
## that should be inserted verbatim in the program
|
||||
## Example:
|
||||
##
|
||||
@@ -1603,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.} =
|
||||
|
||||
@@ -391,7 +391,7 @@ proc setVal[K, V](table: var PConcTable[K, V], key: int, val: int,
|
||||
# Done spinning for a new slot
|
||||
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
|
||||
if val == oldVal:
|
||||
#echo("this val is alredy in the slot")
|
||||
#echo("this val is already in the slot")
|
||||
return oldVal
|
||||
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
|
||||
if nextTable == nil and
|
||||
|
||||
@@ -42,7 +42,7 @@ type
|
||||
## the option was given a value
|
||||
|
||||
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
||||
## Initalizes option parses with cmdline. cmdline should not contain
|
||||
## Initializes option parses with cmdline. cmdline should not contain
|
||||
## argument 0 - program name.
|
||||
## If cmdline.len == 0 default to current command line arguments.
|
||||
result.remainingShortOptions = ""
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -275,9 +275,9 @@ proc createDiffs(dataA, dataB: DiffData): seq[Item] =
|
||||
proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] =
|
||||
## Find the difference in 2 arrays of integers.
|
||||
##
|
||||
## ``arrayA`` A-version of the numbers (usualy the old one)
|
||||
## ``arrayA`` A-version of the numbers (usually the old one)
|
||||
##
|
||||
## ``arrayB`` B-version of the numbers (usualy the new one)
|
||||
## ``arrayB`` B-version of the numbers (usually the new one)
|
||||
##
|
||||
## Returns a sequence of Items that describe the differences.
|
||||
|
||||
@@ -301,7 +301,7 @@ proc diffText*(textA, textB: string): seq[Item] =
|
||||
##
|
||||
## The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
|
||||
## each line is converted into a (hash) number. This hash-value is computed by storing all
|
||||
## textlines into a common hashtable so i can find dublicates in there, and generating a
|
||||
## textlines into a common hashtable so i can find duplicates in there, and generating a
|
||||
## new number each time a new textline is inserted.
|
||||
##
|
||||
## ``textA`` A-version of the text (usually the old one)
|
||||
|
||||
@@ -272,7 +272,7 @@ iterator fastRows*(db: var DbConn, query: SqlQuery,
|
||||
## if you require **ALL** the rows.
|
||||
##
|
||||
## Breaking the fastRows() iterator during a loop may cause a driver error
|
||||
## for subsequenct queries
|
||||
## for subsequent queries
|
||||
##
|
||||
## Rows are retrieved from the server at each iteration.
|
||||
var
|
||||
@@ -303,7 +303,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect, WriteDbEffect].} =
|
||||
## Same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within the interator body.
|
||||
## on demand using []. Returned handle is valid only within the iterator body.
|
||||
var
|
||||
rowRes: Row = @[]
|
||||
sz: TSqlInteger = 0
|
||||
|
||||
@@ -182,7 +182,7 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
|
||||
iterator fastRows*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
||||
## executes the query and iterates over the result dataset. This is very
|
||||
## fast, but potenially dangerous: If the for-loop-body executes another
|
||||
## fast, but potentially dangerous: If the for-loop-body executes another
|
||||
## query, the results can be undefined. For Postgres it is safe though.
|
||||
var res = setupQuery(db, query, args)
|
||||
var L = pqnfields(res)
|
||||
|
||||
@@ -94,6 +94,18 @@
|
||||
##
|
||||
## db.close()
|
||||
##
|
||||
##
|
||||
## Note
|
||||
## ====
|
||||
## This module does not implement any ORM features such as mapping the types from the schema.
|
||||
## Instead, a ``seq[string]`` is returned for each row.
|
||||
##
|
||||
## The reasoning is as follows:
|
||||
## 1. it's close to what many DBs offer natively (char**)
|
||||
## 2. it hides the number of types that the DB supports
|
||||
## (int? int64? decimal up to 10 places? geo coords?)
|
||||
## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query)
|
||||
##
|
||||
## See also
|
||||
## ========
|
||||
##
|
||||
|
||||
@@ -137,7 +137,7 @@ type
|
||||
## into PCRE flags. These include ``NEVER_UTF``, ``ANCHORED``,
|
||||
## ``DOLLAR_ENDONLY``, ``FIRSTLINE``, ``NO_AUTO_CAPTURE``,
|
||||
## ``JAVASCRIPT_COMPAT``, ``U``, ``NO_STUDY``. In other PCRE wrappers, you
|
||||
## will need to pass these as seperate flags to PCRE.
|
||||
## will need to pass these as separate flags to PCRE.
|
||||
pattern*: string ## not nil
|
||||
pcreObj: ptr pcre.Pcre ## not nil
|
||||
pcreExtra: ptr pcre.ExtraData ## nil
|
||||
@@ -215,7 +215,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.
|
||||
|
||||
|
||||
@@ -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".}
|
||||
|
||||
@@ -498,7 +498,7 @@ macro bindMethod*(procedure: typed): auto =
|
||||
this = newIdentNode("this")
|
||||
# construct the `this` parameter:
|
||||
thisQuote = quote do:
|
||||
var `this` {.nodecl, importc.} : `thisType`
|
||||
var `this` {.nodecl, importc: "this".}: `thisType`
|
||||
call = newNimNode(nnkCall).add(rawProc[0], thisQuote[0][0][0])
|
||||
# construct the procedure call inside the method
|
||||
if args.len > 2:
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
##
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user