mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 19:03:42 +00:00
Compare commits
275 Commits
pr_nodecl_
...
v1.6.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aa9273640 | ||
|
|
19dd56f018 | ||
|
|
b6333c4a20 | ||
|
|
d723d5ff72 | ||
|
|
cdbcada3d7 | ||
|
|
5c36f24da2 | ||
|
|
1cdce314a7 | ||
|
|
a67f89e643 | ||
|
|
4fbd28a1a4 | ||
|
|
69d4e49630 | ||
|
|
60350eca1a | ||
|
|
6af6818fe9 | ||
|
|
d070ccbc03 | ||
|
|
fca6a0bd6a | ||
|
|
c546ba5d23 | ||
|
|
7fa782e3a0 | ||
|
|
b93edcd059 | ||
|
|
28985686c0 | ||
|
|
f9b95d1cb4 | ||
|
|
032512cebd | ||
|
|
5e1bffb724 | ||
|
|
e0328e28ee | ||
|
|
afdbfd2c7e | ||
|
|
17d45dfd6a | ||
|
|
f7c79db846 | ||
|
|
b1a0467ffd | ||
|
|
2c24ac1849 | ||
|
|
7a43d00a64 | ||
|
|
0cdbf5e04e | ||
|
|
320a820eb4 | ||
|
|
ebf0e7ebb1 | ||
|
|
9ee9b4283d | ||
|
|
213a9f9f34 | ||
|
|
8c0f2f0152 | ||
|
|
d0d8c95094 | ||
|
|
ec13574b19 | ||
|
|
a1165c8231 | ||
|
|
babd80b446 | ||
|
|
f01ffbf6f1 | ||
|
|
0da50cef4f | ||
|
|
76c347515a | ||
|
|
7f90bcf5b4 | ||
|
|
d81484bff9 | ||
|
|
27732a4248 | ||
|
|
3e677a6225 | ||
|
|
5cfa3672b3 | ||
|
|
0683e8f747 | ||
|
|
d2de2e7be1 | ||
|
|
224319f787 | ||
|
|
871e90aa4e | ||
|
|
ca0757d09f | ||
|
|
f1519259f8 | ||
|
|
eaf43a1bd9 | ||
|
|
dd80e968e8 | ||
|
|
99528ee295 | ||
|
|
2631e99238 | ||
|
|
9dc97ed143 | ||
|
|
76b0842994 | ||
|
|
eb42fe51da | ||
|
|
0bc52ddb85 | ||
|
|
a1c431c6ab | ||
|
|
121602e88f | ||
|
|
565cd4dd25 | ||
|
|
38730862fc | ||
|
|
999a4bb750 | ||
|
|
2292ff950a | ||
|
|
c5d62bcbfe | ||
|
|
8e04112762 | ||
|
|
c9df6cfd92 | ||
|
|
203c18352a | ||
|
|
ec674e6d5b | ||
|
|
322d2f8096 | ||
|
|
c35cb17b13 | ||
|
|
8b86ba96f8 | ||
|
|
01a0b31167 | ||
|
|
02ce5a585b | ||
|
|
ce63020110 | ||
|
|
5abf259908 | ||
|
|
31fe32afd1 | ||
|
|
fbd99c781f | ||
|
|
c9f46ca8c9 | ||
|
|
56a15976b5 | ||
|
|
cba0c20be8 | ||
|
|
60f43fb690 | ||
|
|
e32de02f0a | ||
|
|
ece219de2f | ||
|
|
8923e34d7f | ||
|
|
113bd34b6c | ||
|
|
73e569fec9 | ||
|
|
bd1ca4bb3f | ||
|
|
0a017b208b | ||
|
|
d406727016 | ||
|
|
09d85d8b24 | ||
|
|
e5e445f042 | ||
|
|
aae2356b91 | ||
|
|
5ea0e5608d | ||
|
|
a9485f19a5 | ||
|
|
dda6181fff | ||
|
|
d79f61e54d | ||
|
|
33a1e3acb9 | ||
|
|
831fed1c01 | ||
|
|
65e0906e69 | ||
|
|
c484943cab | ||
|
|
000e6875bd | ||
|
|
17e61c75a2 | ||
|
|
0277cd5252 | ||
|
|
621061d62f | ||
|
|
d53a057f5f | ||
|
|
7d0bfc6725 | ||
|
|
5771a0f9c4 | ||
|
|
5f61f1594d | ||
|
|
62ac3a01fa | ||
|
|
c9e7798978 | ||
|
|
ac7efa1964 | ||
|
|
8a98177025 | ||
|
|
fd76c00479 | ||
|
|
8786e7dddf | ||
|
|
3fd11d7e96 | ||
|
|
a3c2eb04b9 | ||
|
|
46f0f6e47e | ||
|
|
0e7138417c | ||
|
|
e9d5a9d395 | ||
|
|
9508b06513 | ||
|
|
b1f325d641 | ||
|
|
7c7815402a | ||
|
|
c9a52971f4 | ||
|
|
6f290fa386 | ||
|
|
1561a83c49 | ||
|
|
a1f413bcac | ||
|
|
2064fda582 | ||
|
|
efe5a33988 | ||
|
|
4873221429 | ||
|
|
ab0d06869e | ||
|
|
06f1828ee2 | ||
|
|
1368316b7f | ||
|
|
b0cbc9a74c | ||
|
|
64689f932c | ||
|
|
3e39f5bfec | ||
|
|
28af1e5e45 | ||
|
|
c6e3ad4ab9 | ||
|
|
26707a62fc | ||
|
|
0b44840299 | ||
|
|
02d94966c9 | ||
|
|
62d1d0516c | ||
|
|
7d120b83d1 | ||
|
|
0565a70eab | ||
|
|
252df3f1c0 | ||
|
|
608457defc | ||
|
|
4f392727c8 | ||
|
|
4bb2e9e921 | ||
|
|
1788b8b991 | ||
|
|
0e5bf5953e | ||
|
|
85841cd318 | ||
|
|
b1045cb693 | ||
|
|
151b4cc514 | ||
|
|
f194356d21 | ||
|
|
88573da12d | ||
|
|
2a68fa71eb | ||
|
|
fcd05bd031 | ||
|
|
d38177b11f | ||
|
|
9035618347 | ||
|
|
e22d494409 | ||
|
|
6365d8c39a | ||
|
|
b96954ef52 | ||
|
|
bb937f2357 | ||
|
|
dcc40b9609 | ||
|
|
3177e16b0d | ||
|
|
92457cbc39 | ||
|
|
73c4ede283 | ||
|
|
55907a8bf8 | ||
|
|
9de1013c94 | ||
|
|
589dc2d18f | ||
|
|
0adfe6c5a1 | ||
|
|
fd2da6da54 | ||
|
|
9b560747e8 | ||
|
|
bf3a2e010d | ||
|
|
9fcf1a5d4c | ||
|
|
4877caa462 | ||
|
|
8aa045806c | ||
|
|
b9363c8bb4 | ||
|
|
1dc47696c0 | ||
|
|
b741f3cbd3 | ||
|
|
9df55a8979 | ||
|
|
01c38610f5 | ||
|
|
40db88d0f8 | ||
|
|
ff819757be | ||
|
|
2d2587747f | ||
|
|
0bb7bd07d2 | ||
|
|
ebb140edda | ||
|
|
ec9e51abe6 | ||
|
|
b8f1347c99 | ||
|
|
d7370ce269 | ||
|
|
971b639739 | ||
|
|
5e13d577ac | ||
|
|
b6024fe861 | ||
|
|
9746d46009 | ||
|
|
82c930c364 | ||
|
|
c25b7e79cf | ||
|
|
8fe8aada87 | ||
|
|
231a135563 | ||
|
|
7994556f38 | ||
|
|
8c9e88f520 | ||
|
|
7e52a57121 | ||
|
|
35c812fda1 | ||
|
|
47888c18f7 | ||
|
|
a8e040ec30 | ||
|
|
2fb1c80f42 | ||
|
|
e1f3c74bdc | ||
|
|
52d2ff601b | ||
|
|
41b71487af | ||
|
|
3d3b34473b | ||
|
|
fc0aec6f1b | ||
|
|
7cafd22377 | ||
|
|
9aff19f51a | ||
|
|
bc823b6487 | ||
|
|
3d3d790c63 | ||
|
|
a90cabbe40 | ||
|
|
2539d7a862 | ||
|
|
30737b3e7f | ||
|
|
984691bb67 | ||
|
|
5f70b1ab53 | ||
|
|
afa4bc34b4 | ||
|
|
0648cde117 | ||
|
|
980ec713da | ||
|
|
26ed4e5413 | ||
|
|
161736ceb3 | ||
|
|
ce6fa79858 | ||
|
|
f2e7e5d899 | ||
|
|
d4de5d32bc | ||
|
|
efdb180f62 | ||
|
|
095202e218 | ||
|
|
f4e41e6c4f | ||
|
|
8aec198abc | ||
|
|
9084d9bc02 | ||
|
|
48c62ca48b | ||
|
|
70320482be | ||
|
|
e3a07f1997 | ||
|
|
bcf9448a75 | ||
|
|
a2f5e98baa | ||
|
|
a3b370fa87 | ||
|
|
b7a0c08b4f | ||
|
|
46275126b8 | ||
|
|
83c472c40d | ||
|
|
ac57c3193d | ||
|
|
7cf5e73fb7 | ||
|
|
c14008d77f | ||
|
|
168a8784f4 | ||
|
|
ee876aee28 | ||
|
|
8ed903d1d0 | ||
|
|
bfa8188dac | ||
|
|
56409c15c0 | ||
|
|
b614d97a2d | ||
|
|
2bb3a85a7c | ||
|
|
1247043c90 | ||
|
|
0ba76622a3 | ||
|
|
ab6770e77f | ||
|
|
c7920e9f87 | ||
|
|
167881bb83 | ||
|
|
73366c015f | ||
|
|
cfee71e779 | ||
|
|
1090b0c4af | ||
|
|
3f6de926f0 | ||
|
|
13343180b8 | ||
|
|
95dce90467 | ||
|
|
f85e09633d | ||
|
|
575450dfec | ||
|
|
6a2babac47 | ||
|
|
a6e192f020 | ||
|
|
233c6e9fb3 | ||
|
|
97286db546 | ||
|
|
1ac029c0f6 | ||
|
|
b18b636ea6 | ||
|
|
ac89e06c6e | ||
|
|
861b625a66 | ||
|
|
727c6378d2 |
2
.github/workflows/ci_docs.yml
vendored
2
.github/workflows/ci_docs.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
- target: windows
|
||||
os: windows-2019
|
||||
- target: osx
|
||||
os: macos-10.15
|
||||
os: macos-11
|
||||
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
2
.github/workflows/ci_packages.yml
vendored
2
.github/workflows/ci_packages.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-10.15]
|
||||
os: [ubuntu-20.04, macos-11]
|
||||
cpu: [amd64]
|
||||
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
|
||||
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
|
||||
|
||||
@@ -28,10 +28,10 @@ jobs:
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-10.15'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-10.15'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64_batch0_3:
|
||||
|
||||
@@ -24,6 +24,6 @@ if not exist %nim_csources% (
|
||||
cd ..
|
||||
copy /y bin\nim.exe %nim_csources%
|
||||
)
|
||||
bin\nim.exe c --skipUserCfg --skipParentCfg --hints:off koch
|
||||
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
|
||||
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
|
||||
koch tools --skipUserCfg --skipParentCfg --hints:off
|
||||
|
||||
@@ -11,7 +11,7 @@ set -e # exit on first error
|
||||
. ci/funs.sh
|
||||
nimBuildCsourcesIfNeeded "$@"
|
||||
|
||||
echo_run bin/nim c --skipUserCfg --skipParentCfg --hints:off koch
|
||||
echo_run bin/nim c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
|
||||
echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
|
||||
echo_run ./koch tools --skipUserCfg --skipParentCfg --hints:off
|
||||
|
||||
|
||||
91
changelog.md
91
changelog.md
@@ -3,23 +3,114 @@
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- `addr` is now available for all addressable locations,
|
||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
||||
|
||||
- `io`, `assertions`, `formatfloat`, and `` dollars.`$` `` for objects are about to move out of the `system` module. You may instead import `std/syncio`, `std/assertions`, `std/formatfloat` and `std/objectdollar`.
|
||||
The `-d:nimPreviewSlimSystem` option makes these imports required.
|
||||
|
||||
- The `gc:v2` option is removed.
|
||||
|
||||
- The `mainmodule` and `m` options are removed.
|
||||
|
||||
- The `threads:on` option is now the default.
|
||||
|
||||
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
|
||||
`experimental:flexibleOptionalParams`.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
|
||||
This warning will become an error in future versions! Use a `cast` operation
|
||||
like `cast[cstring](x)` instead.
|
||||
|
||||
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
|
||||
|
||||
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
|
||||
|
||||
- Redefining templates with the same signature was previously
|
||||
allowed to support certain macro code. To do this explicitly, the
|
||||
`{.redefine.}` pragma has been added. Note that this is only for templates.
|
||||
Implicit redefinition of templates is now deprecated and will give an error in the future.
|
||||
|
||||
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
|
||||
|
||||
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
|
||||
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
|
||||
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
|
||||
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
|
||||
|
||||
- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
filename argument for more informative errors.
|
||||
- Module `colors` expanded with missing colors from the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||
allowing multiple type definitions to be injected in place of the original type definition.
|
||||
|
||||
```nim
|
||||
import macros
|
||||
|
||||
macro multiply(amount: static int, s: untyped): untyped =
|
||||
let name = $s[0].basename
|
||||
result = newNimNode(nnkTypeSection)
|
||||
for i in 1 .. amount:
|
||||
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||
|
||||
type
|
||||
Foo = object
|
||||
Bar {.multiply: 3.} = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
|
||||
# becomes
|
||||
|
||||
type
|
||||
Foo = object
|
||||
Bar1 = object
|
||||
x, y, z: int
|
||||
Bar2 = object
|
||||
x, y, z: int
|
||||
Bar3 = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
```
|
||||
- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental,
|
||||
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
|
||||
without requiring `-d:nimVersion140` which is now a noop.
|
||||
|
||||
- `--styleCheck` now only applies to the current package.
|
||||
|
||||
|
||||
## Tool changes
|
||||
|
||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||
|
||||
- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by
|
||||
a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg`
|
||||
replace `pkgs` by `pkgs2`.
|
||||
|
||||
- There is a new switch `--nimMainPrefix:prefix` to influence the `NimMain` that the
|
||||
compiler produces. This is particularly useful for generating static libraries.
|
||||
|
||||
31
changelogs/changelog.md
Normal file
31
changelogs/changelog.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# v1.xx.x - yyyy-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
|
||||
|
||||
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
## Tool changes
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
version = system.NimVersion
|
||||
author = "Andreas Rumpf"
|
||||
description = "Compiler package providing the compiler sources as a library."
|
||||
license = "MIT"
|
||||
|
||||
installDirs = @["compiler", "nimsuggest"]
|
||||
|
||||
requires "nim >= 0.14.0"
|
||||
@@ -501,7 +501,7 @@ type
|
||||
nfHasComment # node has a comment
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
@@ -673,7 +673,7 @@ type
|
||||
mSwap, mIsNil, mArrToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mWasMoved, mDestroy, mTrace,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
mOrdinal, mIterableType,
|
||||
@@ -777,6 +777,8 @@ type
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
@@ -873,6 +875,8 @@ type
|
||||
typ*: PType
|
||||
name*: PIdent
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
@@ -1105,21 +1109,6 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
|
||||
of nkIdent: a.ident
|
||||
else: nil
|
||||
|
||||
proc getnimblePkg*(a: PSym): PSym =
|
||||
result = a
|
||||
while result != nil:
|
||||
case result.kind
|
||||
of skModule:
|
||||
result = result.owner
|
||||
assert result.kind == skPackage
|
||||
of skPackage:
|
||||
if result.owner == nil:
|
||||
break
|
||||
else:
|
||||
result = result.owner
|
||||
else:
|
||||
assert false, $result.kind
|
||||
|
||||
const
|
||||
moduleShift = when defined(cpu32): 20 else: 24
|
||||
|
||||
@@ -1164,13 +1153,7 @@ when false:
|
||||
assert dest.ItemId.item <= src.ItemId.item
|
||||
dest = src
|
||||
|
||||
proc getnimblePkgId*(a: PSym): int =
|
||||
let b = a.getnimblePkg
|
||||
result = if b == nil: -1 else: b.id
|
||||
|
||||
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
|
||||
#var
|
||||
# gMainPackageId*: int
|
||||
|
||||
proc isCallExpr*(n: PNode): bool =
|
||||
result = n.kind in nkCallKinds
|
||||
@@ -1678,6 +1661,8 @@ proc copyNode*(src: PNode): PNode =
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
|
||||
template transitionNodeKindCommon(k: TNodeKind) =
|
||||
let obj {.inject.} = n[]
|
||||
@@ -1726,6 +1711,8 @@ template copyNodeImpl(dst, src, processSonsStmt) =
|
||||
if src == nil: return
|
||||
dst = newNode(src.kind)
|
||||
dst.info = src.info
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
dst.typ = src.typ
|
||||
dst.flags = src.flags * PersistentNodeFlags
|
||||
dst.comment = src.comment
|
||||
@@ -2101,3 +2088,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||
assert n.kind == nkTypeClassTy
|
||||
result = n[0].kind == nkEmpty
|
||||
|
||||
const
|
||||
nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||
nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
||||
|
||||
@@ -21,7 +21,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
|
||||
# we have to be *very* conservative:
|
||||
result = canRaiseConservative(n)
|
||||
|
||||
proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
||||
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
|
||||
var n = le
|
||||
while true:
|
||||
@@ -54,6 +54,11 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
||||
if canRaise(ri[0]) and
|
||||
locationEscapes(p, le, p.nestedTryStmts.len > 0):
|
||||
message(p.config, le.info, warnObservableStores, $le)
|
||||
# bug #19613 prevent dangerous aliasing too:
|
||||
if dest != nil and dest != le:
|
||||
for i in 1..<ri.len:
|
||||
let r = ri[i]
|
||||
if isPartOf(dest, r) != arNo: return true
|
||||
|
||||
proc hasNoInit(call: PNode): bool {.inline.} =
|
||||
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
|
||||
@@ -76,10 +81,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if params != nil: pl.add(~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
@@ -150,7 +155,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) =
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
var a, b, c: TLoc
|
||||
initLocExpr(p, q[1], a)
|
||||
initLocExpr(p, q[2], b)
|
||||
@@ -158,6 +163,8 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
|
||||
# but first produce the required index checks:
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c)
|
||||
if prepareForMutation:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let ty = skipTypes(a.t, abstractVar+{tyPtr})
|
||||
let dest = getTypeDesc(p.module, destType)
|
||||
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
|
||||
@@ -187,10 +194,12 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
if atyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
result = ("($4*)(*$1)$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
|
||||
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
|
||||
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
|
||||
lengthExpr)
|
||||
else:
|
||||
result = ("($4*)$1$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
|
||||
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
|
||||
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
|
||||
lengthExpr)
|
||||
else:
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
@@ -214,7 +223,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||
case skipTypes(a.t, abstractVar).kind
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(n):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
@@ -231,9 +240,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
var t: TLoc
|
||||
t.r = "(*$1)" % [a.rdLoc]
|
||||
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
|
||||
result = "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
else:
|
||||
result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
|
||||
result = "($4) ? ($1$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
|
||||
of tyArray:
|
||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
|
||||
of tyPtr, tyRef:
|
||||
@@ -241,7 +253,9 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
of tyString, tySequence:
|
||||
var t: TLoc
|
||||
t.r = "(*$1)" % [a.rdLoc]
|
||||
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
|
||||
result = "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
of tyArray:
|
||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
|
||||
else:
|
||||
@@ -376,8 +390,8 @@ proc genParams(p: BProc, ri: PNode, typ: PType): Rope =
|
||||
if not needTmp[i - 1]:
|
||||
needTmp[i - 1] = potentialAlias(n, potentialWrites)
|
||||
getPotentialWrites(ri[i], false, potentialWrites)
|
||||
if ri[i].kind == nkHiddenAddr:
|
||||
# Optimization: don't use a temp, if we would only take the adress anyway
|
||||
if ri[i].kind in {nkHiddenAddr, nkAddr}:
|
||||
# Optimization: don't use a temp, if we would only take the address anyway
|
||||
needTmp[i - 1] = false
|
||||
|
||||
for i in 1..<ri.len:
|
||||
@@ -439,10 +453,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
if d.k == locNone:
|
||||
getTemp(p, typ[0], d, needsInit=true)
|
||||
@@ -737,7 +751,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
pl.add(~": ")
|
||||
pl.add(genArg(p, ri[i], param, ri))
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(~" ")
|
||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||
if d.k in {locTemp, locNone}:
|
||||
|
||||
@@ -292,8 +292,8 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
|
||||
[rdLoc(d), a.rdLoc])
|
||||
of tySequence:
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
|
||||
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
|
||||
linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n",
|
||||
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)])
|
||||
of tyArray:
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n",
|
||||
[rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))])
|
||||
@@ -302,8 +302,8 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
|
||||
if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
|
||||
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
|
||||
linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n",
|
||||
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)])
|
||||
else:
|
||||
internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind)
|
||||
|
||||
@@ -584,13 +584,23 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
else:
|
||||
# we handle div by zero here so that we know that the compilerproc's
|
||||
# result is only for overflows.
|
||||
var needsOverflowCheck = true
|
||||
if m in {mDivI, mModI}:
|
||||
linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); $2}$n",
|
||||
[rdLoc(b), raiseInstr(p)])
|
||||
|
||||
let res = binaryArithOverflowRaw(p, t, a, b,
|
||||
if t.kind == tyInt64: prc64[m] else: prc[m])
|
||||
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
|
||||
var canBeZero = true
|
||||
if e[2].kind in {nkIntLit..nkUInt64Lit}:
|
||||
canBeZero = e[2].intVal == 0
|
||||
if e[2].kind in {nkIntLit..nkInt64Lit}:
|
||||
needsOverflowCheck = e[2].intVal == -1
|
||||
if canBeZero:
|
||||
linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); $2}$n",
|
||||
[rdLoc(b), raiseInstr(p)])
|
||||
if needsOverflowCheck:
|
||||
let res = binaryArithOverflowRaw(p, t, a, b,
|
||||
if t.kind == tyInt64: prc64[m] else: prc[m])
|
||||
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
|
||||
else:
|
||||
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
putIntoDest(p, d, e, res)
|
||||
|
||||
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
var
|
||||
@@ -721,7 +731,22 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||
skipTypes(typ, abstractInstOwned).kind in {tyVar} and
|
||||
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
|
||||
|
||||
proc derefBlock(p: BProc, e: PNode, d: var TLoc) =
|
||||
# We transform (block: x)[] to (block: x[])
|
||||
let e0 = e[0]
|
||||
var n = shallowCopy(e0)
|
||||
n.typ = e.typ
|
||||
for i in 0 ..< e0.len - 1:
|
||||
n[i] = e0[i]
|
||||
n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1])
|
||||
expr p, n, d
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}:
|
||||
# bug #20107. Watch out to not deref the pointer too late.
|
||||
derefBlock(p, e, d)
|
||||
return
|
||||
|
||||
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
|
||||
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
|
||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||
@@ -978,12 +1003,12 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
|
||||
if reifiedOpenArray(arr.lode):
|
||||
linefmt(p, cpsStmts,
|
||||
"if ($2-$1 != -1 && " &
|
||||
"((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n",
|
||||
"($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError(); $4}$n",
|
||||
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ($2-$1 != -1 && " &
|
||||
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
|
||||
"if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" &
|
||||
"{ #raiseIndexError(); $4}$n",
|
||||
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
|
||||
of tyArray:
|
||||
let first = intLiteral(firstOrd(p.config, ty))
|
||||
@@ -994,7 +1019,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
|
||||
of tySequence, tyString:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ($2-$1 != -1 && " &
|
||||
"((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)){ #raiseIndexError(); $4}$n",
|
||||
"($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError(); $4}$n",
|
||||
[rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p)])
|
||||
else: discard
|
||||
|
||||
@@ -1005,14 +1030,14 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if not reifiedOpenArray(x):
|
||||
# emit range check:
|
||||
if optBoundsCheck in p.options:
|
||||
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
|
||||
linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2Len_0){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
|
||||
[rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
|
||||
inheritLocation(d, a)
|
||||
putIntoDest(p, d, n,
|
||||
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
|
||||
else:
|
||||
if optBoundsCheck in p.options:
|
||||
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.Field1)){ #raiseIndexError2($1,$2.Field1-1); $3}$n",
|
||||
linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2.Field1){ #raiseIndexError2($1,$2.Field1-1); $3}$n",
|
||||
[rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
|
||||
inheritLocation(d, a)
|
||||
putIntoDest(p, d, n,
|
||||
@@ -1027,7 +1052,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
||||
if optBoundsCheck in p.options:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n",
|
||||
"if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); $3}$n",
|
||||
[rdCharLoc(b), lenExpr(p, a), raiseInstr(p)])
|
||||
if d.k == locNone: d.storage = OnHeap
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
@@ -1552,6 +1577,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
return
|
||||
if d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
initLocExpr(p, n[1], a)
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
let L = toInt(lengthOrd(p.config, n[1].typ))
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
@@ -1561,7 +1587,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
else:
|
||||
genNewSeqAux(p, d, intLiteral(L), L == 0)
|
||||
initLocExpr(p, n[1], a)
|
||||
# bug #5007; do not produce excessive C source code:
|
||||
if L < 10:
|
||||
for i in 0..<L:
|
||||
@@ -1605,8 +1630,11 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
|
||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
result = ropecg(p.module, "#isObj($1.m_type, $2)",
|
||||
[a, genTypeInfo2Name(p.module, dest)])
|
||||
let ti = genTypeInfo2Name(p.module, dest)
|
||||
inc p.module.labels
|
||||
let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
|
||||
p.module.s[cfsVars].addf("static TNimTypeV2* $#[2];$n", [cache])
|
||||
result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache])
|
||||
else:
|
||||
# unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
|
||||
# have to call it here first:
|
||||
@@ -1686,7 +1714,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
|
||||
of tyString, tySequence:
|
||||
putIntoDest(p, b, e,
|
||||
"$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage)
|
||||
"($4) ? ($1$3) : NIM_NIL, $2" %
|
||||
[rdLoc(a), lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)],
|
||||
a.storage)
|
||||
of tyArray:
|
||||
putIntoDest(p, b, e,
|
||||
"$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
|
||||
@@ -1741,6 +1771,13 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
|
||||
# use the dynamic type stored at offset 0:
|
||||
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
|
||||
|
||||
proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, e[1], a)
|
||||
var nilCheck = Rope(nil)
|
||||
# use the dynamic type stored at offset 0:
|
||||
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
|
||||
|
||||
template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[1], a)
|
||||
@@ -1759,9 +1796,13 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
# Bug #9279, len(toOpenArray()) has to work:
|
||||
if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice:
|
||||
# magic: pass slice to openArray:
|
||||
var m: TLoc
|
||||
var b, c: TLoc
|
||||
initLocExpr(p, a[1], m)
|
||||
initLocExpr(p, a[2], b)
|
||||
initLocExpr(p, a[3], c)
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, m, b, c)
|
||||
if op == mHigh:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
@@ -2057,6 +2098,11 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes:
|
||||
putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage)
|
||||
else:
|
||||
if etyp.kind == tyPtr:
|
||||
# generates the definition of structs for casts like cast[ptr object](addr x)[]
|
||||
let internalType = etyp.skipTypes({tyPtr})
|
||||
if internalType.kind == tyObject:
|
||||
discard getTypeDesc(p.module, internalType)
|
||||
putIntoDest(p, d, e, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
|
||||
|
||||
@@ -2253,7 +2299,10 @@ proc genDispose(p: BProc; n: PNode) =
|
||||
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
|
||||
|
||||
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
|
||||
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon)
|
||||
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
|
||||
prepareForMutation = e[1].kind == nkHiddenDeref and
|
||||
e[1].typ.skipTypes(abstractInst).kind == tyString and
|
||||
p.config.selectedGC in {gcArc, gcOrc})
|
||||
if d.k == locNone: getTemp(p, e.typ, d)
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
|
||||
when false:
|
||||
@@ -2449,6 +2498,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mMove: genMove(p, e, d)
|
||||
of mDestroy: genDestroy(p, e)
|
||||
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
|
||||
of mAccessTypeField: genAccessTypeField(p, e, d)
|
||||
of mSlice: genSlice(p, e, d)
|
||||
of mTrace: discard "no code to generate"
|
||||
else:
|
||||
|
||||
@@ -87,7 +87,20 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
else:
|
||||
of tySet:
|
||||
case mapSetType(p.config, typ)
|
||||
of ctArray:
|
||||
lineCg(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n",
|
||||
[accessor, getTypeDesc(p.module, typ)])
|
||||
of ctInt8, ctInt16, ctInt32, ctInt64:
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
else:
|
||||
doAssert false, "unexpected set type kind"
|
||||
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
|
||||
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
|
||||
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
|
||||
discard
|
||||
|
||||
proc specializeReset(p: BProc, a: TLoc) =
|
||||
|
||||
@@ -32,13 +32,20 @@ proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
|
||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||
|
||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
if n.kind == nkEmpty: return false
|
||||
if isInvalidReturnType(conf, n.typ):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
return false
|
||||
result = true
|
||||
if n.kind == nkEmpty:
|
||||
result = false
|
||||
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
|
||||
if isInvalidReturnType(conf, n[0].typ, true):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
elif isInvalidReturnType(conf, n.typ, false):
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc inExceptBlockLen(p: BProc): int =
|
||||
for x in p.nestedTryStmts:
|
||||
@@ -1356,8 +1363,24 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimBuiltinSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
if isDefined(p.config, "mswindows"):
|
||||
if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"):
|
||||
# For the vcc compiler, use `setjmp()` with one argument.
|
||||
# See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
else:
|
||||
# The Windows `_setjmp()` takes two arguments, with the second being an
|
||||
# undocumented buffer used by the SEH mechanism for stack unwinding.
|
||||
# Mingw-w64 has been trying to get it right for years, but it's still
|
||||
# prone to stack corruption during unwinding, so we disable that by setting
|
||||
# it to NULL.
|
||||
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
|
||||
|
||||
@@ -39,13 +39,13 @@ proc mangleName(m: BModule; s: PSym): Rope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
result = s.name.s.mangle.rope
|
||||
result.add "_"
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_"
|
||||
result.add rope s.itemId.item
|
||||
if m.hcrOn:
|
||||
result.add "_"
|
||||
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts))
|
||||
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
|
||||
s.loc.r = result
|
||||
writeMangledName(m.ndi, s, m.config)
|
||||
|
||||
@@ -215,12 +215,19 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||
(typ[0] == nil) or isPureObject(typ))
|
||||
|
||||
proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
||||
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
|
||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||
# such a poor programming language.
|
||||
# We exclude records with refs too. This enhances efficiency and
|
||||
# is necessary for proper code generation of assignments.
|
||||
if rettype == nil: result = true
|
||||
var rettype = typ
|
||||
var isAllowedCall = true
|
||||
if isProc:
|
||||
rettype = rettype[0]
|
||||
isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall}
|
||||
if rettype == nil or (isAllowedCall and
|
||||
getSize(conf, rettype) > conf.target.floatSize*3):
|
||||
result = true
|
||||
else:
|
||||
case mapType(conf, rettype, skResult)
|
||||
of ctArray:
|
||||
@@ -256,11 +263,11 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
|
||||
# see `testCodegenABICheck` for example error message it generates
|
||||
|
||||
|
||||
proc fillResult(conf: ConfigRef; param: PNode) =
|
||||
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
|
||||
fillLoc(param.sym.loc, locParam, param, ~"Result",
|
||||
OnStack)
|
||||
let t = param.sym.typ
|
||||
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
|
||||
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
|
||||
incl(param.sym.loc.flags, lfIndirect)
|
||||
param.sym.loc.storage = OnUnknown
|
||||
|
||||
@@ -304,7 +311,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||
else: result = nil
|
||||
|
||||
if result != nil and typ.isImportedType():
|
||||
let sig = hashType typ
|
||||
let sig = hashType(typ, m.config)
|
||||
if cacheGetType(m.typeCache, sig) == nil:
|
||||
m.typeCache[sig] = result
|
||||
|
||||
@@ -364,10 +371,10 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
|
||||
if isImportedCppType(etB) and t.kind == tyGenericInst:
|
||||
result = getTypeDescAux(m, t, check, kind)
|
||||
else:
|
||||
result = getTypeForward(m, t, hashType(t))
|
||||
result = getTypeForward(m, t, hashType(t, m.config))
|
||||
pushType(m, t)
|
||||
of tySequence:
|
||||
let sig = hashType(t)
|
||||
let sig = hashType(t, m.config)
|
||||
if optSeqDestructors in m.config.globalOptions:
|
||||
if skipTypes(etB[0], typedescInst).kind == tyEmpty:
|
||||
internalError(m.config, "cannot map the empty seq type to a C type")
|
||||
@@ -400,7 +407,7 @@ proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
||||
#result = getTypeForward(m, t, hashType(t)) & "_Content"
|
||||
|
||||
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
|
||||
let sig = hashType(t)
|
||||
let sig = hashType(t, m.config)
|
||||
let result = cacheGetType(m.typeCache, sig)
|
||||
if result == nil:
|
||||
discard getTypeDescAux(m, t, check, skVar)
|
||||
@@ -425,7 +432,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false) =
|
||||
params = nil
|
||||
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
|
||||
if t[0] == nil or isInvalidReturnType(m.config, t):
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t[0], check, skResult)
|
||||
@@ -460,12 +467,17 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
|
||||
inc(j)
|
||||
arr = arr[0].skipTypes({tySink})
|
||||
if t[0] != nil and isInvalidReturnType(m.config, t[0]):
|
||||
if t[0] != nil and isInvalidReturnType(m.config, t):
|
||||
var arr = t[0]
|
||||
if params != nil: params.add(", ")
|
||||
if mapReturnType(m.config, t[0]) != ctArray:
|
||||
params.add(getTypeDescWeak(m, arr, check, skResult))
|
||||
params.add("*")
|
||||
if isHeaderFile in m.flags:
|
||||
# still generates types for `--header`
|
||||
params.add(getTypeDescAux(m, arr, check, skResult))
|
||||
params.add("*")
|
||||
else:
|
||||
params.add(getTypeDescWeak(m, arr, check, skResult))
|
||||
params.add("*")
|
||||
else:
|
||||
params.add(getTypeDescAux(m, arr, check, skResult))
|
||||
params.addf(" Result", [])
|
||||
@@ -582,7 +594,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
|
||||
if typ.kind == tyObject:
|
||||
if typ[0] == nil:
|
||||
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
|
||||
if lacksMTypeField(typ):
|
||||
appcg(m, result, " {$n", [])
|
||||
else:
|
||||
if optTinyRtti in m.config.globalOptions:
|
||||
@@ -660,7 +672,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||
else: result.elemType
|
||||
|
||||
proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope =
|
||||
let sig = hashType(t)
|
||||
let sig = hashType(t, m.config)
|
||||
if kind == skParam:
|
||||
result = getTypeDescWeak(m, t[0], check, kind) & "*"
|
||||
else:
|
||||
@@ -684,7 +696,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
|
||||
# C type generation into an analysis and a code generation phase somehow.
|
||||
if t.sym != nil: useHeader(m, t.sym)
|
||||
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
|
||||
let sig = hashType(origTyp)
|
||||
let sig = hashType(origTyp, m.config)
|
||||
|
||||
defer: # defer is the simplest in this case
|
||||
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
|
||||
@@ -713,7 +725,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
|
||||
result = getTypeDescAux(m, et, check, kind) & star
|
||||
else:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let name = getTypeForward(m, et, hashType et)
|
||||
let name = getTypeForward(m, et, hashType(et, m.config))
|
||||
result = name & star
|
||||
m.typeCache[sig] = result
|
||||
of tySequence:
|
||||
@@ -722,7 +734,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
|
||||
m.typeCache[sig] = result
|
||||
else:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let name = getTypeForward(m, et, hashType et)
|
||||
let name = getTypeForward(m, et, hashType(et, m.config))
|
||||
result = name & seqStar(m) & star
|
||||
m.typeCache[sig] = result
|
||||
pushType(m, et)
|
||||
@@ -885,7 +897,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
|
||||
discard # addAbiCheck(m, t, result) # already handled elsewhere
|
||||
of tySet:
|
||||
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
|
||||
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType
|
||||
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType(m.config)
|
||||
m.typeCache[sig] = result
|
||||
if not isImportedType(t):
|
||||
let s = int(getSize(m.config, t))
|
||||
@@ -1058,7 +1070,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
|
||||
objtype = objtype[0].skipTypes(abstractPtrs)
|
||||
if objtype.sym == nil:
|
||||
internalError(m.config, d.info, "anonymous obj with discriminator")
|
||||
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
|
||||
result = "NimDT_$1_$2" % [rope($hashType(objtype, m.config)), rope(d.name.s.mangle)]
|
||||
|
||||
proc rope(arg: Int128): Rope = rope($arg)
|
||||
|
||||
@@ -1266,7 +1278,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||
var it = t
|
||||
while it != nil:
|
||||
it = it.skipTypes(skipPtrs)
|
||||
if it.sym != nil:
|
||||
if it.sym != nil and tfFromGeneric notin it.flags:
|
||||
var m = it.sym.owner
|
||||
while m != nil and m.kind != skModule: m = m.owner
|
||||
if m == nil or sfSystemModule in m.flags:
|
||||
@@ -1279,7 +1291,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||
res.add m.name.s & "."
|
||||
res.add it.sym.name.s
|
||||
else:
|
||||
res.add $hashType(it)
|
||||
res.add $hashType(it, m.config)
|
||||
res.add "|"
|
||||
it = it[0]
|
||||
result = makeCString(res)
|
||||
@@ -1343,7 +1355,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
|
||||
let prefixTI = if m.hcrOn: "(" else: "(&"
|
||||
|
||||
let sig = hashType(origType)
|
||||
let sig = hashType(origType, m.config)
|
||||
result = m.typeInfoMarkerV2.getOrDefault(sig)
|
||||
if result != nil:
|
||||
return prefixTI.rope & result & ")".rope
|
||||
@@ -1414,7 +1426,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
|
||||
let prefixTI = if m.hcrOn: "(" else: "(&"
|
||||
|
||||
let sig = hashType(origType)
|
||||
let sig = hashType(origType, m.config)
|
||||
result = m.typeInfoMarker.getOrDefault(sig)
|
||||
if result != nil:
|
||||
return prefixTI.rope & result & ")".rope
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
||||
injectdestructors, astmsgs
|
||||
injectdestructors, astmsgs, modulepaths
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import spawn, semparallel
|
||||
@@ -48,8 +48,13 @@ proc addForwardedProc(m: BModule, prc: PSym) =
|
||||
m.g.forwardedProcs.add(prc)
|
||||
|
||||
proc findPendingModule(m: BModule, s: PSym): BModule =
|
||||
let ms = s.itemId.module #getModule(s)
|
||||
result = m.g.modules[ms]
|
||||
# TODO fixme
|
||||
if m.config.symbolFiles == v2Sf:
|
||||
let ms = s.itemId.module #getModule(s)
|
||||
result = m.g.modules[ms]
|
||||
else:
|
||||
var ms = getModule(s)
|
||||
result = m.g.modules[ms.position]
|
||||
|
||||
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
|
||||
result.k = k
|
||||
@@ -154,6 +159,11 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
inc(i)
|
||||
result.add newCall(formatValue, resVar, args[num])
|
||||
inc(num)
|
||||
of '^':
|
||||
flushStrLit()
|
||||
inc(i)
|
||||
result.add newCall(formatValue, resVar, args[^1])
|
||||
inc(num)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
@@ -297,6 +307,12 @@ proc lenExpr(p: BProc; a: TLoc): Rope =
|
||||
else:
|
||||
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
|
||||
|
||||
proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
result = "(" & sym & ").p"
|
||||
else:
|
||||
result = sym
|
||||
|
||||
proc dataField(p: BProc): Rope =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
result = rope".p->data"
|
||||
@@ -363,7 +379,8 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||
else:
|
||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
||||
of frEmbedded:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
# inheritance in C++ does not allow struct initialization: bug #18410
|
||||
if not p.module.compileToCpp and optTinyRtti in p.config.globalOptions:
|
||||
var tmp: TLoc
|
||||
if mode == constructRefObj:
|
||||
let objType = t.skipTypes(abstractInst+{tyRef})
|
||||
@@ -442,8 +459,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
if containsGarbageCollectedRef(loc.t):
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
@@ -864,7 +887,7 @@ proc containsResult(n: PNode): bool =
|
||||
if containsResult(n[i]): return true
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt} +
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
|
||||
declarativeDefs
|
||||
|
||||
proc easyResultAsgn(n: PNode): PNode =
|
||||
@@ -1022,7 +1045,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast[resultPos]
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ[0]):
|
||||
if not isInvalidReturnType(m.config, prc.typ):
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
@@ -1036,7 +1059,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
else:
|
||||
fillResult(p.config, resNode)
|
||||
fillResult(p.config, resNode, prc.typ)
|
||||
assignParam(p, res, prc.typ[0])
|
||||
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
|
||||
# to 'unsureAsgn(result, x)'
|
||||
@@ -1285,17 +1308,19 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L")
|
||||
addNimDefines(result, conf)
|
||||
|
||||
proc getSomeNameForModule(m: PSym): Rope =
|
||||
assert m.kind == skModule
|
||||
assert m.owner.kind == skPackage
|
||||
if {sfSystemModule, sfMainModule} * m.flags == {}:
|
||||
result = m.owner.name.s.mangle.rope
|
||||
result.add "_"
|
||||
result.add m.name.s.mangle
|
||||
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
|
||||
## Returns a mangled module name.
|
||||
result.add mangleModuleName(conf, filename).mangle
|
||||
|
||||
proc getSomeNameForModule(m: BModule): Rope =
|
||||
## Returns a mangled module name.
|
||||
assert m.module.kind == skModule
|
||||
assert m.module.owner.kind == skPackage
|
||||
result.add mangleModuleName(m.g.config, m.filename).mangle
|
||||
|
||||
proc getSomeInitName(m: BModule, suffix: string): Rope =
|
||||
if not m.hcrOn:
|
||||
result = getSomeNameForModule(m.module)
|
||||
result = getSomeNameForModule(m)
|
||||
result.add suffix
|
||||
|
||||
proc getInitName(m: BModule): Rope =
|
||||
@@ -1346,20 +1371,29 @@ proc genMainProc(m: BModule) =
|
||||
# The use of a volatile function pointer to call Pre/NimMainInner
|
||||
# prevents inlining of the NimMainInner function and dependent
|
||||
# functions, which might otherwise merge their stack frames.
|
||||
PreMainBody = "$N" &
|
||||
|
||||
PreMainVolatileBody =
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$1" &
|
||||
"\t(*inner)();$N"
|
||||
|
||||
PreMainNonVolatileBody =
|
||||
"$1" &
|
||||
"\tPreMainInner();$N"
|
||||
|
||||
PreMainBodyStart = "$N" &
|
||||
"N_LIB_PRIVATE void PreMainInner(void) {$N" &
|
||||
"$2" &
|
||||
"}$N$N" &
|
||||
PosixCmdLine &
|
||||
"N_LIB_PRIVATE void PreMain(void) {$N" &
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$1" &
|
||||
"\t(*inner)();$N" &
|
||||
"N_LIB_PRIVATE void PreMain(void) {$N"
|
||||
|
||||
PreMainBodyEnd =
|
||||
"}$N$N"
|
||||
|
||||
MainProcs =
|
||||
"\tNimMain();$N"
|
||||
"\t$^NimMain();$N"
|
||||
|
||||
MainProcsWithResult =
|
||||
MainProcs & ("\treturn $1nim_program_result;$N")
|
||||
@@ -1368,17 +1402,32 @@ proc genMainProc(m: BModule) =
|
||||
"$1" &
|
||||
"}$N$N"
|
||||
|
||||
NimMainProc =
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"$4" &
|
||||
"\tinner = NimMainInner;$N" &
|
||||
"$2" &
|
||||
"\t(*inner)();$N" &
|
||||
NimMainVolatileBody =
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"$4" &
|
||||
"\tinner = NimMainInner;$N" &
|
||||
"$2" &
|
||||
"\t(*inner)();$N"
|
||||
|
||||
NimMainNonVolatileBody =
|
||||
"$4" &
|
||||
"$2" &
|
||||
"\tNimMainInner();$N"
|
||||
|
||||
NimMainProcStart =
|
||||
"N_CDECL(void, $5NimMain)(void) {$N"
|
||||
|
||||
NimMainProcEnd =
|
||||
"}$N$N"
|
||||
|
||||
NimMainProc = NimMainProcStart & NimMainVolatileBody & NimMainProcEnd
|
||||
|
||||
NimSlimMainProc = NimMainProcStart & NimMainNonVolatileBody & NimMainProcEnd
|
||||
|
||||
NimMainBody = NimMainInner & NimMainProc
|
||||
|
||||
NimSlimMainBody = NimMainInner & NimSlimMainProc
|
||||
|
||||
PosixCMain =
|
||||
"int main(int argc, char** args, char** env) {$N" &
|
||||
"\tcmdLine = args;$N" &
|
||||
@@ -1439,38 +1488,45 @@ proc genMainProc(m: BModule) =
|
||||
m.includeHeader("<libc/component.h>")
|
||||
|
||||
let initStackBottomCall =
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit])
|
||||
if m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit])
|
||||
else:
|
||||
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit])
|
||||
|
||||
if m.config.target.targetOS == osWindows and
|
||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in m.config.globalOptions:
|
||||
const nimMain = WinNimMain
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
else:
|
||||
const nimMain = WinNimDllMain
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osGenode:
|
||||
const nimMain = GenodeNimMain
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
elif optGenDynLib in m.config.globalOptions:
|
||||
const nimMain = PosixNimDllMain
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osStandalone:
|
||||
const nimMain = NimMainBody
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
else:
|
||||
const nimMain = NimMainBody
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
|
||||
if m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
const nimMain = NimMainBody
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
else:
|
||||
const nimMain = NimSlimMainBody
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
|
||||
if optNoMain notin m.config.globalOptions:
|
||||
if m.config.cppCustomNamespace.len > 0:
|
||||
@@ -1480,23 +1536,22 @@ proc genMainProc(m: BModule) =
|
||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in m.config.globalOptions:
|
||||
const otherMain = WinCMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
|
||||
else:
|
||||
const otherMain = WinCDllMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osGenode:
|
||||
const otherMain = ComponentConstruct
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif optGenDynLib in m.config.globalOptions:
|
||||
const otherMain = PosixCDllMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osStandalone:
|
||||
const otherMain = StandaloneCMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
else:
|
||||
const otherMain = PosixCMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
|
||||
|
||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
|
||||
|
||||
if m.config.cppCustomNamespace.len > 0:
|
||||
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
|
||||
@@ -1504,11 +1559,11 @@ proc genMainProc(m: BModule) =
|
||||
proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) =
|
||||
## Called from the IC backend.
|
||||
if HasDatInitProc in flags:
|
||||
let datInit = getSomeNameForModule(m) & "DatInit000"
|
||||
let datInit = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "DatInit000"
|
||||
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
|
||||
g.mainDatInit.addf("\t$1();$N", [datInit])
|
||||
if HasModuleInitProc in flags:
|
||||
let init = getSomeNameForModule(m) & "Init000"
|
||||
let init = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "Init000"
|
||||
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
|
||||
let initCall = "\t$1();$N" % [init]
|
||||
if sfMainModule in m.flags:
|
||||
@@ -1545,7 +1600,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
hcrModuleMeta.addf("\t\"\"};$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
|
||||
[($sigHash(m.module)).rope])
|
||||
[($sigHash(m.module, m.config)).rope])
|
||||
if sfMainModule in m.module.flags:
|
||||
g.mainModProcs.add(hcrModuleMeta)
|
||||
g.mainModProcs.addf("static void* hcr_handle;$N", [])
|
||||
@@ -1878,7 +1933,7 @@ proc writeHeader(m: BModule) =
|
||||
|
||||
if optGenDynLib in m.config.globalOptions:
|
||||
result.add("N_LIB_IMPORT ")
|
||||
result.addf("N_CDECL(void, NimMain)(void);$n", [])
|
||||
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
|
||||
if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
if not writeRope(result, m.filename):
|
||||
@@ -1889,7 +1944,7 @@ proc getCFile(m: BModule): AbsoluteFile =
|
||||
if m.compileToCpp: ".nim.cpp"
|
||||
elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m"
|
||||
else: ".nim.c"
|
||||
result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
|
||||
result = changeFileExt(completeCfilePath(m.config, mangleModuleName(m.config, m.cfilename).AbsoluteFile), ext)
|
||||
|
||||
when false:
|
||||
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
|
||||
@@ -2042,7 +2097,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
discard cgsym(m, "rawWrite")
|
||||
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
discard cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
discard cgsym(m, "initThreadVarsEmulation")
|
||||
|
||||
@@ -46,6 +46,7 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
# replace ordinary method by dispatcher method:
|
||||
let disp = getDispatcher(result[0].sym)
|
||||
if disp != nil:
|
||||
result[0].typ = disp.typ
|
||||
result[0].sym = disp
|
||||
# change the arguments to up/downcasts to fit the dispatcher's parameters:
|
||||
for i in 1..<result.len:
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
# yield 2
|
||||
# if :unrollFinally: # This node is created by `newEndFinallyNode`
|
||||
# if :curExc.isNil:
|
||||
# return :tmpResult
|
||||
# if nearestFinally == 0:
|
||||
# return :tmpResult
|
||||
# else:
|
||||
# :state = nearestFinally # bubble up
|
||||
# else:
|
||||
# closureIterSetupExc(nil)
|
||||
# raise
|
||||
@@ -804,7 +807,10 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
||||
# Generate the following code:
|
||||
# if :unrollFinally:
|
||||
# if :curExc.isNil:
|
||||
# return :tmpResult
|
||||
# if nearestFinally == 0:
|
||||
# return :tmpResult
|
||||
# else:
|
||||
# :state = nearestFinally # bubble up
|
||||
# else:
|
||||
# raise
|
||||
let curExc = ctx.newCurExcAccess()
|
||||
@@ -813,11 +819,20 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
||||
let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode)
|
||||
cmp.typ = ctx.g.getSysType(info, tyBool)
|
||||
|
||||
let asgn = newTree(nkFastAsgn,
|
||||
newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info),
|
||||
ctx.newTmpResultAccess())
|
||||
let retStmt =
|
||||
if ctx.nearestFinally == 0:
|
||||
# last finally, we can return
|
||||
let retValue = if ctx.fn.typ[0].isNil:
|
||||
ctx.g.emptyNode
|
||||
else:
|
||||
newTree(nkFastAsgn,
|
||||
newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info),
|
||||
ctx.newTmpResultAccess())
|
||||
newTree(nkReturnStmt, retValue)
|
||||
else:
|
||||
# bubble up to next finally
|
||||
newTree(nkGotoState, ctx.g.newIntLit(info, ctx.nearestFinally))
|
||||
|
||||
let retStmt = newTree(nkReturnStmt, asgn)
|
||||
let branch = newTree(nkElifBranch, cmp, retStmt)
|
||||
|
||||
let nullifyExc = newTree(nkCall, newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")), nilnode)
|
||||
@@ -861,6 +876,13 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
|
||||
of nkSkip:
|
||||
discard
|
||||
of nkTryStmt:
|
||||
if n.hasYields:
|
||||
# the inner try will handle these transformations
|
||||
discard
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
n[i] = ctx.transformReturnsInTry(n[i])
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
n[i] = ctx.transformReturnsInTry(n[i])
|
||||
@@ -1130,7 +1152,7 @@ proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: P
|
||||
result = newType(tyArray, nextTypeId(idgen), owner)
|
||||
|
||||
let rng = newType(tyRange, nextTypeId(idgen), owner)
|
||||
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n))
|
||||
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
|
||||
rng.rawAddSon(t)
|
||||
|
||||
result.rawAddSon(rng)
|
||||
@@ -1347,20 +1369,24 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
|
||||
# detect: 'finally: raises X' which is currently not supported. We produce
|
||||
# an error for this case for now. All this will be done properly with Yuriy's
|
||||
# patch.
|
||||
|
||||
result = n
|
||||
case n.kind
|
||||
of nkTryStmt:
|
||||
let f = n.lastSon
|
||||
var didAddSomething = false
|
||||
if f.kind == nkFinally:
|
||||
c.finallys.add f.lastSon
|
||||
didAddSomething = true
|
||||
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
|
||||
if f.kind == nkFinally:
|
||||
if didAddSomething:
|
||||
discard c.finallys.pop()
|
||||
|
||||
of nkWhileStmt, nkBlockStmt:
|
||||
if n.hasYields == false: return n
|
||||
c.blocks.add((n, c.finallys.len))
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
@@ -1384,7 +1410,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for i in countdown(c.finallys.high, fin):
|
||||
var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info, idgen: c.idgen)
|
||||
result.add freshVars(preprocess(c, c.finallys[i]), vars)
|
||||
result.add freshVars(copyTree(c.finallys[i]), vars)
|
||||
c.idgen = vars.idgen
|
||||
result.add n
|
||||
of nkSkip: discard
|
||||
|
||||
@@ -64,7 +64,8 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
if conf.cmd == cmdNimscript: return false
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars(conf)
|
||||
if conf.backend != backendJs: # bug #19059
|
||||
extccomp.initVars(conf)
|
||||
self.processCmdLine(passCmd2, "", conf)
|
||||
if conf.cmd == cmdNone:
|
||||
rawMessage(conf, errGenerated, "command missing")
|
||||
|
||||
@@ -113,7 +113,7 @@ const
|
||||
errInvalidCmdLineOption = "invalid command line option: '$1'"
|
||||
errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
|
||||
errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
|
||||
errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found"
|
||||
errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found"
|
||||
|
||||
proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
||||
if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
|
||||
@@ -238,7 +238,7 @@ const
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjump', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
|
||||
template warningOptionNoop(switch: string) =
|
||||
warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch)
|
||||
@@ -248,7 +248,7 @@ template deprecatedAlias(oldName, newName: string) =
|
||||
|
||||
proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
|
||||
case switch.normalize
|
||||
of "gc":
|
||||
of "gc", "mm":
|
||||
case arg.normalize
|
||||
of "boehm": result = conf.selectedGC == gcBoehm
|
||||
of "refc": result = conf.selectedGC == gcRefc
|
||||
@@ -596,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
|
||||
of "project":
|
||||
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
|
||||
of "gc":
|
||||
of "gc", "mm":
|
||||
if conf.backend == backendJs: return # for: bug #16033
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -885,8 +885,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
splitSwitch(conf, arg, key, val, pass, info)
|
||||
os.putEnv(key, val)
|
||||
of "cc":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
setCC(conf, arg, info)
|
||||
if conf.backend != backendJs: # bug #19330
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
setCC(conf, arg, info)
|
||||
of "track":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
track(conf, arg, info)
|
||||
@@ -1051,7 +1052,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info)
|
||||
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
|
||||
handleStdinInput(conf)
|
||||
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
|
||||
of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
|
||||
of "nimmainprefix": conf.nimMainPrefix = arg
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
@@ -1088,6 +1090,8 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
else:
|
||||
if pass == passCmd1: config.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
if p.key.endsWith(".nims"):
|
||||
incl(config.globalOptions, optWasNimscript)
|
||||
# support UNIX style filenames everywhere for portable build scripts:
|
||||
if config.projectName.len == 0:
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
|
||||
@@ -138,3 +138,6 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasHintAll")
|
||||
defineSymbol("nimHasTrace")
|
||||
defineSymbol("nimHasEffectsOf")
|
||||
|
||||
defineSymbol("nimHasEnforceNoRaises")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import
|
||||
options, ast, ropes, idents, passes, modulepaths, pathutils
|
||||
import options, ast, ropes, passes, pathutils, msgs, lineinfos
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
import modulegraphs
|
||||
|
||||
import std/[os, strutils, parseutils]
|
||||
import std/private/globs
|
||||
|
||||
type
|
||||
TGen = object of PPassContext
|
||||
@@ -28,6 +30,50 @@ proc addDependencyAux(b: Backend; importing, imported: string) =
|
||||
b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)])
|
||||
# s1 -> s2_4[label="[0-9]"];
|
||||
|
||||
proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
const stdPrefix = "std/"
|
||||
const pkgPrefix = "pkg/"
|
||||
if isStdlib:
|
||||
let sub = "lib/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
doAssert false
|
||||
else:
|
||||
start += sub.len
|
||||
let base = s[start..^1]
|
||||
|
||||
if base.startsWith("system") or base.startsWith("std"):
|
||||
result = base
|
||||
else:
|
||||
for dir in stdlibDirs:
|
||||
if base.startsWith(dir):
|
||||
return stdPrefix & base.splitFile.name
|
||||
|
||||
result = stdPrefix & base
|
||||
else:
|
||||
var sub = getEnv("NIMBLE_DIR")
|
||||
if sub.len == 0:
|
||||
sub = ".nimble/pkgs/"
|
||||
else:
|
||||
sub.add "/pkgs/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
result = s
|
||||
else:
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
|
||||
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
doAssert n.kind == nkSym, $n.kind
|
||||
|
||||
let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex))
|
||||
let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex))
|
||||
let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module))
|
||||
let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
|
||||
addDependencyAux(b, parent, child)
|
||||
|
||||
proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
let g = PGen(c)
|
||||
@@ -35,11 +81,9 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkImportStmt:
|
||||
for i in 0..<n.len:
|
||||
var imported = getModuleName(g.config, n[i])
|
||||
addDependencyAux(b, g.module.name.s, imported)
|
||||
addDependency(c, g, b, n[i])
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
var imported = getModuleName(g.config, n[0])
|
||||
addDependencyAux(b, g.module.name.s, imported)
|
||||
addDependency(c, g, b, n[0])
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
for i in 0..<n.len: discard addDotDependency(c, n[i])
|
||||
else:
|
||||
|
||||
@@ -16,7 +16,7 @@ import
|
||||
packages/docutils/rst, packages/docutils/rstgen,
|
||||
json, xmltree, trees, types,
|
||||
typesrenderer, astalgo, lineinfos, intsets,
|
||||
pathutils, tables, nimpaths, renderverbatim, osproc
|
||||
pathutils, tables, nimpaths, renderverbatim, osproc, packages
|
||||
import packages/docutils/rstast except FileIndex, TLineInfo
|
||||
|
||||
from uri import encodeUrl
|
||||
@@ -221,6 +221,7 @@ template declareClosures =
|
||||
of meInvalidDirective: k = errRstInvalidDirectiveX
|
||||
of meInvalidField: k = errRstInvalidField
|
||||
of meFootnoteMismatch: k = errRstFootnoteMismatch
|
||||
of meSandboxedDirective: k = errRstSandboxedDirective
|
||||
of mwRedefinitionOfLabel: k = warnRstRedefinitionOfLabel
|
||||
of mwUnknownSubstitution: k = warnRstUnknownSubstitutionX
|
||||
of mwBrokenLink: k = warnRstBrokenLink
|
||||
@@ -265,7 +266,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
result.cache = cache
|
||||
result.outDir = conf.outDir.string
|
||||
result.isPureRst = isPureRst
|
||||
var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown}
|
||||
var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown, roSandboxDisabled}
|
||||
if not isPureRst: options.incl roNimFile
|
||||
result.sharedState = newRstSharedState(
|
||||
options, filename.string,
|
||||
@@ -274,6 +275,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
conf.configVars, filename.string,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics") and
|
||||
conf.configVars.hasKey("doc.plausibleAnalytics"):
|
||||
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics"):
|
||||
result.analytics = """
|
||||
<script>
|
||||
@@ -287,6 +292,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
|
||||
</script>
|
||||
""" % [conf.configVars.getOrDefault"doc.googleAnalytics"]
|
||||
elif conf.configVars.hasKey("doc.plausibleAnalytics"):
|
||||
result.analytics = """
|
||||
<script defer data-domain="$1" src="https://plausible.io/js/plausible.js"></script>
|
||||
""" % [conf.configVars.getOrDefault"doc.plausibleAnalytics"]
|
||||
else:
|
||||
result.analytics = ""
|
||||
|
||||
@@ -394,9 +403,6 @@ proc getPlainDocstring(n: PNode): string =
|
||||
result = getPlainDocstring(n[i])
|
||||
if result.len > 0: return
|
||||
|
||||
proc belongsToPackage(conf: ConfigRef; module: PSym): bool =
|
||||
result = module.kind == skModule and module.getnimblePkgId == conf.mainPackageId
|
||||
|
||||
proc externalDep(d: PDoc; module: PSym): string =
|
||||
if optWholeProject in d.conf.globalOptions or d.conf.docRoot.len > 0:
|
||||
let full = AbsoluteFile toFullPath(d.conf, FileIndex module.position)
|
||||
@@ -452,7 +458,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
|
||||
"\\spanIdentifier{$1}", [escLit, procLink])
|
||||
elif s != nil and s.kind in {skType, skVar, skLet, skConst} and
|
||||
sfExported in s.flags and s.owner != nil and
|
||||
belongsToPackage(d.conf, s.owner) and d.target == outHtml:
|
||||
belongsToProjectPackage(d.conf, s.owner) and d.target == outHtml:
|
||||
let external = externalDep(d, s.owner)
|
||||
result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>",
|
||||
[changeFileExt(external, "html"), literal,
|
||||
@@ -1040,7 +1046,7 @@ proc traceDeps(d: PDoc, it: PNode) =
|
||||
for x in it[2]:
|
||||
a[2] = x
|
||||
traceDeps(d, a)
|
||||
elif it.kind == nkSym and belongsToPackage(d.conf, it.sym):
|
||||
elif it.kind == nkSym and belongsToProjectPackage(d.conf, it.sym):
|
||||
let external = externalDep(d, it.sym)
|
||||
if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ")
|
||||
dispA(d.conf, d.section[k].finalMarkup,
|
||||
@@ -1050,7 +1056,7 @@ proc traceDeps(d: PDoc, it: PNode) =
|
||||
|
||||
proc exportSym(d: PDoc; s: PSym) =
|
||||
const k = exportSection
|
||||
if s.kind == skModule and belongsToPackage(d.conf, s):
|
||||
if s.kind == skModule and belongsToProjectPackage(d.conf, s):
|
||||
let external = externalDep(d, s)
|
||||
if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ")
|
||||
dispA(d.conf, d.section[k].finalMarkup,
|
||||
@@ -1059,7 +1065,7 @@ proc exportSym(d: PDoc; s: PSym) =
|
||||
changeFileExt(external, "html")])
|
||||
elif s.kind != skModule and s.owner != nil:
|
||||
let module = originatingModule(s)
|
||||
if belongsToPackage(d.conf, module):
|
||||
if belongsToProjectPackage(d.conf, module):
|
||||
let
|
||||
complexSymbol = complexName(s.kind, s.ast, s.name.s)
|
||||
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
||||
@@ -1226,9 +1232,10 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
var str: string
|
||||
renderRstToOut(d[], resolved, str)
|
||||
entry.json[entry.rstField] = %str
|
||||
d.jEntriesFinal.add entry.json
|
||||
d.jEntriesPre[i].rst = nil
|
||||
|
||||
d.jEntriesFinal.add entry.json # generates docs
|
||||
|
||||
proc add(d: PDoc; j: JsonItem) =
|
||||
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
|
||||
|
||||
@@ -1529,7 +1536,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
@@ -1552,7 +1559,7 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
|
||||
@@ -1573,5 +1580,5 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
|
||||
|
||||
try:
|
||||
writeFile(filename, code)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
options, ast, msgs, passes, docgen, lineinfos, pathutils
|
||||
options, ast, msgs, passes, docgen, lineinfos, pathutils, packages
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -23,7 +23,7 @@ type
|
||||
PGen = ref TGen
|
||||
|
||||
proc shouldProcess(g: PGen): bool =
|
||||
(optWholeProject in g.doc.conf.globalOptions and g.module.getnimblePkgId == g.doc.conf.mainPackageId) or
|
||||
(optWholeProject in g.doc.conf.globalOptions and g.doc.conf.belongsToProjectPackage(g.module)) or
|
||||
sfMainModule in g.module.flags or g.config.projectMainIdx == g.module.info.fileIndex
|
||||
|
||||
template closeImpl(body: untyped) {.dirty.} =
|
||||
|
||||
@@ -110,8 +110,8 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
|
||||
else:
|
||||
globalError(conf, info, "cannot map calling convention to FFI")
|
||||
|
||||
template rd(T, p: untyped): untyped = (cast[ptr T](p))[]
|
||||
template wr(T, p, v: untyped): untyped = (cast[ptr T](p))[] = v
|
||||
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
|
||||
template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v
|
||||
template `+!`(x, y: untyped): untyped =
|
||||
cast[pointer](cast[ByteAddress](x) + y)
|
||||
|
||||
@@ -177,8 +177,8 @@ const maxPackDepth = 20
|
||||
var packRecCheck = 0
|
||||
|
||||
proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
|
||||
template awr(T, v: untyped): untyped =
|
||||
wr(T, res, v)
|
||||
template awr(typ, v: untyped): untyped =
|
||||
wr(typ, res, v)
|
||||
|
||||
case typ.kind
|
||||
of tyBool: awr(bool, v.intVal != 0)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
# from a lineinfos file, to provide generalized procedures to compile
|
||||
# nim files.
|
||||
|
||||
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils
|
||||
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
|
||||
|
||||
import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar]
|
||||
import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
|
||||
|
||||
type
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
@@ -367,6 +367,7 @@ proc initVars*(conf: ConfigRef) =
|
||||
|
||||
proc completeCfilePath*(conf: ConfigRef; cfile: AbsoluteFile,
|
||||
createSubDir: bool = true): AbsoluteFile =
|
||||
## Generate the absolute file path to the generated modules.
|
||||
result = completeGeneratedFilePath(conf, cfile, createSubDir)
|
||||
|
||||
proc toObjFile*(conf: ConfigRef; filename: AbsoluteFile): AbsoluteFile =
|
||||
@@ -377,7 +378,7 @@ proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
|
||||
conf.toCompile.add(cf)
|
||||
|
||||
proc addLocalCompileOption*(conf: ConfigRef; option: string; nimfile: AbsoluteFile) =
|
||||
let key = completeCfilePath(conf, withPackageName(conf, nimfile)).string
|
||||
let key = completeCfilePath(conf, mangleModuleName(conf, nimfile).AbsoluteFile).string
|
||||
var value = conf.cfileSpecificOptions.getOrDefault(key)
|
||||
if strutils.find(value, option, 0) < 0:
|
||||
addOpt(value, option)
|
||||
@@ -483,7 +484,10 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} =
|
||||
(conf.target.hostOS == osWindows)
|
||||
|
||||
proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool =
|
||||
conf.backend == backendCpp and not cfile.string.endsWith(".c")
|
||||
# List of possible file extensions taken from gcc
|
||||
for ext in [".C", ".cc", ".cpp", ".CPP", ".c++", ".cp", ".cxx"]:
|
||||
if cfile.string.endsWith(ext): return true
|
||||
false
|
||||
|
||||
proc envFlags(conf: ConfigRef): string =
|
||||
result = if conf.backend == backendCpp:
|
||||
@@ -491,14 +495,14 @@ proc envFlags(conf: ConfigRef): string =
|
||||
else:
|
||||
getEnv("CFLAGS")
|
||||
|
||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
|
||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; isCpp: bool): string =
|
||||
if compiler == ccEnv:
|
||||
result = if useCpp(conf, cfile):
|
||||
result = if isCpp:
|
||||
getEnv("CXX")
|
||||
else:
|
||||
getEnv("CC")
|
||||
else:
|
||||
result = if useCpp(conf, cfile):
|
||||
result = if isCpp:
|
||||
CC[compiler].cppCompiler
|
||||
else:
|
||||
CC[compiler].compilerExe
|
||||
@@ -512,47 +516,36 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
|
||||
result = false # assume an old or crappy GCC
|
||||
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
|
||||
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
|
||||
let (s, exitCode) = try: execCmdEx(exe & " --version") except: ("", 1)
|
||||
# NOTE: should we need the full version, use -dumpfullversion
|
||||
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
|
||||
if exitCode == 0:
|
||||
var i = 0
|
||||
var j = 0
|
||||
# the version is the last part of the first line:
|
||||
while i < s.len and s[i] != '\n':
|
||||
if s[i] in {' ', '\t'}: j = i+1
|
||||
inc i
|
||||
if j > 0:
|
||||
var major = 0
|
||||
while j < s.len and s[j] in {'0'..'9'}:
|
||||
major = major * 10 + (ord(s[j]) - ord('0'))
|
||||
inc j
|
||||
if i < s.len and s[j] == '.': inc j
|
||||
while j < s.len and s[j] in {'0'..'9'}:
|
||||
inc j
|
||||
if j+1 < s.len and s[j] == '.' and s[j+1] in {'0'..'9'}:
|
||||
# we found a third version number, chances are high
|
||||
# we really parsed the version:
|
||||
result = major >= 5
|
||||
var major: int
|
||||
discard parseInt(s, major)
|
||||
result = major >= 5
|
||||
else:
|
||||
result = conf.cCompiler == ccCLang
|
||||
|
||||
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
|
||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||
elif optMixedMode in conf.globalOptions and conf.backend != backendCpp: CC[compiler].cppCompiler
|
||||
else: getCompilerExe(conf, compiler, AbsoluteFile"")
|
||||
else: getCompilerExe(conf, compiler, optMixedMode in conf.globalOptions or conf.backend == backendCpp)
|
||||
|
||||
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
isMainFile = false; produceOutput = false): string =
|
||||
let c = conf.cCompiler
|
||||
let
|
||||
c = conf.cCompiler
|
||||
isCpp = useCpp(conf, cfile.cname)
|
||||
# We produce files like module.nim.cpp, so the absolute Nim filename is not
|
||||
# cfile.name but `cfile.cname.changeFileExt("")`:
|
||||
var options = cFileSpecificOptions(conf, cfile.nimname, cfile.cname.changeFileExt("").string)
|
||||
if useCpp(conf, cfile.cname):
|
||||
if isCpp:
|
||||
# needs to be prepended so that --passc:-std=c++17 can override default.
|
||||
# we could avoid allocation by making cFileSpecificOptions inplace
|
||||
options = CC[c].cppXsupport & ' ' & options
|
||||
# If any C++ file was compiled, we need to use C++ driver for linking as well
|
||||
incl conf.globalOptions, optMixedMode
|
||||
|
||||
var exe = getConfigVar(conf, c, ".exe")
|
||||
if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
|
||||
if exe.len == 0: exe = getCompilerExe(conf, c, isCpp)
|
||||
|
||||
if needsExeExt(conf): exe = addFileExt(exe, "exe")
|
||||
if (optGenDynLib in conf.globalOptions or (conf.hcrOn and not isMainFile)) and
|
||||
@@ -572,7 +565,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
|
||||
compilePattern = joinPath(conf.cCompilerPath, exe)
|
||||
else:
|
||||
compilePattern = getCompilerExe(conf, c, cfile.cname)
|
||||
compilePattern = getCompilerExe(conf, c, isCpp)
|
||||
|
||||
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
|
||||
|
||||
@@ -634,7 +627,7 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
|
||||
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good
|
||||
|
||||
let hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
|
||||
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
|
||||
let currentHash = footprint(conf, cfile)
|
||||
var f: File
|
||||
if open(f, hashFile.string, fmRead):
|
||||
@@ -649,8 +642,10 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
close(f)
|
||||
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
|
||||
# we want to generate the hash file unconditionally
|
||||
let extFileChanged = externalFileChanged(conf, c)
|
||||
if optForceFullMake notin conf.globalOptions and fileExists(c.obj) and
|
||||
not externalFileChanged(conf, c):
|
||||
not extFileChanged:
|
||||
c.flags.incl CfileFlag.Cached
|
||||
else:
|
||||
# make sure Nim keeps recompiling the external file on reruns
|
||||
@@ -840,9 +835,9 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
|
||||
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
|
||||
if conf.hasHint(hintCC):
|
||||
if optListCmd in conf.globalOptions or conf.verbosity > 1:
|
||||
result = MsgKindToStr[hintCC] % (demanglePackageName(path.splitFile.name) & ": " & compileCmd)
|
||||
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
|
||||
else:
|
||||
result = MsgKindToStr[hintCC] % demanglePackageName(path.splitFile.name)
|
||||
result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name)
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef) =
|
||||
var
|
||||
@@ -1011,7 +1006,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
var bcache: BuildCache
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except:
|
||||
except ValueError, KeyError, JsonKindError:
|
||||
let e = getCurrentException()
|
||||
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
|
||||
[e.msg, e.getStackTrace(), jsonFile.string]
|
||||
|
||||
@@ -90,13 +90,13 @@ proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId =
|
||||
t.vals.add v
|
||||
|
||||
|
||||
proc `[]`*[T](t: var BiTable[T]; LitId: LitId): var T {.inline.} =
|
||||
let idx = idToIdx LitId
|
||||
proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} =
|
||||
let idx = idToIdx litId
|
||||
assert idx < t.vals.len
|
||||
result = t.vals[idx]
|
||||
|
||||
proc `[]`*[T](t: BiTable[T]; LitId: LitId): lent T {.inline.} =
|
||||
let idx = idToIdx LitId
|
||||
proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} =
|
||||
let idx = idToIdx litId
|
||||
assert idx < t.vals.len
|
||||
result = t.vals[idx]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import std/packedsets, algorithm, tables
|
||||
|
||||
import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen,
|
||||
pathutils, extccomp, msgs]
|
||||
pathutils, extccomp, msgs, modulepaths]
|
||||
|
||||
import packed_ast, ic, dce, rodfiles
|
||||
|
||||
@@ -61,7 +61,8 @@ proc addFileToLink(config: ConfigRef; m: PSym) =
|
||||
if config.backend == backendCpp: ".nim.cpp"
|
||||
elif config.backend == backendObjc: ".nim.m"
|
||||
else: ".nim.c"
|
||||
let cfile = changeFileExt(completeCfilePath(config, withPackageName(config, filename)), ext)
|
||||
let cfile = changeFileExt(completeCfilePath(config,
|
||||
mangleModuleName(config, filename).AbsoluteFile), ext)
|
||||
let objFile = completeCfilePath(config, toObjFile(config, cfile))
|
||||
if fileExists(objFile):
|
||||
var cf = Cfile(nimname: m.name.s, cname: cfile,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import hashes, tables, intsets, std/sha1
|
||||
import packed_ast, bitabs, rodfiles
|
||||
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
|
||||
pathutils, condsyms]
|
||||
pathutils, condsyms, packages, modulepaths]
|
||||
#import ".." / [renderer, astalgo]
|
||||
from os import removeFile, isAbsolute
|
||||
|
||||
@@ -548,6 +548,10 @@ proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) =
|
||||
rawMessage(config, warnCannotOpenFile, filename.string & " reason: " & $err)
|
||||
#echo "Error: ", $err, " loading file: ", filename.string
|
||||
|
||||
proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
|
||||
result = changeFileExt(completeGeneratedFilePath(conf,
|
||||
mangleModuleName(conf, f).AbsoluteFile), ext)
|
||||
|
||||
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
|
||||
ignoreConfig = false): RodFileError =
|
||||
var f = rodfiles.open(filename.string)
|
||||
@@ -927,17 +931,6 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
|
||||
result = g[si].types[t.item]
|
||||
assert result.itemId.item > 0
|
||||
|
||||
proc newPackage(config: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
let filename = AbsoluteFile toFullPath(config, fileIdx)
|
||||
let name = getIdent(cache, splitFile(filename).name)
|
||||
let info = newLineInfo(fileIdx, 1, 1)
|
||||
let
|
||||
pck = getPackageName(config, filename.string)
|
||||
pck2 = if pck.len > 0: pck else: "unknown"
|
||||
pack = getIdent(cache, pck2)
|
||||
result = newSym(skPackage, getIdent(cache, pck2),
|
||||
ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
|
||||
|
||||
proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
fileIdx: FileIndex; m: var LoadedModule) =
|
||||
m.iface = initTable[PIdent, seq[PackedItemId]]()
|
||||
@@ -965,7 +958,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
|
||||
name: getIdent(cache, splitFile(filename).name),
|
||||
info: newLineInfo(fileIdx, 1, 1),
|
||||
position: int(fileIdx))
|
||||
m.module.owner = newPackage(conf, cache, fileIdx)
|
||||
m.module.owner = getPackage(conf, cache, fileIdx)
|
||||
m.module.flags = m.fromDisk.moduleFlags
|
||||
|
||||
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
|
||||
@@ -34,8 +34,7 @@ from typetraits import supportsCopyMem
|
||||
##
|
||||
## Now read the bits below to understand what's missing.
|
||||
##
|
||||
## Issues with the Example
|
||||
## ```````````````````````
|
||||
## ### Issues with the Example
|
||||
## Missing Sections:
|
||||
## This is a low level API, so headers and sections need to be stored and
|
||||
## loaded by the user, see `storeHeader` & `loadHeader` and `storeSection` &
|
||||
|
||||
@@ -185,11 +185,13 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
|
||||
for it in mitems c.graph.ifaces[fromMod.position].converters:
|
||||
if filter:
|
||||
loadPackedSym(c.graph, it)
|
||||
addConverter(c, it)
|
||||
if sfExported in it.sym.flags:
|
||||
addConverter(c, it)
|
||||
for it in mitems c.graph.ifaces[fromMod.position].patterns:
|
||||
if filter:
|
||||
loadPackedSym(c.graph, it)
|
||||
addPattern(c, it)
|
||||
if sfExported in it.sym.flags:
|
||||
addPattern(c, it)
|
||||
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
|
||||
if filter:
|
||||
loadPackedSym(c.graph, it)
|
||||
@@ -197,7 +199,7 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet)
|
||||
addUnnamedIt(c, fromMod, it.sym.id notin exceptSet)
|
||||
addUnnamedIt(c, fromMod, it.sym.name.id notin exceptSet)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
c.addImport ImportedModule(m: fromMod, mode: importAll)
|
||||
|
||||
@@ -275,7 +275,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
|
||||
var op = getAttachedOp(c.graph, t, kind)
|
||||
if op == nil or op.ast.isGenericRoutine:
|
||||
# give up and find the canonical type instead:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||
if canon != nil:
|
||||
op = getAttachedOp(c.graph, canon, kind)
|
||||
@@ -573,7 +573,7 @@ proc processScope(c: var Con; s: var Scope; ret: PNode): PNode =
|
||||
|
||||
template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped): PNode =
|
||||
assert not ret.typ.isEmptyType
|
||||
var result = newNodeI(nkStmtListExpr, ret.info)
|
||||
var result = newNodeIT(nkStmtListExpr, ret.info, ret.typ)
|
||||
# There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0
|
||||
# later and use it to eliminate the temporary when theres no need for it, but its
|
||||
# tricky because you would have to intercept moveOrCopy at a certain point
|
||||
@@ -1018,6 +1018,26 @@ proc sameLocation*(a, b: PNode): bool =
|
||||
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
|
||||
else: false
|
||||
|
||||
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode, isDecl: bool): PNode =
|
||||
# with side effects
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
|
||||
temp.typ = ri[1].typ
|
||||
var v = newNodeI(nkLetSection, ri[1].info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = newNodeI(nkEmpty, tempAsNode.info)
|
||||
vpart[2] = ri[1]
|
||||
v.add(vpart)
|
||||
|
||||
var newAccess = copyNode(ri)
|
||||
newAccess.add ri[0]
|
||||
newAccess.add tempAsNode
|
||||
|
||||
var snk = c.genSink(dest, newAccess, isDecl)
|
||||
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode =
|
||||
if sameLocation(dest, ri):
|
||||
# rule (self-assignment-removal):
|
||||
@@ -1041,8 +1061,11 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
|
||||
if aliases(dest, ri) == no:
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = c.genSink(dest, ri, isDecl)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
if isAtom(ri[1]):
|
||||
var snk = c.genSink(dest, ri, isDecl)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
result = genFieldAccessSideEffects(c, dest, ri, isDecl)
|
||||
else:
|
||||
result = c.genSink(dest, destructiveMoveVar(ri, c, s), isDecl)
|
||||
else:
|
||||
|
||||
@@ -141,5 +141,5 @@ shortDesc: "The Nim Compiler"
|
||||
licenses: "bin/nim,MIT;lib/*,MIT;"
|
||||
|
||||
[nimble]
|
||||
pkgName: "compiler"
|
||||
pkgName: "nim"
|
||||
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css"
|
||||
|
||||
@@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool =
|
||||
var marker = initIntSet()
|
||||
result = canAlias(arg, ret, marker)
|
||||
|
||||
proc containsVariable(n: PNode): bool =
|
||||
case n.kind
|
||||
of nodesToIgnoreSet:
|
||||
result = false
|
||||
of nkSym:
|
||||
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||
else:
|
||||
for ch in n:
|
||||
if containsVariable(ch): return true
|
||||
result = false
|
||||
|
||||
proc checkIsolate*(n: PNode): bool =
|
||||
if types.containsTyRef(n.typ):
|
||||
# XXX Maybe require that 'n.typ' is acyclic. This is not much
|
||||
@@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool =
|
||||
else:
|
||||
let argType = n[i].typ
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
|
||||
if argType.canAlias(n.typ):
|
||||
if argType.canAlias(n.typ) or containsVariable(n[i]):
|
||||
# bug #19013: Alias information is not enough, we need to check for potential
|
||||
# "overlaps". I claim the problem can only happen by reading again from a location
|
||||
# that materialized which is only possible if a variable that contains a `ref`
|
||||
# is involved.
|
||||
return false
|
||||
result = true
|
||||
of nkIfStmt, nkIfExpr:
|
||||
|
||||
@@ -178,7 +178,7 @@ const
|
||||
proc mapType(typ: PType): TJSTypeKind =
|
||||
let t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyVar, tyRef, tyPtr, tyLent:
|
||||
of tyVar, tyRef, tyPtr:
|
||||
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
|
||||
result = etyObject
|
||||
else:
|
||||
@@ -186,7 +186,8 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||
of tyPointer:
|
||||
# treat a tyPointer like a typed pointer to an array of bytes
|
||||
result = etyBaseIndex
|
||||
of tyRange, tyDistinct, tyOrdinal, tyProxy:
|
||||
of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
|
||||
# tyLent is no-op as JS has pass-by-reference semantics
|
||||
result = mapType(t[0])
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
|
||||
of tyBool: result = etyBool
|
||||
@@ -258,7 +259,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
|
||||
if m.config.hcrOn:
|
||||
# When hot reloading is enabled, we must ensure that the names
|
||||
# of functions and types will be preserved across rebuilds:
|
||||
result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
|
||||
result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config))
|
||||
else:
|
||||
result.add("_")
|
||||
result.add(rope(s.id))
|
||||
@@ -1060,14 +1061,14 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
xtyp = etySeq
|
||||
case xtyp
|
||||
of etySeq:
|
||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
@@ -1092,10 +1093,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
elif a.typ == etyBaseIndex:
|
||||
# array indexing may not map to var type
|
||||
if b.address != nil:
|
||||
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
else:
|
||||
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
|
||||
else:
|
||||
elif b.address != nil:
|
||||
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
|
||||
@@ -1442,13 +1451,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if s.loc.r == nil:
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
r.res = s.loc.r
|
||||
if mapType(p, s.typ) == etyBaseIndex:
|
||||
r.address = s.loc.r
|
||||
r.res = s.loc.r & "_Idx"
|
||||
else:
|
||||
r.res = s.loc.r
|
||||
r.kind = resVal
|
||||
|
||||
proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let it = n[0]
|
||||
let t = mapType(p, it.typ)
|
||||
if t == etyObject:
|
||||
if t == etyObject or it.typ.kind == tyLent:
|
||||
gen(p, it, r)
|
||||
else:
|
||||
var a: TCompRes
|
||||
@@ -1689,7 +1702,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result = putToSeq("0", indirect)
|
||||
of tyFloat..tyFloat128:
|
||||
result = putToSeq("0.0", indirect)
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
|
||||
result = createVar(p, lastSon(typ), indirect)
|
||||
of tySet:
|
||||
result = putToSeq("{}", indirect)
|
||||
@@ -1731,7 +1744,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
createObjInitList(p, t, initIntSet(), initList)
|
||||
result = ("({$1})") % [initList]
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyVar, tyPtr, tyLent, tyRef, tyPointer:
|
||||
of tyVar, tyPtr, tyRef, tyPointer:
|
||||
if mapType(p, t) == etyBaseIndex:
|
||||
result = putToSeq("[null, 0]", indirect)
|
||||
else:
|
||||
@@ -2380,9 +2393,11 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
if prc.typ[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast[resultPos].sym
|
||||
let mname = mangleName(p.module, resultSym)
|
||||
if not isIndirect(resultSym) and
|
||||
# otherwise uses "fat pointers"
|
||||
let useRawPointer = not isIndirect(resultSym) and
|
||||
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
|
||||
mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
mapType(p, resultSym.typ) == etyBaseIndex
|
||||
if useRawPointer:
|
||||
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
|
||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||
else:
|
||||
@@ -2565,8 +2580,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkObjConstr: genObjConstr(p, n, r)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
genAddr(p, n, r)
|
||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
|
||||
if n.typ.kind in {tyLent}:
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
genAddr(p, n, r)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
if n.typ.kind in {tyLent}:
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
genDeref(p, n, r)
|
||||
of nkBracketExpr: genArrayAccess(p, n, r)
|
||||
of nkDotExpr: genFieldAccess(p, n, r)
|
||||
of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r)
|
||||
@@ -2690,7 +2712,7 @@ proc genModule(p: PProc, n: PNode) =
|
||||
if p.config.hcrOn and n.kind == nkStmtList:
|
||||
let moduleSym = p.module.module
|
||||
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
|
||||
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts)
|
||||
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts, p.config)
|
||||
lineF(p, "var $1;$n", [moduleLoadedVar])
|
||||
var inGuardedBlock = false
|
||||
|
||||
|
||||
@@ -272,16 +272,11 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
addField(obj, s, g.cache, idgen)
|
||||
let field = addField(obj, s, g.cache, idgen)
|
||||
|
||||
var access = newSymNode(envParam)
|
||||
assert obj.kind == tyObject
|
||||
let field = getFieldFromObj(obj, s)
|
||||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, s.info)
|
||||
else:
|
||||
localError(g.config, s.info, "internal error: cannot generate fresh variable")
|
||||
result = access
|
||||
result = rawIndirectAccess(access, field, s.info)
|
||||
|
||||
# ------------------ new stuff -------------------------------------------
|
||||
|
||||
@@ -449,7 +444,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if s.name.id == getIdent(c.graph.cache, ":state").id:
|
||||
obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
else:
|
||||
addField(obj, s, c.graph.cache, c.idgen)
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# direct or indirect dependency:
|
||||
elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s):
|
||||
discard """
|
||||
@@ -471,7 +466,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
addField(obj, s, c.graph.cache, c.idgen)
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# create required upFields:
|
||||
var w = owner.skipGenericOwner
|
||||
if isInnerProc(w) or owner.isIterator:
|
||||
|
||||
@@ -551,11 +551,15 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
if not preventComment:
|
||||
emitComment(em, tok, dontIndent = false)
|
||||
of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit:
|
||||
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
|
||||
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
|
||||
em.lineSpan = countNewlines(lit)
|
||||
if em.lineSpan > 0: calcCol(em, lit)
|
||||
wr em, lit, ltLit
|
||||
if not em.inquote:
|
||||
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
|
||||
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
|
||||
em.lineSpan = countNewlines(lit)
|
||||
if em.lineSpan > 0: calcCol(em, lit)
|
||||
wr em, lit, ltLit
|
||||
else:
|
||||
if endsInAlpha(em): wrSpace(em)
|
||||
wr em, tok.literal, ltLit
|
||||
of tkEof: discard
|
||||
else:
|
||||
let lit = if tok.ident != nil: tok.ident.s else: tok.literal
|
||||
|
||||
@@ -121,6 +121,8 @@ type
|
||||
cache*: IdentCache
|
||||
when defined(nimsuggest):
|
||||
previousToken: TLineInfo
|
||||
tokenEnd*: TLineInfo
|
||||
previousTokenEnd*: TLineInfo
|
||||
config*: ConfigRef
|
||||
|
||||
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
|
||||
@@ -912,7 +914,7 @@ proc getSymbol(L: var Lexer, tok: var Token) =
|
||||
else: break
|
||||
tokenEnd(tok, pos-1)
|
||||
h = !$h
|
||||
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h)
|
||||
if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
|
||||
(tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
|
||||
tok.tokType = tkSymbol
|
||||
@@ -926,7 +928,7 @@ proc getSymbol(L: var Lexer, tok: var Token) =
|
||||
proc endOperator(L: var Lexer, tok: var Token, pos: int,
|
||||
hash: Hash) {.inline.} =
|
||||
var h = !$hash
|
||||
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h)
|
||||
if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
|
||||
else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon))
|
||||
L.bufpos = pos
|
||||
@@ -1216,6 +1218,10 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
template atTokenEnd() {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
L.previousTokenEnd.line = L.tokenEnd.line
|
||||
L.previousTokenEnd.col = L.tokenEnd.col
|
||||
L.tokenEnd.line = tok.line.uint16
|
||||
L.tokenEnd.col = getColNumber(L, L.bufpos).int16
|
||||
# we attach the cursor to the last *strong* token
|
||||
if tok.tokType notin weakTokens:
|
||||
L.previousToken.line = tok.line.uint16
|
||||
|
||||
@@ -162,9 +162,12 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
|
||||
# the value needs to be destroyed before we assign the selector
|
||||
# or the value is lost
|
||||
let prevKind = c.kind
|
||||
let prevAddMemReset = c.addMemReset
|
||||
c.kind = attachedDestructor
|
||||
c.addMemReset = true
|
||||
fillBodyObj(c, n, body, x, y, enforceDefaultOp = false)
|
||||
c.kind = prevKind
|
||||
c.addMemReset = prevAddMemReset
|
||||
localEnforceDefaultOp = true
|
||||
|
||||
if c.kind != attachedDestructor:
|
||||
@@ -525,7 +528,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# operation here:
|
||||
var t = t
|
||||
if t.assignment == nil or t.destructor == nil:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.g.canonTypes.getOrDefault(h)
|
||||
if canon != nil: t = canon
|
||||
|
||||
@@ -941,6 +944,12 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
|
||||
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yy.typ = xx.typ
|
||||
body.add newAsgnStmt(xx, yy)
|
||||
|
||||
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
@@ -980,6 +989,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
||||
else:
|
||||
fillBody(a, typ, result.ast[bodyPos], d, src)
|
||||
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
|
||||
# bug #19205: Do not forget to also copy the hidden type field:
|
||||
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
|
||||
|
||||
if not a.canRaise: incl result.flags, sfNeverRaises
|
||||
completePartialOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
@@ -1059,7 +1072,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
|
||||
|
||||
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
var canon = g.canonTypes.getOrDefault(h)
|
||||
if canon == nil:
|
||||
g.canonTypes[h] = skipped
|
||||
|
||||
@@ -39,6 +39,7 @@ type
|
||||
errRstInvalidDirectiveX,
|
||||
errRstInvalidField,
|
||||
errRstFootnoteMismatch,
|
||||
errRstSandboxedDirective,
|
||||
errProveInit, # deadcode
|
||||
errGenerated,
|
||||
errUser,
|
||||
@@ -75,7 +76,9 @@ type
|
||||
warnAnyEnumConv = "AnyEnumConv",
|
||||
warnHoleEnumConv = "HoleEnumConv",
|
||||
warnCstringConv = "CStringConv",
|
||||
warnPtrToCstringConv = "PtrToCstringConv",
|
||||
warnEffect = "Effect",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
@@ -109,6 +112,7 @@ const
|
||||
errRstInvalidDirectiveX: "invalid directive: '$1'",
|
||||
errRstInvalidField: "invalid field: $1",
|
||||
errRstFootnoteMismatch: "number of footnotes and their references don't match: $1",
|
||||
errRstSandboxedDirective: "disabled directive: '$1'",
|
||||
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
|
||||
errGenerated: "$1",
|
||||
errUser: "$1",
|
||||
@@ -164,7 +168,9 @@ const
|
||||
warnAnyEnumConv: "$1",
|
||||
warnHoleEnumConv: "$1",
|
||||
warnCstringConv: "$1",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnBareExcept: "$1",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
import std/strutils
|
||||
from std/sugar import dup
|
||||
|
||||
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs
|
||||
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages
|
||||
export packages
|
||||
|
||||
const
|
||||
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
@@ -85,24 +86,33 @@ proc differ*(line: string, a, b: int, x: string): string =
|
||||
result = y
|
||||
|
||||
proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
# operators stay as they are:
|
||||
if k in {skResult, skTemp} or s.name.s[0] notin Letters: return
|
||||
if k in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
if s.typ != nil and s.typ.kind == tyTypeDesc: return
|
||||
if {sfImportc, sfExportc} * s.flags != {}: return
|
||||
if optStyleCheck notin s.options: return
|
||||
let beau = beautifyName(s.name.s, k)
|
||||
if s.name.s != beau:
|
||||
lintReport(conf, info, beau, s.name.s)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {} and optStyleUsages notin conf.globalOptions:
|
||||
nep1CheckDefImpl(conf, info, s, k)
|
||||
template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) =
|
||||
## Check symbol definitions adhere to NEP1 style rules.
|
||||
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
|
||||
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
|
||||
sym.kind != skResult and # ignore `result`
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
|
||||
k notin {skType, skGenericParam} and # ignore types and generic params
|
||||
(sym.typ == nil or sym.typ.kind != tyTypeDesc) and # ignore `typedesc`
|
||||
{sfImportc, sfExportc} * sym.flags == {} and # ignore FFI
|
||||
sfAnon notin sym.flags: # ignore if created by compiler
|
||||
nep1CheckDefImpl(ctx.config, info, sym, k)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
styleCheckDef(conf, info, s, s.kind)
|
||||
template styleCheckDef*(conf: ConfigRef; s: PSym) =
|
||||
styleCheckDef(conf, s.info, s, s.kind)
|
||||
template styleCheckDef*(ctx: PContext; info: TLineInfo; s: PSym) =
|
||||
## Check symbol definitions adhere to NEP1 style rules.
|
||||
styleCheckDef(ctx, info, s, s.kind)
|
||||
|
||||
template styleCheckDef*(ctx: PContext; s: PSym) =
|
||||
## Check symbol definitions adhere to NEP1 style rules.
|
||||
styleCheckDef(ctx, s.info, s, s.kind)
|
||||
|
||||
proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string =
|
||||
let line = sourceLine(conf, info)
|
||||
@@ -116,23 +126,27 @@ proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string =
|
||||
let last = first+identLen(line, first)-1
|
||||
result = differ(line, first, last, newName)
|
||||
|
||||
proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
if info.fileIndex.int < 0: return
|
||||
# we simply convert it to what it looks like in the definition
|
||||
# for consistency
|
||||
|
||||
# operators stay as they are:
|
||||
if s.kind == skTemp or s.name.s[0] notin Letters or sfAnon in s.flags:
|
||||
return
|
||||
|
||||
proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
let newName = s.name.s
|
||||
let badName = differs(conf, info, newName)
|
||||
if badName.len > 0:
|
||||
# special rules for historical reasons
|
||||
let forceHint = badName == "nnkArgList" and newName == "nnkArglist" or badName == "nnkArglist" and newName == "nnkArgList"
|
||||
lintReport(conf, info, newName, badName, forceHint = forceHint, extraMsg = "".dup(addDeclaredLoc(conf, s)))
|
||||
lintReport(conf, info, newName, badName, "".dup(addDeclaredLoc(conf, s)))
|
||||
|
||||
proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
|
||||
## Check symbol uses match their definition's style.
|
||||
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
|
||||
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
|
||||
styleCheckUseImpl(ctx.config, info, sym)
|
||||
|
||||
proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
let wanted = $w
|
||||
if pragmaName != wanted:
|
||||
lintReport(conf, info, wanted, pragmaName)
|
||||
|
||||
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
checkPragmaUseImpl(conf, info, w, pragmaName)
|
||||
|
||||
@@ -44,6 +44,11 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
|
||||
case x.kind
|
||||
of nkIdent: id.add(x.ident.s)
|
||||
of nkSym: id.add(x.sym.name.s)
|
||||
of nkSymChoices:
|
||||
if x[0].kind == nkSym:
|
||||
id.add(x[0].sym.name.s)
|
||||
else:
|
||||
handleError(n, origin)
|
||||
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
|
||||
else: handleError(n, origin)
|
||||
result = getIdent(c.cache, id)
|
||||
|
||||
@@ -71,14 +71,20 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
|
||||
let value = n.lastSon
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
var tempAsNode: PNode
|
||||
let avoidTemp = value.kind == nkSym
|
||||
if avoidTemp:
|
||||
tempAsNode = value
|
||||
else:
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
tempAsNode = newSymNode(temp)
|
||||
|
||||
var v = newNodeI(nkVarSection, value.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
v.addVar(tempAsNode, value)
|
||||
if not avoidTemp:
|
||||
v.addVar(tempAsNode, value)
|
||||
result.add(v)
|
||||
|
||||
for i in 0..<n.len-2:
|
||||
@@ -221,7 +227,7 @@ proc lookupInRecord(n: PNode, id: ItemId): PSym =
|
||||
if n.sym.itemId.module == id.module and n.sym.itemId.item == -abs(id.item): result = n.sym
|
||||
else: discard
|
||||
|
||||
proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) =
|
||||
proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym =
|
||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||
# This is hacky but the clean solution is much more complex than it looks.
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
|
||||
@@ -235,6 +241,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) =
|
||||
field.flags = s.flags * {sfCursor}
|
||||
obj.n.add newSymNode(field)
|
||||
fieldCheck()
|
||||
result = field
|
||||
|
||||
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
|
||||
result = lookupInRecord(obj.n, s.itemId)
|
||||
|
||||
@@ -58,6 +58,9 @@ proc commandCheck(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
conf.setErrorMaxHighMaybe
|
||||
defineSymbol(conf.symbols, "nimcheck")
|
||||
if optWasNimscript in conf.globalOptions:
|
||||
defineSymbol(conf.symbols, "nimscript")
|
||||
defineSymbol(conf.symbols, "nimconfig")
|
||||
semanticPasses(graph) # use an empty backend for semantic checking only
|
||||
compileProject(graph)
|
||||
|
||||
@@ -363,7 +366,8 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook})
|
||||
|
||||
for it in conf.searchPaths: msgWriteln(conf, it.string)
|
||||
of cmdCheck: commandCheck(graph)
|
||||
of cmdCheck:
|
||||
commandCheck(graph)
|
||||
of cmdParse:
|
||||
wantMainModule(conf)
|
||||
discard parseFile(conf.projectMainIdx, cache, conf)
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
## represents a complete Nim project. Single modules can either be kept in RAM
|
||||
## or stored in a rod-file.
|
||||
|
||||
import intsets, tables, hashes, md5
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils
|
||||
import intsets, tables, hashes, md5, sequtils
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
|
||||
import ic / [packed_ast, ic]
|
||||
|
||||
type
|
||||
@@ -50,6 +50,10 @@ type
|
||||
concreteTypes*: seq[FullId]
|
||||
inst*: PInstantiation
|
||||
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
ifaces*: seq[Iface] ## indexed by int32 fileIdx
|
||||
packed*: PackedModuleGraph
|
||||
@@ -64,7 +68,6 @@ type
|
||||
|
||||
startupPackedConfig*: PackedConfig
|
||||
packageSyms*: TStrTable
|
||||
modulesPerPackage*: Table[ItemId, TStrTable]
|
||||
deps*: IntSet # the dependency graph or potentially its transitive closure.
|
||||
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
|
||||
suggestMode*: bool # whether we are in nimsuggest mode or not.
|
||||
@@ -81,6 +84,8 @@ type
|
||||
doStopCompile*: proc(): bool {.closure.}
|
||||
usageSym*: PSym # for nimsuggest
|
||||
owners*: seq[PSym]
|
||||
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
|
||||
suggestErrors*: Table[FileIndex, seq[Suggest]]
|
||||
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
|
||||
systemModule*: PSym
|
||||
sysTypes*: array[TTypeKind, PType]
|
||||
@@ -368,20 +373,9 @@ template getPContext(): untyped =
|
||||
when c is PContext: c
|
||||
else: c.c
|
||||
|
||||
when defined(nimfind):
|
||||
template onUse*(info: TLineInfo; s: PSym) =
|
||||
let c = getPContext()
|
||||
if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
|
||||
|
||||
template onDef*(info: TLineInfo; s: PSym) =
|
||||
let c = getPContext()
|
||||
if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
|
||||
|
||||
template onDefResolveForward*(info: TLineInfo; s: PSym) =
|
||||
let c = getPContext()
|
||||
if c.graph.onDefinitionResolveForward != nil:
|
||||
c.graph.onDefinitionResolveForward(c.graph, s, info)
|
||||
|
||||
when defined(nimsuggest):
|
||||
template onUse*(info: TLineInfo; s: PSym) = discard
|
||||
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
|
||||
else:
|
||||
template onUse*(info: TLineInfo; s: PSym) = discard
|
||||
template onDef*(info: TLineInfo; s: PSym) = discard
|
||||
@@ -432,8 +426,7 @@ proc initOperators*(g: ModuleGraph): Operators =
|
||||
result.opNot = createMagic(g, "not", mNot)
|
||||
result.opContains = createMagic(g, "contains", mInSet)
|
||||
|
||||
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result = ModuleGraph()
|
||||
proc initModuleGraphFields(result: ModuleGraph) =
|
||||
# A module ID of -1 means that the symbol is not attached to a module at all,
|
||||
# but to the module graph:
|
||||
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
|
||||
@@ -443,9 +436,9 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result.ifaces = @[]
|
||||
result.importStack = @[]
|
||||
result.inclToMod = initTable[FileIndex, FileIndex]()
|
||||
result.config = config
|
||||
result.cache = cache
|
||||
result.owners = @[]
|
||||
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
|
||||
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
|
||||
result.methods = @[]
|
||||
initStrTable(result.compilerprocs)
|
||||
initStrTable(result.exposed)
|
||||
@@ -459,6 +452,12 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result.operators = initOperators(result)
|
||||
result.emittedTypeInfo = initTable[string, FileIndex]()
|
||||
|
||||
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result = ModuleGraph()
|
||||
result.config = config
|
||||
result.cache = cache
|
||||
initModuleGraphFields(result)
|
||||
|
||||
proc resetAllModules*(g: ModuleGraph) =
|
||||
initStrTable(g.packageSyms)
|
||||
g.deps = initIntSet()
|
||||
@@ -470,6 +469,7 @@ proc resetAllModules*(g: ModuleGraph) =
|
||||
g.methods = @[]
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
initModuleGraphFields(g)
|
||||
|
||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
if fileIdx.int32 >= 0:
|
||||
@@ -548,7 +548,19 @@ proc transitiveClosure(g: var IntSet; n: int) =
|
||||
|
||||
proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
let m = g.getModule fileIdx
|
||||
if m != nil: incl m.flags, sfDirty
|
||||
if m != nil:
|
||||
g.suggestSymbols.del(fileIdx)
|
||||
g.suggestErrors.del(fileIdx)
|
||||
incl m.flags, sfDirty
|
||||
|
||||
proc unmarkAllDirty*(g: ModuleGraph) =
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil:
|
||||
m.flags.excl sfDirty
|
||||
|
||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||
result = g.suggestMode and sfDirty in m.flags
|
||||
|
||||
proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
# we need to mark its dependent modules D as dirty right away because after
|
||||
@@ -560,12 +572,31 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
|
||||
# every module that *depends* on this file is also dirty:
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)):
|
||||
incl m.flags, sfDirty
|
||||
if g.deps.contains(i.dependsOn(fileIdx.int)):
|
||||
let
|
||||
fi = FileIndex(i)
|
||||
module = g.getModule(fi)
|
||||
if module != nil and not g.isDirty(module):
|
||||
g.markDirty(fi)
|
||||
g.markClientsDirty(fi)
|
||||
|
||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||
result = g.suggestMode and sfDirty in m.flags
|
||||
proc needsCompilation*(g: ModuleGraph): bool =
|
||||
# every module that *depends* on this file is also dirty:
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil:
|
||||
if sfDirty in m.flags:
|
||||
return true
|
||||
|
||||
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
|
||||
let module = g.getModule(fileIdx)
|
||||
if module != nil and g.isDirty(module):
|
||||
return true
|
||||
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil and g.isDirty(m) and g.deps.contains(fileIdx.int32.dependsOn(i)):
|
||||
return true
|
||||
|
||||
proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} =
|
||||
result = s.ast[bodyPos]
|
||||
@@ -594,3 +625,34 @@ proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string,
|
||||
let fromModule2 = if fromModule != nil: $fromModule.name.s else: "(toplevel)"
|
||||
let mode = if isNimscript: "(nims) " else: ""
|
||||
rawMessage(conf, hintProcessing, "$#$# $#: $#: $#" % [mode, indent, fromModule2, moduleStatus, path])
|
||||
|
||||
proc getPackage*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
## Returns a package symbol for yet to be defined module for fileIdx.
|
||||
## The package symbol is added to the graph if it doesn't exist.
|
||||
let pkgSym = getPackage(graph.config, graph.cache, fileIdx)
|
||||
# check if the package is already in the graph
|
||||
result = graph.packageSyms.strTableGet(pkgSym.name)
|
||||
if result == nil:
|
||||
# the package isn't in the graph, so create and add it
|
||||
result = pkgSym
|
||||
graph.packageSyms.strTableAdd(pkgSym)
|
||||
|
||||
func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
|
||||
## Check if symbol belongs to the 'stdlib' package.
|
||||
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId
|
||||
|
||||
proc `==`*(a, b: SymInfoPair): bool =
|
||||
result = a.sym == b.sym and a.info.exactEquals(b.info)
|
||||
|
||||
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): seq[SymInfoPair] =
|
||||
result = graph.suggestSymbols.getOrDefault(fileIdx, @[])
|
||||
|
||||
iterator suggestSymbolsIter*(g: ModuleGraph): SymInfoPair =
|
||||
for xs in g.suggestSymbols.values:
|
||||
for x in xs:
|
||||
yield x
|
||||
|
||||
iterator suggestErrorsIter*(g: ModuleGraph): Suggest =
|
||||
for xs in g.suggestErrors.values:
|
||||
for x in xs:
|
||||
yield x
|
||||
|
||||
@@ -10,100 +10,6 @@
|
||||
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
|
||||
pathutils
|
||||
|
||||
when false:
|
||||
const
|
||||
considerParentDirs = not defined(noParentProjects)
|
||||
considerNimbleDirs = not defined(noNimbleDirs)
|
||||
|
||||
proc findInNimbleDir(pkg, subdir, dir: string): string =
|
||||
var best = ""
|
||||
var bestv = ""
|
||||
for k, p in os.walkDir(dir, relative=true):
|
||||
if k == pcDir and p.len > pkg.len+1 and
|
||||
p[pkg.len] == '-' and p.startsWith(pkg):
|
||||
let (_, a, _) = getPathVersionChecksum(p)
|
||||
if bestv.len == 0 or bestv < a:
|
||||
bestv = a
|
||||
best = dir / p
|
||||
|
||||
if best.len > 0:
|
||||
var f: File
|
||||
if open(f, best / changeFileExt(pkg, ".nimble-link")):
|
||||
# the second line contains what we're interested in, see:
|
||||
# https://github.com/nim-lang/nimble#nimble-link
|
||||
var override = ""
|
||||
discard readLine(f, override)
|
||||
discard readLine(f, override)
|
||||
close(f)
|
||||
if not override.isAbsolute():
|
||||
best = best / override
|
||||
else:
|
||||
best = override
|
||||
let f = if subdir.len == 0: pkg else: subdir
|
||||
let res = addFileExt(best / f, "nim")
|
||||
if best.len > 0 and fileExists(res):
|
||||
result = res
|
||||
|
||||
when false:
|
||||
proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
|
||||
template attempt(a) =
|
||||
let x = addFileExt(a, "nim")
|
||||
if fileExists(x): return x
|
||||
|
||||
case pkg
|
||||
of "stdlib":
|
||||
if subdir.len == 0:
|
||||
return options.libpath
|
||||
else:
|
||||
for candidate in stdlibDirs:
|
||||
attempt(options.libpath / candidate / subdir)
|
||||
of "root":
|
||||
let root = project.splitFile.dir
|
||||
if subdir.len == 0:
|
||||
return root
|
||||
else:
|
||||
attempt(root / subdir)
|
||||
else:
|
||||
when considerParentDirs:
|
||||
var p = parentDir(source.splitFile.dir)
|
||||
# support 'import $karax':
|
||||
let f = if subdir.len == 0: pkg else: subdir
|
||||
|
||||
while p.len > 0:
|
||||
let dir = p / pkg
|
||||
if dirExists(dir):
|
||||
attempt(dir / f)
|
||||
# 2nd attempt: try to use 'karax/karax'
|
||||
attempt(dir / pkg / f)
|
||||
# 3rd attempt: try to use 'karax/src/karax'
|
||||
attempt(dir / "src" / f)
|
||||
attempt(dir / "src" / pkg / f)
|
||||
p = parentDir(p)
|
||||
|
||||
when considerNimbleDirs:
|
||||
if not options.gNoNimblePath:
|
||||
var nimbleDir = getEnv("NIMBLE_DIR")
|
||||
if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
|
||||
result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs")
|
||||
if result.len > 0: return result
|
||||
when not defined(windows):
|
||||
result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs")
|
||||
if result.len > 0: return result
|
||||
|
||||
proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
|
||||
resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
|
||||
|
||||
proc lookupPackage(pkg, subdir: PNode): string =
|
||||
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
|
||||
case pkg.kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
result = scriptableImport(pkg.strVal, sub, pkg.info)
|
||||
of nkIdent:
|
||||
result = scriptableImport(pkg.ident.s, sub, pkg.info)
|
||||
else:
|
||||
localError(pkg.info, "package name must be an identifier or string literal")
|
||||
result = ""
|
||||
|
||||
proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
# This returns a short relative module name without the nim extension
|
||||
# e.g. like "system", "importer" or "somepath/module"
|
||||
@@ -163,3 +69,18 @@ proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
|
||||
result = InvalidFileIdx
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
|
||||
proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
## Mangle a relative module path to avoid path and symbol collisions.
|
||||
##
|
||||
## Used by backends that need to generate intermediary files from Nim modules.
|
||||
## This is needed because the compiler uses a flat cache file hierarchy.
|
||||
##
|
||||
## Example:
|
||||
## `foo-#head/../bar` becomes `@foo-@hhead@s..@sbar`
|
||||
"@m" & relativeTo(path, conf.projectPath).string.multiReplace(
|
||||
{$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
|
||||
proc demangleModuleName*(path: string): string =
|
||||
## Demangle a relative module path.
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import
|
||||
ast, astalgo, magicsys, msgs, options,
|
||||
idents, lexer, passes, syntaxes, llstream, modulegraphs,
|
||||
lineinfos, pathutils, tables
|
||||
lineinfos, pathutils, tables, packages
|
||||
|
||||
import ic / replayer
|
||||
|
||||
@@ -22,56 +22,11 @@ proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
|
||||
getIdent(graph.cache, splitFile(filename).name)
|
||||
|
||||
template packageId(): untyped {.dirty.} = ItemId(module: PackageModuleId, item: int32(fileIdx))
|
||||
|
||||
proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
## returns package symbol (skPackage) for yet to be defined module for fileIdx
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
let name = getModuleIdent(graph, filename)
|
||||
let info = newLineInfo(fileIdx, 1, 1)
|
||||
let
|
||||
pck = getPackageName(graph.config, filename.string)
|
||||
pck2 = if pck.len > 0: pck else: "unknown"
|
||||
pack = getIdent(graph.cache, pck2)
|
||||
result = graph.packageSyms.strTableGet(pack)
|
||||
if result == nil:
|
||||
result = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info)
|
||||
#initStrTable(packSym.tab)
|
||||
graph.packageSyms.strTableAdd(result)
|
||||
else:
|
||||
let modules = graph.modulesPerPackage.getOrDefault(result.itemId)
|
||||
let existing = if modules.data.len > 0: strTableGet(modules, name) else: nil
|
||||
if existing != nil and existing.info.fileIndex != info.fileIndex:
|
||||
when false:
|
||||
# we used to produce an error:
|
||||
localError(graph.config, info,
|
||||
"module names need to be unique per Nimble package; module clashes with " &
|
||||
toFullPath(graph.config, existing.info.fileIndex))
|
||||
else:
|
||||
# but starting with version 0.20 we now produce a fake Nimble package instead
|
||||
# to resolve the conflicts:
|
||||
let pck3 = fakePackageName(graph.config, filename)
|
||||
# this makes the new `result`'s owner be the original `result`
|
||||
result = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), result, info)
|
||||
#initStrTable(packSym.tab)
|
||||
graph.packageSyms.strTableAdd(result)
|
||||
|
||||
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
let packSym = getPackage(graph, fileIdx)
|
||||
result.owner = packSym
|
||||
result.position = int fileIdx
|
||||
|
||||
#initStrTable(result.tab(graph))
|
||||
when false:
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
# This is now implemented via
|
||||
# c.moduleScope.addSym(module) # a module knows itself
|
||||
# in sem.nim, around line 527
|
||||
|
||||
if graph.modulesPerPackage.getOrDefault(packSym.itemId).data.len == 0:
|
||||
graph.modulesPerPackage[packSym.itemId] = newStrTable()
|
||||
graph.modulesPerPackage[packSym.itemId].strTableAdd(result)
|
||||
|
||||
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
@@ -133,7 +88,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
graph.config.notes =
|
||||
if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
else: graph.config.foreignPackageNotes
|
||||
|
||||
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
|
||||
@@ -168,7 +123,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
conf.projectMainIdx2 = projectFile
|
||||
|
||||
let packSym = getPackage(graph, projectFile)
|
||||
graph.config.mainPackageId = packSym.getnimblePkgId
|
||||
graph.config.mainPackageId = packSym.getPackageId
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
|
||||
@@ -123,6 +123,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
|
||||
var dummy: bool
|
||||
result = fileInfoIdx(conf, filename, dummy)
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
|
||||
var dummy: bool
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
if line < int high(uint16):
|
||||
@@ -618,9 +625,9 @@ template internalAssert*(conf: ConfigRef, e: bool) =
|
||||
let arg = info2.toFileLineCol
|
||||
internalErrorImpl(conf, unknownLineInfo, arg, info2)
|
||||
|
||||
template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, forceHint = false, extraMsg = "") =
|
||||
template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraMsg = "") =
|
||||
let m = "'$1' should be: '$2'$3" % [got, beau, extraMsg]
|
||||
let msg = if optStyleError in conf.globalOptions and not forceHint: errGenerated else: hintName
|
||||
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
|
||||
liMessage(conf, info, msg, m, doNothing, instLoc())
|
||||
|
||||
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
|
||||
@@ -10,6 +10,7 @@ define:nimPreviewFloatRoundtrip
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
tlsEmulation:off
|
||||
@end
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
|
||||
@@ -37,6 +37,15 @@ when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
proc nimbleLockExists(config: ConfigRef): bool =
|
||||
const nimbleLock = "nimble.lock"
|
||||
let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
|
||||
if optSkipParentConfigFiles notin config.globalOptions:
|
||||
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
|
||||
if fileExists(dir / nimbleLock):
|
||||
return true
|
||||
return fileExists(pd.string / nimbleLock)
|
||||
|
||||
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
@@ -70,6 +79,11 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}:
|
||||
rawMessage(config, errGenerated, errArgsNeedRunOption)
|
||||
|
||||
if config.nimbleLockExists:
|
||||
# disable nimble path if nimble.lock is present.
|
||||
# see https://github.com/nim-lang/nimble/issues/1004
|
||||
disableNimblePath(config)
|
||||
|
||||
proc getNimRunExe(conf: ConfigRef): string =
|
||||
# xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to
|
||||
# customize the binary to run the command with, e.g. for custom `nodejs` or `wine`.
|
||||
|
||||
@@ -298,7 +298,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
|
||||
if conf.cmd == cmdNimscript:
|
||||
showHintConf()
|
||||
conf.configFiles.setLen 0
|
||||
if conf.cmd != cmdIdeTools:
|
||||
if conf.cmd notin {cmdIdeTools, cmdCheck, cmdDump}:
|
||||
if conf.cmd == cmdNimscript:
|
||||
runNimScriptIfExists(conf.projectFull, isMain = true)
|
||||
else:
|
||||
@@ -308,5 +308,6 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
|
||||
runNimScriptIfExists(scriptFile, isMain = true)
|
||||
else:
|
||||
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file
|
||||
# `nim check foo.nims' means to check the syntax of the NimScript file
|
||||
discard
|
||||
showHintConf()
|
||||
|
||||
@@ -19,7 +19,7 @@ const
|
||||
useEffectSystem* = true
|
||||
useWriteTracking* = false
|
||||
hasFFI* = defined(nimHasLibFFI)
|
||||
copyrightYear* = "2021"
|
||||
copyrightYear* = "2023"
|
||||
|
||||
nimEnableCovariance* = defined(nimEnableCovariance)
|
||||
|
||||
@@ -183,8 +183,9 @@ type
|
||||
# as far as usesWriteBarrier() is concerned
|
||||
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
implicitDeref,
|
||||
@@ -207,7 +208,8 @@ type
|
||||
strictNotNil,
|
||||
overloadableEnums,
|
||||
strictEffects,
|
||||
unicodeOperators
|
||||
unicodeOperators,
|
||||
flexibleOptionalParams
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -262,6 +264,9 @@ type
|
||||
scope*, localUsages*, globalUsages*: int # more usages is better
|
||||
tokenLen*: int
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
ProfileInfo* = object
|
||||
@@ -389,8 +394,14 @@ type
|
||||
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
|
||||
severity: Severity) {.closure, gcsafe.}
|
||||
cppCustomNamespace*: string
|
||||
nimMainPrefix*: string
|
||||
vmProfileData*: ProfileData
|
||||
|
||||
expandProgress*: bool
|
||||
expandLevels*: int
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
if a.len > 0:
|
||||
@@ -595,7 +606,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos}
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr}
|
||||
of "linux":
|
||||
result = conf.target.targetOS in {osLinux, osAndroid}
|
||||
of "bsd":
|
||||
@@ -615,6 +626,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
result = conf.target.targetOS == osNintendoSwitch
|
||||
of "freertos", "lwip":
|
||||
result = conf.target.targetOS == osFreeRTOS
|
||||
of "zephyr":
|
||||
result = conf.target.targetOS == osZephyr
|
||||
of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
|
||||
of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
|
||||
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
|
||||
@@ -797,6 +810,8 @@ proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile,
|
||||
|
||||
proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
|
||||
createSubDir: bool = true): AbsoluteFile =
|
||||
## Return an absolute path of a generated intermediary file.
|
||||
## Optionally creates the cache directory if `createSubDir` is `true`.
|
||||
let subdir = getNimcacheDir(conf)
|
||||
if createSubDir:
|
||||
try:
|
||||
@@ -804,11 +819,6 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
|
||||
except OSError:
|
||||
conf.quitOrRaise "cannot create directory: " & subdir.string
|
||||
result = subdir / RelativeFile f.string.splitPath.tail
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
||||
proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
|
||||
result = changeFileExt(completeGeneratedFilePath(conf,
|
||||
withPackageName(conf, f)), ext)
|
||||
|
||||
proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile =
|
||||
for it in conf.searchPaths:
|
||||
@@ -845,7 +855,7 @@ when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo):
|
||||
let ret = relativePath(path, base)
|
||||
result = path.len > 0 and not ret.startsWith ".."
|
||||
|
||||
const stdlibDirs = [
|
||||
const stdlibDirs* = [
|
||||
"pure", "core", "arch",
|
||||
"pure/collections",
|
||||
"pure/concurrency",
|
||||
@@ -979,6 +989,9 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
|
||||
result = optDynlibOverrideAll in conf.globalOptions or
|
||||
conf.dllOverrides.hasKey(lib.canonDynlibName)
|
||||
|
||||
proc expandDone*(conf: ConfigRef): bool =
|
||||
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
of "sug": ideSug
|
||||
@@ -987,12 +1000,17 @@ proc parseIdeCmd*(s: string): IdeCmd =
|
||||
of "use": ideUse
|
||||
of "dus": ideDus
|
||||
of "chk": ideChk
|
||||
of "chkFile": ideChkFile
|
||||
of "mod": ideMod
|
||||
of "highlight": ideHighlight
|
||||
of "outline": ideOutline
|
||||
of "known": ideKnown
|
||||
of "msg": ideMsg
|
||||
of "project": ideProject
|
||||
of "globalSymbols": ideGlobalSymbols
|
||||
of "recompile": ideRecompile
|
||||
of "changed": ideChanged
|
||||
of "type": ideType
|
||||
else: ideNone
|
||||
|
||||
proc `$`*(c: IdeCmd): string =
|
||||
@@ -1003,6 +1021,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideUse: "use"
|
||||
of ideDus: "dus"
|
||||
of ideChk: "chk"
|
||||
of ideChkFile: "chkFile"
|
||||
of ideMod: "mod"
|
||||
of ideNone: "none"
|
||||
of ideHighlight: "highlight"
|
||||
@@ -1010,6 +1029,12 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideKnown: "known"
|
||||
of ideMsg: "msg"
|
||||
of ideProject: "project"
|
||||
of ideGlobalSymbols: "globalSymbols"
|
||||
of ideDeclaration: "declaration"
|
||||
of ideExpand: "expand"
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
|
||||
@@ -37,24 +37,7 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string =
|
||||
proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
## returns nimble package name, e.g.: `cligen`
|
||||
let path = getNimbleFile(conf, path)
|
||||
result = path.splitFile.name
|
||||
|
||||
proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
# Convert `path` so that 2 modules with same name
|
||||
# in different directory get different name and they can be
|
||||
# placed in a directory.
|
||||
# foo-#head/../bar becomes @foo-@hhead@s..@sbar
|
||||
result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace(
|
||||
{$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
|
||||
proc demanglePackageName*(path: string): string =
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
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)
|
||||
if path.len > 0:
|
||||
return path.splitFile.name
|
||||
else:
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
return "unknown"
|
||||
|
||||
49
compiler/packages.nim
Normal file
49
compiler/packages.nim
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2022 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Package related procs.
|
||||
##
|
||||
## See Also:
|
||||
## * `packagehandling` for package path handling
|
||||
## * `modulegraphs.getPackage`
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
|
||||
import "." / [options, ast, lineinfos, idents, pathutils, msgs]
|
||||
|
||||
proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
## Return a new package symbol.
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.getPackage`
|
||||
let
|
||||
filename = AbsoluteFile toFullPath(conf, fileIdx)
|
||||
name = getIdent(cache, splitFile(filename).name)
|
||||
info = newLineInfo(fileIdx, 1, 1)
|
||||
pkgName = getPackageName(conf, filename.string)
|
||||
pkgIdent = getIdent(cache, pkgName)
|
||||
newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
|
||||
|
||||
func getPackageSymbol*(sym: PSym): PSym =
|
||||
## Return the owning package symbol.
|
||||
assert sym != nil
|
||||
result = sym
|
||||
while result.kind != skPackage:
|
||||
result = result.owner
|
||||
assert result != nil, repr(sym.info)
|
||||
|
||||
func getPackageId*(sym: PSym): int =
|
||||
## Return the owning package ID.
|
||||
sym.getPackageSymbol.id
|
||||
|
||||
func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
|
||||
## Return whether the symbol belongs to the project's package.
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
conf.mainPackageId == sym.getPackageId
|
||||
@@ -331,6 +331,12 @@ proc colcom(p: var Parser, n: PNode) =
|
||||
|
||||
const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
|
||||
|
||||
template setEndInfo() =
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = TLineInfo(fileIndex: p.lex.fileIdx,
|
||||
line: p.lex.previousTokenEnd.line,
|
||||
col: p.lex.previousTokenEnd.col)
|
||||
|
||||
proc parseSymbol(p: var Parser, mode = smNormal): PNode =
|
||||
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
#| | IDENT | KEYW
|
||||
@@ -383,6 +389,7 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
|
||||
# if it is a keyword:
|
||||
#if not isKeyword(p.tok.tokType): getTok(p)
|
||||
result = p.emptyNode
|
||||
setEndInfo()
|
||||
|
||||
proc colonOrEquals(p: var Parser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
@@ -524,6 +531,7 @@ proc parseCast(p: var Parser): PNode =
|
||||
result.add(exprColonEqExpr(p))
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
setEndInfo()
|
||||
|
||||
proc setBaseFlags(n: PNode, base: NumericalBase) =
|
||||
case base
|
||||
@@ -546,6 +554,7 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
|
||||
getTok(p)
|
||||
else:
|
||||
result = a
|
||||
setEndInfo()
|
||||
|
||||
proc complexOrSimpleStmt(p: var Parser): PNode
|
||||
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
|
||||
@@ -582,10 +591,10 @@ proc parsePar(p: var Parser): PNode =
|
||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
#| | 'when' | 'var' | 'mixin'
|
||||
#| par = '(' optInd
|
||||
#| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | pragmaStmt
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
#| optPar ')'
|
||||
#
|
||||
@@ -650,6 +659,7 @@ proc parsePar(p: var Parser): PNode =
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
setEndInfo()
|
||||
|
||||
proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode =
|
||||
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
@@ -896,6 +906,7 @@ proc parseOperators(p: var Parser, headNode: PNode,
|
||||
a.add(b)
|
||||
result = a
|
||||
opPrec = getPrecedence(p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode =
|
||||
result = primary(p, mode)
|
||||
@@ -942,6 +953,7 @@ proc parsePragma(p: var Parser): PNode =
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
dec p.em.keepIndents
|
||||
setEndInfo()
|
||||
|
||||
proc identVis(p: var Parser; allowDot=false): PNode =
|
||||
#| identVis = symbol OPR? # postfix position
|
||||
@@ -1010,6 +1022,7 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result.add(newNodeP(nkEmpty, p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTuple(p: var Parser, indentAllowed = false): PNode =
|
||||
#| tupleDecl = 'tuple'
|
||||
@@ -1053,6 +1066,7 @@ proc parseTuple(p: var Parser, indentAllowed = false): PNode =
|
||||
parMessage(p, errGenerated, "the syntax for tuple types is 'tuple[...]', not 'tuple(...)'")
|
||||
else:
|
||||
result = newNodeP(nkTupleClassTy, p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseParamList(p: var Parser, retColon = true): PNode =
|
||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
@@ -1101,6 +1115,7 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
dec p.em.keepIndents
|
||||
setEndInfo()
|
||||
|
||||
proc optPragmas(p: var Parser): PNode =
|
||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
|
||||
@@ -1118,12 +1133,12 @@ proc parseDoBlock(p: var Parser; info: TLineInfo): PNode =
|
||||
result = newProcNode(nkDo, info,
|
||||
body = result, params = params, name = p.emptyNode, pattern = p.emptyNode,
|
||||
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
|
||||
#| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
# either a proc type or a anonymous proc
|
||||
let info = parLineInfo(p)
|
||||
getTok(p)
|
||||
let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
|
||||
let params = parseParamList(p)
|
||||
let pragmas = optPragmas(p)
|
||||
@@ -1134,12 +1149,13 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
|
||||
params = params, name = p.emptyNode, pattern = p.emptyNode,
|
||||
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
|
||||
else:
|
||||
result = newNodeI(nkProcTy, info)
|
||||
result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
|
||||
if hasSignature:
|
||||
result.add(params)
|
||||
if kind == nkFuncDef:
|
||||
parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
|
||||
result.add(pragmas)
|
||||
setEndInfo()
|
||||
|
||||
proc isExprStart(p: Parser): bool =
|
||||
case p.tok.tokType
|
||||
@@ -1159,6 +1175,7 @@ proc parseSymbolList(p: var Parser, result: PNode) =
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, s)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
mode: PrimaryMode): PNode =
|
||||
@@ -1181,6 +1198,7 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
let list = newNodeP(nodeKind, p)
|
||||
result.add list
|
||||
parseSymbolList(p, list)
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode
|
||||
|
||||
@@ -1206,6 +1224,7 @@ proc parseFor(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
template nimprettyDontTouch(body) =
|
||||
when defined(nimpretty):
|
||||
@@ -1244,6 +1263,7 @@ proc parseExpr(p: var Parser): PNode =
|
||||
nimprettyDontTouch:
|
||||
result = parseTry(p, isExpr=true)
|
||||
else: result = simpleExpr(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseEnum(p: var Parser): PNode
|
||||
proc parseObject(p: var Parser): PNode
|
||||
@@ -1275,12 +1295,15 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
|
||||
|
||||
case p.tok.tokType
|
||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
|
||||
of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
|
||||
of tkIterator:
|
||||
of tkProc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
|
||||
if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef)
|
||||
else: result.transitionSonsKind(nkIteratorTy)
|
||||
of tkFunc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
|
||||
of tkIterator:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkIteratorDef)
|
||||
of tkEnum:
|
||||
if mode == pmTypeDef:
|
||||
prettySection:
|
||||
@@ -1337,11 +1360,13 @@ proc parseTypeDesc(p: var Parser): PNode =
|
||||
newlineWasSplitting(p)
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDefAux(p: var Parser): PNode =
|
||||
#| typeDefAux = simpleExpr ('not' expr)?
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc makeCall(n: PNode): PNode =
|
||||
## Creates a call if the given node isn't already a call.
|
||||
@@ -1464,6 +1489,7 @@ proc parseExprStmt(p: var Parser): PNode =
|
||||
else:
|
||||
result = a
|
||||
result = postExprBlocks(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = parseExpr(p)
|
||||
@@ -1475,6 +1501,7 @@ proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseImport(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| importStmt = 'import' optInd expr
|
||||
@@ -1503,6 +1530,7 @@ proc parseImport(p: var Parser, kind: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIncludeStmt(p: var Parser): PNode =
|
||||
#| includeStmt = 'include' optInd expr ^+ comma
|
||||
@@ -1519,6 +1547,7 @@ proc parseIncludeStmt(p: var Parser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseFromStmt(p: var Parser): PNode =
|
||||
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
@@ -1539,6 +1568,7 @@ proc parseFromStmt(p: var Parser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| returnStmt = 'return' optInd expr?
|
||||
@@ -1560,6 +1590,7 @@ proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
|
||||
var e = parseExpr(p)
|
||||
e = postExprBlocks(p, e)
|
||||
result.add(e)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condStmt = expr colcom stmt COMMENT?
|
||||
@@ -1584,6 +1615,7 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condExpr = expr colcom expr optInd
|
||||
@@ -1608,6 +1640,7 @@ proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseWhile(p: var Parser): PNode =
|
||||
#| whileStmt = 'while' expr colcom stmt
|
||||
@@ -1617,6 +1650,7 @@ proc parseWhile(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseCase(p: var Parser): PNode =
|
||||
#| ofBranch = 'of' exprList colcom stmt
|
||||
@@ -1664,6 +1698,7 @@ proc parseCase(p: var Parser): PNode =
|
||||
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
setEndInfo()
|
||||
|
||||
proc parseTry(p: var Parser; isExpr: bool): PNode =
|
||||
#| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
|
||||
@@ -1690,12 +1725,14 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
|
||||
b.add(parseStmt(p))
|
||||
result.add(b)
|
||||
if b == nil: parMessage(p, "expected 'except'")
|
||||
setEndInfo()
|
||||
|
||||
proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseBlock(p: var Parser): PNode =
|
||||
#| blockStmt = 'block' symbol? colcom stmt
|
||||
@@ -1706,6 +1743,7 @@ proc parseBlock(p: var Parser): PNode =
|
||||
else: result.add(parseSymbol(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
|
||||
#| staticStmt = 'static' colcom stmt
|
||||
@@ -1714,6 +1752,7 @@ proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseAsm(p: var Parser): PNode =
|
||||
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
||||
@@ -1730,6 +1769,7 @@ proc parseAsm(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
return
|
||||
getTok(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseGenericParam(p: var Parser): PNode =
|
||||
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
|
||||
@@ -1765,6 +1805,7 @@ proc parseGenericParam(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result.add(p.emptyNode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseGenericParamList(p: var Parser): PNode =
|
||||
#| genericParamList = '[' optInd
|
||||
@@ -1783,12 +1824,14 @@ proc parseGenericParamList(p: var Parser): PNode =
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkBracketRi)
|
||||
setEndInfo()
|
||||
|
||||
proc parsePattern(p: var Parser): PNode =
|
||||
#| pattern = '{' stmt '}'
|
||||
eat(p, tkCurlyLe)
|
||||
result = parseStmt(p)
|
||||
eat(p, tkCurlyRi)
|
||||
setEndInfo()
|
||||
|
||||
proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
|
||||
@@ -1797,6 +1840,12 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
if kind in {nkProcDef, nkLambda, nkIteratorDef, nkFuncDef} and
|
||||
p.tok.tokType notin {tkSymbol, tokKeywordLow..tokKeywordHigh, tkAccent}:
|
||||
# no name; lambda or proc type
|
||||
# in every context that we can parse a routine, we can also parse these
|
||||
result = parseProcExpr(p, true, if kind == nkProcDef: nkLambda else: kind)
|
||||
return
|
||||
result.add(identVis(p))
|
||||
if p.tok.tokType == tkCurlyLe and p.validInd: result.add(p.parsePattern)
|
||||
else: result.add(p.emptyNode)
|
||||
@@ -1827,6 +1876,7 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
|
||||
#else:
|
||||
# assert false, p.lex.config$body.info # avoids hard to track bugs, fail early.
|
||||
# Yeah, that worked so well. There IS a bug in this logic, now what?
|
||||
setEndInfo()
|
||||
|
||||
proc newCommentStmt(p: var Parser): PNode =
|
||||
#| commentStmt = COMMENT
|
||||
@@ -1862,6 +1912,7 @@ proc parseSection(p: var Parser, kind: TNodeKind,
|
||||
result.add(defparser(p))
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc parseEnum(p: var Parser): PNode =
|
||||
#| enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
@@ -1877,7 +1928,7 @@ proc parseEnum(p: var Parser): PNode =
|
||||
|
||||
var symPragma = a
|
||||
var pragma: PNode
|
||||
if p.tok.tokType == tkCurlyDotLe:
|
||||
if (p.tok.indent < 0 or p.tok.indent >= p.currInd) and p.tok.tokType == tkCurlyDotLe:
|
||||
pragma = optPragmas(p)
|
||||
symPragma = newNodeP(nkPragmaExpr, p)
|
||||
symPragma.add(a)
|
||||
@@ -1908,6 +1959,7 @@ proc parseEnum(p: var Parser): PNode =
|
||||
break
|
||||
if result.len <= 1:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectPart(p: var Parser): PNode
|
||||
proc parseObjectWhen(p: var Parser): PNode =
|
||||
@@ -1933,6 +1985,7 @@ proc parseObjectWhen(p: var Parser): PNode =
|
||||
branch.add(parseObjectPart(p))
|
||||
flexComment(p, branch)
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectCase(p: var Parser): PNode =
|
||||
#| objectBranch = 'of' exprList colcom objectPart
|
||||
@@ -1978,6 +2031,7 @@ proc parseObjectCase(p: var Parser): PNode =
|
||||
if b.kind == nkElse: break
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectPart(p: var Parser): PNode =
|
||||
#| objectPart = IND{>} objectPart^+IND{=} DED
|
||||
@@ -2010,6 +2064,7 @@ proc parseObjectPart(p: var Parser): PNode =
|
||||
result = p.emptyNode
|
||||
else:
|
||||
result = p.emptyNode
|
||||
setEndInfo()
|
||||
|
||||
proc parseObject(p: var Parser): PNode =
|
||||
#| objectDecl = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
|
||||
@@ -2035,6 +2090,7 @@ proc parseObject(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
else:
|
||||
result.add(parseObjectPart(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeClassParam(p: var Parser): PNode =
|
||||
let modifier =
|
||||
@@ -2052,6 +2108,7 @@ proc parseTypeClassParam(p: var Parser): PNode =
|
||||
result.add(p.parseSymbol)
|
||||
else:
|
||||
result = p.parseSymbol
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeClass(p: var Parser): PNode =
|
||||
#| conceptParam = ('var' | 'out')? symbol
|
||||
@@ -2095,6 +2152,7 @@ proc parseTypeClass(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
else:
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDef(p: var Parser): PNode =
|
||||
#|
|
||||
@@ -2143,6 +2201,7 @@ proc parseTypeDef(p: var Parser): PNode =
|
||||
else:
|
||||
result.add(p.emptyNode)
|
||||
indAndComment(p, result) # special extension!
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode =
|
||||
#| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
@@ -2159,6 +2218,7 @@ proc parseVarTuple(p: var Parser): PNode =
|
||||
result.add(p.emptyNode) # no type desc
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
setEndInfo()
|
||||
|
||||
proc parseVariable(p: var Parser): PNode =
|
||||
#| colonBody = colcom stmt postExprBlocks?
|
||||
@@ -2171,6 +2231,7 @@ proc parseVariable(p: var Parser): PNode =
|
||||
else: result = parseIdentColonEquals(p, {withPragma, withDot})
|
||||
result[^1] = postExprBlocks(p, result[^1])
|
||||
indAndComment(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseConstant(p: var Parser): PNode =
|
||||
#| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
|
||||
@@ -2190,6 +2251,7 @@ proc parseConstant(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
result[^1] = postExprBlocks(p, result[^1])
|
||||
indAndComment(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseBind(p: var Parser, k: TNodeKind): PNode =
|
||||
#| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
|
||||
@@ -2205,6 +2267,7 @@ proc parseBind(p: var Parser, k: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseStmtPragma(p: var Parser): PNode =
|
||||
#| pragmaStmt = pragma (':' COMMENT? stmt)?
|
||||
@@ -2216,6 +2279,7 @@ proc parseStmtPragma(p: var Parser): PNode =
|
||||
skipComment(p, result)
|
||||
result.add a
|
||||
result.add parseStmt(p)
|
||||
setEndInfo()
|
||||
|
||||
proc simpleStmt(p: var Parser): PNode =
|
||||
#| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
|
||||
@@ -2358,6 +2422,7 @@ proc parseStmt(p: var Parser): PNode =
|
||||
if p.tok.tokType != tkSemiColon: break
|
||||
getTok(p)
|
||||
if err and p.tok.tokType == tkEof: break
|
||||
setEndInfo()
|
||||
|
||||
proc parseAll(p: var Parser): PNode =
|
||||
## Parses the rest of the input stream held by the parser into a PNode.
|
||||
@@ -2373,6 +2438,7 @@ proc parseAll(p: var Parser): PNode =
|
||||
getTok(p)
|
||||
if p.tok.indent != 0:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
## Implements an iterator which, when called repeatedly, returns the next
|
||||
@@ -2402,6 +2468,7 @@ proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
result = complexOrSimpleStmt(p)
|
||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
break
|
||||
setEndInfo()
|
||||
|
||||
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
|
||||
filename: string = ""; line: int = 0;
|
||||
@@ -2413,9 +2480,10 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
|
||||
var stream = llStreamOpen(s)
|
||||
stream.lineOffset = line
|
||||
|
||||
var parser: Parser
|
||||
parser.lex.errorHandler = errorHandler
|
||||
openParser(parser, AbsoluteFile filename, stream, cache, config)
|
||||
var p: Parser
|
||||
p.lex.errorHandler = errorHandler
|
||||
openParser(p, AbsoluteFile filename, stream, cache, config)
|
||||
|
||||
result = parser.parseAll
|
||||
closeParser(parser)
|
||||
result = p.parseAll
|
||||
closeParser(p)
|
||||
setEndInfo()
|
||||
|
||||
@@ -14,7 +14,8 @@ import
|
||||
options, ast, llstream, msgs,
|
||||
idents,
|
||||
syntaxes, modulegraphs, reorder,
|
||||
lineinfos, pathutils
|
||||
lineinfos, pathutils, std/sha1, packages
|
||||
|
||||
|
||||
type
|
||||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||
@@ -101,7 +102,7 @@ const
|
||||
|
||||
proc prepareConfigNotes(graph: ModuleGraph; module: PSym) =
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if module.getnimblePkgId == graph.config.mainPackageId:
|
||||
if graph.config.belongsToProjectPackage(module):
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
else:
|
||||
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
|
||||
@@ -111,12 +112,6 @@ proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
|
||||
result = true
|
||||
#module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")
|
||||
|
||||
proc partOfStdlib(x: PSym): bool =
|
||||
var it = x.owner
|
||||
while it != nil and it.kind == skPackage and it.owner != nil:
|
||||
it = it.owner
|
||||
result = it != nil and it.name.s == "stdlib"
|
||||
|
||||
proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
stream: PLLStream): bool {.discardable.} =
|
||||
if graph.stopCompile(): return true
|
||||
@@ -135,10 +130,15 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
return false
|
||||
else:
|
||||
s = stream
|
||||
|
||||
when defined(nimsuggest):
|
||||
let filename = toFullPathConsiderDirty(graph.config, fileIdx).string
|
||||
msgs.setHash(graph.config, fileIdx, $sha1.secureHashFile(filename))
|
||||
|
||||
while true:
|
||||
openParser(p, fileIdx, s, graph.cache, graph.config)
|
||||
|
||||
if not partOfStdlib(module) or module.name.s == "distros":
|
||||
if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"):
|
||||
# XXX what about caching? no processing then? what if I change the
|
||||
# modules to include between compilation runs? we'd need to track that
|
||||
# in ROD files. I think we should enable this feature only
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Path handling utilities for Nim. Strictly typed code in order
|
||||
## to avoid the never ending time sink in getting path handling right.
|
||||
|
||||
import os, pathnorm
|
||||
import os, pathnorm, strutils
|
||||
|
||||
type
|
||||
AbsoluteFile* = distinct string
|
||||
@@ -99,3 +99,52 @@ when true:
|
||||
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
|
||||
|
||||
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
|
||||
|
||||
proc skipHomeDir(x: string): int =
|
||||
when defined(windows):
|
||||
if x.continuesWith("Users/", len("C:/")):
|
||||
result = 3
|
||||
else:
|
||||
result = 0
|
||||
else:
|
||||
if x.startsWith("/home/") or x.startsWith("/Users/"):
|
||||
result = 3
|
||||
elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")):
|
||||
result = 5
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc relevantPart(s: string; afterSlashX: int): string =
|
||||
result = newStringOfCap(s.len - 8)
|
||||
var slashes = afterSlashX
|
||||
for i in 0..<s.len:
|
||||
if slashes == 0:
|
||||
result.add s[i]
|
||||
elif s[i] == '/':
|
||||
dec slashes
|
||||
|
||||
template canonSlashes(x: string): string =
|
||||
when defined(windows):
|
||||
x.replace('\\', '/')
|
||||
else:
|
||||
x
|
||||
|
||||
proc customPathImpl(x: string): string =
|
||||
# Idea: Encode a "protocol" via "//protocol/path" which is not ambiguous
|
||||
# as path canonicalization would have removed the double slashes.
|
||||
# /mnt/X/Users/Y
|
||||
# X:\\Users\Y
|
||||
# /home/Y
|
||||
# -->
|
||||
# //user/
|
||||
if not isAbsolute(x):
|
||||
result = customPathImpl(canonSlashes(getCurrentDir() / x))
|
||||
else:
|
||||
let slashes = skipHomeDir(x)
|
||||
if slashes > 0:
|
||||
result = "//user/" & relevantPart(x, slashes)
|
||||
else:
|
||||
result = x
|
||||
|
||||
proc customPath*(x: string): string =
|
||||
customPathImpl canonSlashes x
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny
|
||||
|
||||
type
|
||||
TInfoOSProp* = enum
|
||||
@@ -185,6 +185,10 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "Zephyr", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
|
||||
@@ -15,7 +15,7 @@ import ".." / [ast, astalgo,
|
||||
proc semLocals*(c: PContext, n: PNode): PNode =
|
||||
var counter = 0
|
||||
var tupleType = newTypeS(tyTuple, c)
|
||||
result = newNodeIT(nkPar, n.info, tupleType)
|
||||
result = newNodeIT(nkTupleConstr, n.info, tupleType)
|
||||
tupleType.n = newNodeI(nkRecList, n.info)
|
||||
let owner = getCurrOwner(c)
|
||||
# for now we skip openarrays ...
|
||||
|
||||
@@ -31,7 +31,7 @@ const
|
||||
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe,
|
||||
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
|
||||
wRequires, wEnsures}
|
||||
wRequires, wEnsures, wEnforceNoRaises}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
@@ -498,8 +498,11 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
var cf = Cfile(nimname: splitFile(src).name,
|
||||
cname: src, obj: dest, flags: {CfileFlag.External},
|
||||
customArgs: customArgs)
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
|
||||
if not fileExists(src):
|
||||
localError(c.config, n.info, "cannot find: " & src.string)
|
||||
else:
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
|
||||
|
||||
proc getStrLit(c: PContext, n: PNode; i: int): string =
|
||||
n[i] = c.semConstExpr(c, n[i])
|
||||
@@ -635,12 +638,13 @@ proc pragmaLine(c: PContext, n: PNode) =
|
||||
n.info = getInfoContext(c.config, -1)
|
||||
|
||||
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
## Create and add a new custom pragma `{.pragma: name.}` node to the module's context.
|
||||
let it = n[i]
|
||||
if it.kind notin nkPragmaCallKinds and it.safeLen == 2: invalidPragma(c, n)
|
||||
elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent:
|
||||
invalidPragma(c, n)
|
||||
|
||||
var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), nil, it.info, c.config.options)
|
||||
var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), c.module, it.info, c.config.options)
|
||||
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
|
||||
strTableAdd(c.userPragmas, userPragma)
|
||||
|
||||
@@ -822,8 +826,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
let ident = considerQuotedIdent(c, key)
|
||||
var userPragma = strTableGet(c.userPragmas, ident)
|
||||
if userPragma != nil:
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
styleCheckUse(c.config, key.info, userPragma)
|
||||
styleCheckUse(c, key.info, userPragma)
|
||||
|
||||
# number of pragmas increase/decrease with user pragma expansion
|
||||
inc c.instCounter
|
||||
@@ -837,8 +840,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
else:
|
||||
let k = whichKeyword(ident)
|
||||
if k in validPragmas:
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
checkPragmaUse(c.config, key.info, k, ident.s)
|
||||
checkPragmaUse(c.config, key.info, k, ident.s)
|
||||
case k
|
||||
of wExportc, wExportCpp:
|
||||
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
@@ -1237,11 +1239,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
pragmaProposition(c, it)
|
||||
of wEnsures:
|
||||
pragmaEnsures(c, it)
|
||||
of wEnforceNoRaises:
|
||||
sym.flags.incl sfNeverRaises
|
||||
else: invalidPragma(c, it)
|
||||
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
||||
discard "ignore the .push pragma; it doesn't apply"
|
||||
else:
|
||||
if sym == nil or (sym.kind in {skVar, skLet, skParam,
|
||||
if sym == nil or (sym.kind in {skVar, skLet, skParam, skIterator,
|
||||
skField, skProc, skFunc, skConverter, skMethod, skType}):
|
||||
n[i] = semCustomPragma(c, it)
|
||||
elif sym != nil:
|
||||
|
||||
@@ -162,6 +162,7 @@ proc putNL(g: var TSrcGen) =
|
||||
proc optNL(g: var TSrcGen, indent: int) =
|
||||
g.pendingNL = indent
|
||||
g.lineLen = indent
|
||||
g.col = g.indent
|
||||
when defined(nimpretty): g.pendingNewlineCount = 0
|
||||
|
||||
proc optNL(g: var TSrcGen) =
|
||||
@@ -170,6 +171,7 @@ proc optNL(g: var TSrcGen) =
|
||||
proc optNL(g: var TSrcGen; a, b: PNode) =
|
||||
g.pendingNL = g.indent
|
||||
g.lineLen = g.indent
|
||||
g.col = g.indent
|
||||
when defined(nimpretty): g.pendingNewlineCount = lineDiff(a, b)
|
||||
|
||||
proc indentNL(g: var TSrcGen) =
|
||||
|
||||
@@ -288,8 +288,23 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# fail fast:
|
||||
globalError(c.config, n.info, "type mismatch")
|
||||
return
|
||||
# see getMsgDiagnostic:
|
||||
if nfExplicitCall notin n.flags and {nfDotField, nfDotSetter} * n.flags != {}:
|
||||
let ident = considerQuotedIdent(c, n[0], n).s
|
||||
let sym = n[1].typ.typSym
|
||||
var typeHint = ""
|
||||
if sym == nil:
|
||||
discard
|
||||
else:
|
||||
typeHint = " for type " & getProcHeader(c.config, sym)
|
||||
localError(c.config, n.info, errUndeclaredField % ident & typeHint)
|
||||
return
|
||||
if errors.len == 0:
|
||||
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
|
||||
if n[0].kind in nkIdentKinds:
|
||||
let ident = considerQuotedIdent(c, n[0], n).s
|
||||
localError(c.config, n.info, errUndeclaredRoutine % ident)
|
||||
else:
|
||||
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
|
||||
return
|
||||
|
||||
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
|
||||
@@ -331,7 +346,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
|
||||
sym = nextOverloadIter(o, c, f)
|
||||
|
||||
let ident = considerQuotedIdent(c, f, n).s
|
||||
if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}:
|
||||
if nfExplicitCall notin n.flags and {nfDotField, nfDotSetter} * n.flags != {}:
|
||||
let sym = n[1].typ.typSym
|
||||
var typeHint = ""
|
||||
if sym == nil:
|
||||
@@ -364,11 +379,15 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
else:
|
||||
initialBinding = nil
|
||||
|
||||
template pickBest(headSymbol) =
|
||||
pickBestCandidate(c, f, n, orig, initialBinding,
|
||||
filter, result, alt, errors, efExplain in flags,
|
||||
errorsEnabled, flags)
|
||||
|
||||
var dummyErrors: CandidateErrors
|
||||
template pickSpecialOp(headSymbol) =
|
||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||
filter, result, alt, errors, efExplain in flags,
|
||||
errorsEnabled, flags)
|
||||
pickBest(f)
|
||||
filter, result, alt, dummyErrors, efExplain in flags,
|
||||
false, flags)
|
||||
|
||||
let overloadsState = result.state
|
||||
if overloadsState != csMatch:
|
||||
@@ -380,7 +399,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
n.sons.insert(hiddenArg, 1)
|
||||
orig.sons.insert(hiddenArg, 1)
|
||||
|
||||
pickBest(f)
|
||||
pickSpecialOp(f)
|
||||
|
||||
if result.state != csMatch:
|
||||
n.sons.delete(1)
|
||||
@@ -400,7 +419,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
let op = newIdentNode(getIdent(c.cache, x), n.info)
|
||||
n[0] = op
|
||||
orig[0] = op
|
||||
pickBest(op)
|
||||
pickSpecialOp(op)
|
||||
|
||||
if nfExplicitCall in n.flags:
|
||||
tryOp ".()"
|
||||
@@ -414,23 +433,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
let callOp = newIdentNode(getIdent(c.cache, ".="), n.info)
|
||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||
pickBest(callOp)
|
||||
pickSpecialOp(callOp)
|
||||
|
||||
if overloadsState == csEmpty and result.state == csEmpty:
|
||||
if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim
|
||||
template impl() =
|
||||
# xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
|
||||
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
|
||||
if n[0].kind == nkIdent and n[0].ident.s == ".=" and n[2].kind == nkIdent:
|
||||
let sym = n[1].typ.sym
|
||||
if sym == nil:
|
||||
impl()
|
||||
else:
|
||||
let field = n[2].ident.s
|
||||
let msg = errUndeclaredField % field & " for type " & getProcHeader(c.config, sym)
|
||||
localError(c.config, orig[2].info, msg)
|
||||
else:
|
||||
impl()
|
||||
result.state = csNoMatch
|
||||
# xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
|
||||
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
|
||||
return
|
||||
elif result.state != csMatch:
|
||||
if nfExprCall in n.flags:
|
||||
@@ -654,7 +663,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
for i in 1..<n.len:
|
||||
let e = semExpr(c, n[i])
|
||||
let e = semExprWithType(c, n[i])
|
||||
if e.typ == nil:
|
||||
n[i].typ = errorType(c)
|
||||
else:
|
||||
|
||||
@@ -522,7 +522,7 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(par, n.info)
|
||||
for i in 0..<n.len: result.add n[i]
|
||||
result = semExpr(c, result)
|
||||
result = semExpr(c, result, flags = {efNoUndeclared})
|
||||
|
||||
proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
case n.kind
|
||||
@@ -645,7 +645,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||
skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
|
||||
if skipTypes(it[1].typ, abstractVar).kind in
|
||||
{tyNil, tyTuple, tySet} or it[1].isArrayConstr:
|
||||
var s = skipTypes(it.typ, abstractVar)
|
||||
var s = skipTypes(it.typ, abstractVar + tyUserTypeClasses)
|
||||
if s.kind != tyUntyped:
|
||||
changeType(c, it[1], s, check=true)
|
||||
n[i] = it[1]
|
||||
@@ -925,6 +925,14 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||
return errorNode(c, n)
|
||||
|
||||
result = n
|
||||
|
||||
when defined(nimsuggest):
|
||||
if c.config.expandProgress:
|
||||
if c.config.expandLevels == 0:
|
||||
return n
|
||||
else:
|
||||
c.config.expandLevels -= 1
|
||||
|
||||
let callee = result[0].sym
|
||||
case callee.kind
|
||||
of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
|
||||
@@ -970,6 +978,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if s != nil:
|
||||
setGenericParams(c, n[0])
|
||||
return semDirectOp(c, n, flags)
|
||||
elif isSymChoice(n[0]):
|
||||
# overloaded generic procs e.g. newSeq[int] can end up here
|
||||
return semDirectOp(c, n, flags)
|
||||
|
||||
let nOrig = n.copyTree
|
||||
semOpAux(c, n)
|
||||
@@ -1018,10 +1029,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if n.len == 1: return semObjConstr(c, n, flags)
|
||||
return semConv(c, n)
|
||||
else:
|
||||
result = overloadedCallOpr(c, n)
|
||||
result = overloadedCallOpr(c, n) # this uses efNoUndeclared
|
||||
# Now that nkSym does not imply an iteration over the proc/iterator space,
|
||||
# the old ``prc`` (which is likely an nkIdent) has to be restored:
|
||||
if result == nil:
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
# XXX: hmm, what kind of symbols will end up here?
|
||||
# do we really need to try the overload resolution?
|
||||
n[0] = prc
|
||||
@@ -1188,7 +1199,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
let s = getGenSym(c, sym)
|
||||
case s.kind
|
||||
of skConst:
|
||||
markUsed(c, n.info, s)
|
||||
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc})
|
||||
case typ.kind
|
||||
@@ -1249,7 +1261,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if s.magic == mNimvm:
|
||||
localError(c.config, n.info, "illegal context for 'nimvm' magic")
|
||||
|
||||
markUsed(c, n.info, s)
|
||||
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
# We cannot check for access to outer vars for example because it's still
|
||||
@@ -1270,7 +1283,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
n.typ = s.typ
|
||||
return n
|
||||
of skType:
|
||||
markUsed(c, n.info, s)
|
||||
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
|
||||
return s.typ.n
|
||||
@@ -1414,7 +1428,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||
ty = ty.lastSon
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink})
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink, tyStatic})
|
||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
@@ -1433,8 +1447,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# is the access to a public field or in the same module or in a friend?
|
||||
markUsed(c, n[1].info, f)
|
||||
onUse(n[1].info, f)
|
||||
let info = n[1].info
|
||||
n[0] = makeDeref(n[0])
|
||||
n[1] = newSymNode(f) # we now have the correct field
|
||||
n[1].info = info # preserve the original info
|
||||
n.typ = f.typ
|
||||
if check == nil:
|
||||
result = n
|
||||
@@ -1841,6 +1857,9 @@ proc semReturn(c: PContext, n: PNode): PNode =
|
||||
localError(c.config, n.info, "'return' not allowed here")
|
||||
|
||||
proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
when defined(nimsuggest):
|
||||
if c.graph.config.expandDone():
|
||||
return n
|
||||
openScope(c)
|
||||
result = semExpr(c, n)
|
||||
if c.p.resultSym != nil and not isEmptyType(result.typ):
|
||||
@@ -2579,7 +2598,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
labl.owner = c.p.owner
|
||||
n[0] = newSymNode(labl, n[0].info)
|
||||
suggestSym(c.graph, n[0].info, labl, c.graph.usageSym)
|
||||
styleCheckDef(c.config, labl)
|
||||
styleCheckDef(c, labl)
|
||||
onDef(n[0].info, labl)
|
||||
n[1] = semExpr(c, n[1], flags)
|
||||
n.typ = n[1].typ
|
||||
@@ -2778,6 +2797,19 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
echo ("<", c.config$n.info, n, ?.result.typ)
|
||||
|
||||
result = n
|
||||
when defined(nimsuggest):
|
||||
var expandStarted = false
|
||||
if c.config.ideCmd == ideExpand and not c.config.expandProgress and
|
||||
((n.kind in {nkFuncDef, nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkConverterDef} and
|
||||
n.info.exactEquals(c.config.expandPosition)) or
|
||||
(n.kind in {nkCall, nkCommand} and
|
||||
n[0].info.exactEquals(c.config.expandPosition))):
|
||||
expandStarted = true
|
||||
c.config.expandProgress = true
|
||||
if c.config.expandLevels == 0:
|
||||
c.config.expandNodeResult = $n
|
||||
suggestQuit()
|
||||
|
||||
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
|
||||
if nfSem in n.flags: return
|
||||
case n.kind
|
||||
@@ -2997,7 +3029,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# the node is left intact for now
|
||||
discard
|
||||
of nkStaticExpr: result = semStaticExpr(c, n[0])
|
||||
of nkAsgn: result = semAsgn(c, n)
|
||||
of nkAsgn, nkFastAsgn: result = semAsgn(c, n)
|
||||
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
|
||||
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
|
||||
of nkRaiseStmt: result = semRaise(c, n)
|
||||
@@ -3076,3 +3108,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
localError(c.config, n.info, "invalid expression: " &
|
||||
renderTree(n, {renderNoComments}))
|
||||
if result != nil: incl(result.flags, nfSem)
|
||||
|
||||
when defined(nimsuggest):
|
||||
if expandStarted:
|
||||
c.config.expandNodeResult = $result
|
||||
suggestQuit()
|
||||
|
||||
@@ -133,7 +133,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
||||
of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
|
||||
of mBitnotI:
|
||||
if n.typ.isUnsigned:
|
||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, idgen, g)
|
||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, idgen, g)
|
||||
else:
|
||||
result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
|
||||
@@ -248,23 +248,23 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
||||
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
|
||||
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
|
||||
of mAddU:
|
||||
let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
|
||||
let val = maskBytes(getInt(a) + getInt(b), int(getSize(g.config, n.typ)))
|
||||
result = newIntNodeT(val, n, idgen, g)
|
||||
of mSubU:
|
||||
let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
|
||||
let val = maskBytes(getInt(a) - getInt(b), int(getSize(g.config, n.typ)))
|
||||
result = newIntNodeT(val, n, idgen, g)
|
||||
# echo "subU: ", val, " n: ", n, " result: ", val
|
||||
of mMulU:
|
||||
let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
|
||||
let val = maskBytes(getInt(a) * getInt(b), int(getSize(g.config, n.typ)))
|
||||
result = newIntNodeT(val, n, idgen, g)
|
||||
of mModU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA mod argB, n, idgen, g)
|
||||
of mDivU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA div argB, n, idgen, g)
|
||||
of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)
|
||||
@@ -412,7 +412,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
|
||||
rangeCheck(n, getInt(result), g)
|
||||
of tyFloat..tyFloat64:
|
||||
case srcTyp.kind
|
||||
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
|
||||
result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
|
||||
else:
|
||||
result = a
|
||||
|
||||
@@ -179,7 +179,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
let s = newSymS(skUnknown, getIdentNode(c, n), c)
|
||||
addPrelimDecl(c, s)
|
||||
styleCheckDef(c.config, n.info, s, kind)
|
||||
styleCheckDef(c, n.info, s, kind)
|
||||
onDef(n.info, s)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
|
||||
@@ -433,7 +433,7 @@ proc semQuantifier(c: PContext; n: PNode): PNode =
|
||||
let op = considerQuotedIdent(c, it[0])
|
||||
if op.id == ord(wIn):
|
||||
let v = newSymS(skForVar, it[1], c)
|
||||
styleCheckDef(c.config, v)
|
||||
styleCheckDef(c, v)
|
||||
onDef(it[1].info, v)
|
||||
let domain = semExprWithType(c, it[2], {efWantIterator})
|
||||
v.typ = domain.typ
|
||||
|
||||
@@ -366,10 +366,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
||||
if objType.kind == tyObject:
|
||||
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
||||
let initResult = semConstructTypeAux(c, constrCtx, {})
|
||||
assert constrCtx.missingFields.len > 0
|
||||
localError(c.config, info,
|
||||
"The $1 type doesn't have a default value. The following fields must " &
|
||||
"be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
||||
if constrCtx.missingFields.len > 0:
|
||||
localError(c.config, info,
|
||||
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
||||
elif objType.kind == tyDistinct:
|
||||
localError(c.config, info,
|
||||
"The $1 distinct type doesn't have a default value." % typeToString(t))
|
||||
|
||||
@@ -851,11 +851,15 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
elif isIndirectCall(tracked, a):
|
||||
assumeTheWorst(tracked, n, op)
|
||||
gcsafeAndSideeffectCheck()
|
||||
else:
|
||||
if strictEffects in tracked.c.features and a.kind == nkSym and
|
||||
a.sym.kind in routineKinds:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
else:
|
||||
mergeRaises(tracked, effectList[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList[tagEffects], n)
|
||||
gcsafeAndSideeffectCheck()
|
||||
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished}:
|
||||
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
|
||||
for i in 1..<n.len:
|
||||
trackOperandForIndirectCall(tracked, n[i], op, i, a)
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
@@ -880,7 +884,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
optStaticBoundsCheck in tracked.currOptions:
|
||||
checkBounds(tracked, n[1], n[2])
|
||||
|
||||
if a.kind != nkSym or a.sym.magic != mRunnableExamples:
|
||||
if a.kind != nkSym or a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst}:
|
||||
for i in 0..<n.safeLen:
|
||||
track(tracked, n[i])
|
||||
|
||||
@@ -1047,7 +1051,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
addAsgnFact(tracked.guards, n[0], n[1])
|
||||
notNilCheck(tracked, n[1], n[0].typ)
|
||||
when false: cstringCheck(tracked, n)
|
||||
if tracked.owner.kind != skMacro:
|
||||
if tracked.owner.kind != skMacro and n[0].typ.kind notin {tyOpenArray, tyVarargs}:
|
||||
createTypeBoundOps(tracked, n[0].typ, n.info)
|
||||
if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym):
|
||||
checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n[1])
|
||||
@@ -1212,6 +1216,11 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
message(tracked.config, n.info, warnCstringConv,
|
||||
"implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" %
|
||||
$n[1])
|
||||
if n.typ.skipTypes(abstractInst).kind == tyCstring and
|
||||
isCharArrayPtr(n[1].typ, true):
|
||||
message(tracked.config, n.info, warnPtrToCstringConv,
|
||||
$n[1].typ)
|
||||
|
||||
|
||||
let t = n.typ.skipTypes(abstractInst)
|
||||
if t.kind == tyEnum:
|
||||
@@ -1389,6 +1398,9 @@ proc hasRealBody(s: PSym): bool =
|
||||
|
||||
proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
let g = c.graph
|
||||
when defined(nimsuggest):
|
||||
if g.config.expandDone():
|
||||
return
|
||||
var effects = s.typ.n[0]
|
||||
if effects.kind != nkEffectList: return
|
||||
# effects already computed?
|
||||
|
||||
@@ -191,6 +191,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
isImported = true
|
||||
elif not isException(typ):
|
||||
localError(c.config, typeNode.info, errExprCannotBeRaised)
|
||||
elif not isDefectOrCatchableError(typ):
|
||||
message(c.config, a.info, warnBareExcept, "catch a more precise Exception deriving from CatchableError or Defect.")
|
||||
|
||||
if containsOrIncl(check, typ.id):
|
||||
localError(c.config, typeNode.info, errExceptionAlreadyHandled)
|
||||
@@ -230,7 +232,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
elif a.len == 1:
|
||||
# count number of ``except: body`` blocks
|
||||
inc catchAllExcepts
|
||||
|
||||
message(c.config, a.info, warnBareExcept,
|
||||
"The bare except clause is deprecated; use `except CatchableError:` instead")
|
||||
else:
|
||||
# support ``except KeyError, ValueError, ... : body``
|
||||
if catchAllExcepts > 0:
|
||||
@@ -306,7 +309,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
|
||||
if identWithin(n[i], s): return true
|
||||
result = n.kind == nkSym and n.sym.name.id == s.id
|
||||
|
||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
|
||||
if isTopLevel(c):
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||
incl(result.flags, sfGlobal)
|
||||
@@ -330,7 +333,8 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||
discard
|
||||
result = n.info
|
||||
let info = getLineInfo(n)
|
||||
suggestSym(c.graph, info, result, c.graph.usageSym)
|
||||
if reportToNimsuggest:
|
||||
suggestSym(c.graph, info, result, c.graph.usageSym)
|
||||
|
||||
proc checkNilable(c: PContext; v: PSym) =
|
||||
if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and v.typ.requiresInit:
|
||||
@@ -368,7 +372,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
|
||||
let typ = semTypeNode(c, a[^2], nil)
|
||||
for j in 0..<a.len-2:
|
||||
let v = semIdentDef(c, a[j], skParam)
|
||||
styleCheckDef(c.config, v)
|
||||
styleCheckDef(c, v)
|
||||
onDef(a[j].info, v)
|
||||
v.typ = typ
|
||||
strTableIncl(c.signatures, v)
|
||||
@@ -595,8 +599,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
if a.kind != nkVarTuple: typ else: tup[j])
|
||||
addToVarSection(c, result, n, a)
|
||||
continue
|
||||
var v = semIdentDef(c, a[j], symkind)
|
||||
styleCheckDef(c.config, v)
|
||||
var v = semIdentDef(c, a[j], symkind, false)
|
||||
styleCheckDef(c, v)
|
||||
onDef(a[j].info, v)
|
||||
if sfGenSym notin v.flags:
|
||||
if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
|
||||
@@ -660,6 +664,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
|
||||
message(c.config, v.info, hintGlobalVar)
|
||||
|
||||
suggestSym(c.graph, v.info, v, c.graph.usageSym)
|
||||
|
||||
proc semConst(c: PContext, n: PNode): PNode =
|
||||
result = copyNode(n)
|
||||
inc c.inStaticContext
|
||||
@@ -719,7 +725,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
var v = semIdentDef(c, a[j], skConst)
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
elif v.owner == nil: v.owner = getCurrOwner(c)
|
||||
styleCheckDef(c.config, v)
|
||||
styleCheckDef(c, v)
|
||||
onDef(a[j].info, v)
|
||||
|
||||
if a.kind != nkVarTuple:
|
||||
@@ -744,7 +750,7 @@ include semfields
|
||||
proc symForVar(c: PContext, n: PNode): PSym =
|
||||
let m = if n.kind == nkPragmaExpr: n[0] else: n
|
||||
result = newSymG(skForVar, m, c)
|
||||
styleCheckDef(c.config, result)
|
||||
styleCheckDef(c, result)
|
||||
onDef(n.info, result)
|
||||
if n.kind == nkPragmaExpr:
|
||||
pragma(c, result, n[1], forVarPragmas)
|
||||
@@ -975,7 +981,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
|
||||
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool}
|
||||
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
|
||||
case caseTyp.kind
|
||||
of shouldChckCovered:
|
||||
chckCovered = true
|
||||
@@ -1362,7 +1368,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
let name = typeSectionTypeName(c, a[0])
|
||||
var s = name.sym
|
||||
# check the style here after the pragmas have been processed:
|
||||
styleCheckDef(c.config, s)
|
||||
styleCheckDef(c, s)
|
||||
# compute the type's size and check for illegal recursions:
|
||||
if a[1].kind == nkEmpty:
|
||||
var x = a[2]
|
||||
@@ -1976,7 +1982,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
("'" & proto.name.s & "' from " & c.config$proto.info &
|
||||
" '" & s.name.s & "' from " & c.config$s.info))
|
||||
|
||||
styleCheckDef(c.config, s)
|
||||
styleCheckDef(c, s)
|
||||
if hasProto:
|
||||
onDefResolveForward(n[namePos].info, proto)
|
||||
else:
|
||||
@@ -2053,7 +2059,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
trackProc(c, s, s.ast[bodyPos])
|
||||
else:
|
||||
if (s.typ[0] != nil and s.kind != skIterator):
|
||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info))
|
||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, s, n.info))
|
||||
|
||||
openScope(c)
|
||||
n[bodyPos] = semGenericStmt(c, n[bodyPos])
|
||||
@@ -2075,6 +2081,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
incl(s.flags, sfWasForwarded)
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||
sideEffectsCheck(c, s)
|
||||
|
||||
closeScope(c) # close scope for parameters
|
||||
# c.currentScope = oldScope
|
||||
popOwner(c)
|
||||
|
||||
@@ -230,7 +230,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||
if n.kind != nkSym:
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(c.c.config, n.info, local)
|
||||
styleCheckDef(c.c, n.info, local)
|
||||
onDef(n.info, local)
|
||||
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
|
||||
if k == skParam and c.inTemplateHeader > 0:
|
||||
@@ -250,8 +250,14 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
result = n
|
||||
of OverloadableSyms-{skEnumField}:
|
||||
of OverloadableSyms-{skEnumField, skTemplate, skMacro}:
|
||||
result = symChoice(c, n, s, scOpen, isField)
|
||||
of skTemplate, skMacro:
|
||||
result = symChoice(c, n, s, scOpen, isField)
|
||||
if result.kind == nkSym:
|
||||
# template/macro symbols might need to be semchecked again
|
||||
# prepareOperand etc don't do this without setting the type to nil
|
||||
result.typ = nil
|
||||
of skGenericParam:
|
||||
if isField and sfGenSym in s.flags: result = n
|
||||
else: result = newSymNodeTypeDesc(s, c.idgen, n.info)
|
||||
@@ -270,8 +276,9 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||
# Issue #12832
|
||||
when defined(nimsuggest):
|
||||
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
styleCheckUse(c.config, n.info, s)
|
||||
# field access (dot expr) will be handled by builtinFieldAccess
|
||||
if not isField:
|
||||
styleCheckUse(c, n.info, s)
|
||||
|
||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -296,7 +303,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
||||
var s = newGenSym(k, ident, c)
|
||||
s.ast = n
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(c.c.config, n.info, s)
|
||||
styleCheckDef(c.c, n.info, s)
|
||||
onDef(n.info, s)
|
||||
n[namePos] = newSymNode(s, n[namePos].info)
|
||||
else:
|
||||
@@ -373,6 +380,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
result = newSymNode(s, n.info)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
if s.kind in {skType, skVar, skLet, skConst}:
|
||||
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
|
||||
result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
|
||||
of nkBind:
|
||||
result = semTemplBody(c, n[0])
|
||||
@@ -430,7 +439,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
# labels are always 'gensym'ed:
|
||||
let s = newGenSym(skLabel, n[0], c)
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(c.c.config, s)
|
||||
styleCheckDef(c.c, s)
|
||||
onDef(n[0].info, s)
|
||||
n[0] = newSymNode(s, n[0].info)
|
||||
n[1] = semTemplBody(c, n[1])
|
||||
@@ -618,7 +627,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
s.owner.name.s == "vm" and s.name.s == "stackTrace":
|
||||
incl(s.flags, sfCallsite)
|
||||
|
||||
styleCheckDef(c.config, s)
|
||||
styleCheckDef(c, s)
|
||||
onDef(n[namePos].info, s)
|
||||
# check parameter list:
|
||||
#s.scope = c.currentScope
|
||||
|
||||
@@ -139,7 +139,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
e.flags.incl {sfUsed, sfExported}
|
||||
|
||||
result.n.add symNode
|
||||
styleCheckDef(c.config, e)
|
||||
styleCheckDef(c, e)
|
||||
onDef(e.info, e)
|
||||
if sfGenSym notin e.flags:
|
||||
if not isPure:
|
||||
@@ -476,7 +476,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
result.n.add newSymNode(field)
|
||||
addSonSkipIntLit(result, typ, c.idgen)
|
||||
styleCheckDef(c.config, a[j].info, field)
|
||||
styleCheckDef(c, a[j].info, field)
|
||||
onDef(field.info, field)
|
||||
if result.n.len == 0: result.n = nil
|
||||
if isTupleRecursive(result):
|
||||
@@ -808,7 +808,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
|
||||
if a.kind == nkEmpty: father.add newSymNode(f)
|
||||
else: a.add newSymNode(f)
|
||||
styleCheckDef(c.config, f)
|
||||
styleCheckDef(c, f)
|
||||
onDef(f.info, f)
|
||||
if a.kind != nkEmpty: father.add a
|
||||
of nkSym:
|
||||
@@ -1248,7 +1248,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
if hasDefault:
|
||||
def = a[^1]
|
||||
block determineType:
|
||||
if genericParams.isGenericParams:
|
||||
if genericParams != nil and genericParams.len > 0:
|
||||
def = semGenericStmt(c, def)
|
||||
if hasUnresolvedArgs(c, def):
|
||||
def.typ = makeTypeFromExpr(c, def.copyTree)
|
||||
@@ -1315,7 +1315,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
result.n.add newSymNode(arg)
|
||||
rawAddSon(result, finalType)
|
||||
addParamOrResult(c, arg, kind)
|
||||
styleCheckDef(c.config, a[j].info, arg)
|
||||
styleCheckDef(c, a[j].info, arg)
|
||||
onDef(a[j].info, arg)
|
||||
if {optNimV1Emulation, optNimV12Emulation} * c.config.globalOptions == {}:
|
||||
a[j] = newSymNode(arg)
|
||||
@@ -1376,7 +1376,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
result.flags.excl tfHasMeta
|
||||
result.n.typ = r
|
||||
|
||||
if genericParams.isGenericParams:
|
||||
if genericParams != nil and genericParams.len > 0:
|
||||
for n in genericParams:
|
||||
if {sfUsed, sfAnon} * n.sym.flags == {}:
|
||||
result.flags.incl tfUnresolved
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
## Computes hash values for routine (proc, method etc) signatures.
|
||||
|
||||
import ast, tables, ropes, md5, modulegraphs
|
||||
import ast, tables, ropes, md5, modulegraphs, options, msgs, packages, pathutils
|
||||
from hashes import Hash
|
||||
import types
|
||||
|
||||
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
|
||||
proc `&=`(c: var MD5Context, ch: char) =
|
||||
# XXX suspicious code here; relies on ch being zero terminated?
|
||||
md5Update(c, unsafeAddr ch, 1)
|
||||
md5Update(c, cast[cstring](unsafeAddr ch), 1)
|
||||
proc `&=`(c: var MD5Context, r: Rope) =
|
||||
for l in leaves(r): md5Update(c, l.cstring, l.len)
|
||||
proc `&=`(c: var MD5Context, i: BiggestInt) =
|
||||
@@ -39,8 +39,7 @@ type
|
||||
CoDistinct
|
||||
CoHashTypeInsideNode
|
||||
|
||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
|
||||
|
||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef)
|
||||
proc hashSym(c: var MD5Context, s: PSym) =
|
||||
if sfAnon in s.flags or s.kind == skGenericParam:
|
||||
c &= ":anon"
|
||||
@@ -51,20 +50,21 @@ proc hashSym(c: var MD5Context, s: PSym) =
|
||||
c &= "."
|
||||
it = it.owner
|
||||
|
||||
proc hashTypeSym(c: var MD5Context, s: PSym) =
|
||||
proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) =
|
||||
if sfAnon in s.flags or s.kind == skGenericParam:
|
||||
c &= ":anon"
|
||||
else:
|
||||
var it = s
|
||||
c &= customPath(conf.toFullPath(s.info))
|
||||
while it != nil:
|
||||
if sfFromGeneric in it.flags and it.kind in routineKinds and
|
||||
it.typ != nil:
|
||||
hashType c, it.typ, {CoProc}
|
||||
hashType c, it.typ, {CoProc}, conf
|
||||
c &= it.name.s
|
||||
c &= "."
|
||||
it = it.owner
|
||||
|
||||
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
|
||||
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) =
|
||||
if n == nil:
|
||||
c &= "\255"
|
||||
return
|
||||
@@ -79,7 +79,7 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
|
||||
of nkSym:
|
||||
hashSym(c, n.sym)
|
||||
if CoHashTypeInsideNode in flags and n.sym.typ != nil:
|
||||
hashType(c, n.sym.typ, flags)
|
||||
hashType(c, n.sym.typ, flags, conf)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
let v = n.intVal
|
||||
lowlevel v
|
||||
@@ -89,9 +89,9 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
c &= n.strVal
|
||||
else:
|
||||
for i in 0..<n.len: hashTree(c, n[i], flags)
|
||||
for i in 0..<n.len: hashTree(c, n[i], flags, conf)
|
||||
|
||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) =
|
||||
if t == nil:
|
||||
c &= "\254"
|
||||
return
|
||||
@@ -99,14 +99,14 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
case t.kind
|
||||
of tyGenericInvocation:
|
||||
for i in 0..<t.len:
|
||||
c.hashType t[i], flags
|
||||
c.hashType t[i], flags, conf
|
||||
of tyDistinct:
|
||||
if CoDistinct in flags:
|
||||
if t.sym != nil: c.hashSym(t.sym)
|
||||
if t.sym == nil or tfFromGeneric in t.flags:
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
elif CoType in flags or t.sym == nil:
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
else:
|
||||
c.hashSym(t.sym)
|
||||
of tyGenericInst:
|
||||
@@ -116,15 +116,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
# value for each instantiation, so we hash the generic parameters here:
|
||||
let normalizedType = t.skipGenericAlias
|
||||
for i in 0..<normalizedType.len - 1:
|
||||
c.hashType t[i], flags
|
||||
c.hashType t[i], flags, conf
|
||||
else:
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
of tyOwned:
|
||||
if CoConsiderOwned in flags:
|
||||
c &= char(t.kind)
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
of tyBool, tyChar, tyInt..tyUInt64:
|
||||
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
||||
# produced instead of ``NI``:
|
||||
@@ -138,7 +138,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
t.typeInst = nil
|
||||
assert inst.kind == tyGenericInst
|
||||
for i in 0..<inst.len - 1:
|
||||
c.hashType inst[i], flags
|
||||
c.hashType inst[i], flags, conf
|
||||
t.typeInst = inst
|
||||
return
|
||||
c &= char(t.kind)
|
||||
@@ -150,7 +150,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
# The user has set a specific name for this type
|
||||
c &= t.sym.loc.r
|
||||
elif CoOwnerSig in flags:
|
||||
c.hashTypeSym(t.sym)
|
||||
c.hashTypeSym(t.sym, conf)
|
||||
else:
|
||||
c.hashSym(t.sym)
|
||||
|
||||
@@ -169,7 +169,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
# xxx instead, use a hash table to indicate we've already visited a type, which
|
||||
# would also be more efficient.
|
||||
symWithFlags.flags.excl {sfAnon, sfGenSym}
|
||||
hashTree(c, t.n, flags + {CoHashTypeInsideNode})
|
||||
hashTree(c, t.n, flags + {CoHashTypeInsideNode}, conf)
|
||||
symWithFlags.flags = oldFlags
|
||||
else:
|
||||
# The object has no fields: we _must_ add something here in order to
|
||||
@@ -179,14 +179,14 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
else:
|
||||
c &= t.id
|
||||
if t.len > 0 and t[0] != nil:
|
||||
hashType c, t[0], flags
|
||||
hashType c, t[0], flags, conf
|
||||
of tyRef, tyPtr, tyGenericBody, tyVar:
|
||||
c &= char(t.kind)
|
||||
c.hashType t.lastSon, flags
|
||||
c.hashType t.lastSon, flags, conf
|
||||
if tfVarIsPtr in t.flags: c &= ".varisptr"
|
||||
of tyFromExpr:
|
||||
c &= char(t.kind)
|
||||
c.hashTree(t.n, {})
|
||||
c.hashTree(t.n, {}, conf)
|
||||
of tyTuple:
|
||||
c &= char(t.kind)
|
||||
if t.n != nil and CoType notin flags:
|
||||
@@ -195,19 +195,19 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
assert(t.n[i].kind == nkSym)
|
||||
c &= t.n[i].sym.name.s
|
||||
c &= ':'
|
||||
c.hashType(t[i], flags+{CoIgnoreRange})
|
||||
c.hashType(t[i], flags+{CoIgnoreRange}, conf)
|
||||
c &= ','
|
||||
else:
|
||||
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}
|
||||
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}, conf
|
||||
of tyRange:
|
||||
if CoIgnoreRange notin flags:
|
||||
c &= char(t.kind)
|
||||
c.hashTree(t.n, {})
|
||||
c.hashType(t[0], flags)
|
||||
c.hashTree(t.n, {}, conf)
|
||||
c.hashType(t[0], flags, conf)
|
||||
of tyStatic:
|
||||
c &= char(t.kind)
|
||||
c.hashTree(t.n, {})
|
||||
c.hashType(t[0], flags)
|
||||
c.hashTree(t.n, {}, conf)
|
||||
c.hashType(t[0], flags, conf)
|
||||
of tyProc:
|
||||
c &= char(t.kind)
|
||||
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
|
||||
@@ -217,11 +217,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
let param = params[i].sym
|
||||
c &= param.name.s
|
||||
c &= ':'
|
||||
c.hashType(param.typ, flags)
|
||||
c.hashType(param.typ, flags, conf)
|
||||
c &= ','
|
||||
c.hashType(t[0], flags)
|
||||
c.hashType(t[0], flags, conf)
|
||||
else:
|
||||
for i in 0..<t.len: c.hashType(t[i], flags)
|
||||
for i in 0..<t.len: c.hashType(t[i], flags, conf)
|
||||
c &= char(t.callConv)
|
||||
# purity of functions doesn't have to affect the mangling (which is in fact
|
||||
# problematic for HCR - someone could have cached a pointer to another
|
||||
@@ -233,10 +233,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
if tfVarargs in t.flags: c &= ".varargs"
|
||||
of tyArray:
|
||||
c &= char(t.kind)
|
||||
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange})
|
||||
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange}, conf)
|
||||
else:
|
||||
c &= char(t.kind)
|
||||
for i in 0..<t.len: c.hashType(t[i], flags)
|
||||
for i in 0..<t.len: c.hashType(t[i], flags, conf)
|
||||
if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
|
||||
|
||||
when defined(debugSigHashes):
|
||||
@@ -253,19 +253,19 @@ when defined(debugSigHashes):
|
||||
# select hash, type from sighashes where hash in
|
||||
# (select hash from sighashes group by hash having count(*) > 1) order by hash;
|
||||
|
||||
proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash =
|
||||
proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash =
|
||||
var c: MD5Context
|
||||
md5Init c
|
||||
hashType c, t, flags+{CoOwnerSig}
|
||||
hashType c, t, flags+{CoOwnerSig}, conf
|
||||
md5Final c, result.MD5Digest
|
||||
when defined(debugSigHashes):
|
||||
db.exec(sql"INSERT OR IGNORE INTO sighashes(type, hash) VALUES (?, ?)",
|
||||
typeToString(t), $result)
|
||||
|
||||
proc hashProc*(s: PSym): SigHash =
|
||||
proc hashProc*(s: PSym; conf: ConfigRef): SigHash =
|
||||
var c: MD5Context
|
||||
md5Init c
|
||||
hashType c, s.typ, {CoProc}
|
||||
hashType c, s.typ, {CoProc}, conf
|
||||
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
@@ -311,9 +311,9 @@ proc hashOwner*(s: PSym): SigHash =
|
||||
|
||||
md5Final c, result.MD5Digest
|
||||
|
||||
proc sigHash*(s: PSym): SigHash =
|
||||
proc sigHash*(s: PSym; conf: ConfigRef): SigHash =
|
||||
if s.kind in routineKinds and s.typ != nil:
|
||||
result = hashProc(s)
|
||||
result = hashProc(s, conf)
|
||||
else:
|
||||
result = hashNonProc(s)
|
||||
|
||||
@@ -374,7 +374,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
|
||||
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
c.hashType(sym.typ, {CoProc})
|
||||
c.hashType(sym.typ, {CoProc}, graph.config)
|
||||
c &= char(sym.kind)
|
||||
c.md5Final(result.MD5Digest)
|
||||
graph.symBodyHashes[sym.id] = result # protect from recursion in the body
|
||||
@@ -387,12 +387,12 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
|
||||
graph.symBodyHashes[sym.id] = result
|
||||
|
||||
proc idOrSig*(s: PSym, currentModule: string,
|
||||
sigCollisions: var CountTable[SigHash]): Rope =
|
||||
sigCollisions: var CountTable[SigHash]; conf: ConfigRef): Rope =
|
||||
if s.kind in routineKinds and s.typ != nil:
|
||||
# signatures for exported routines are reliable enough to
|
||||
# produce a unique name and this means produced C++ is more stable regarding
|
||||
# Nim changes:
|
||||
let sig = hashProc(s)
|
||||
let sig = hashProc(s, conf)
|
||||
result = rope($sig)
|
||||
#let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
|
||||
let counter = sigCollisions.getOrDefault(sig)
|
||||
|
||||
@@ -2461,7 +2461,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
if m.callee.n[f].kind != nkSym:
|
||||
internalError(c.config, n[a].info, "matches")
|
||||
noMatch()
|
||||
if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a))
|
||||
if flexibleOptionalParams in c.features and a >= firstArgBlock:
|
||||
f = max(f, m.callee.n.len - (n.len - a))
|
||||
formal = m.callee.n[f].sym
|
||||
m.firstMismatch.kind = kTypeMismatch
|
||||
if containsOrIncl(marker, formal.position) and container.isNil:
|
||||
|
||||
@@ -40,15 +40,15 @@ proc inc(arg: var OffsetAccum; value: int) =
|
||||
else:
|
||||
arg.offset += value
|
||||
|
||||
proc alignmentMax(a,b: int): int =
|
||||
proc alignmentMax(a, b: int): int =
|
||||
if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if a == szUnknownSize or b == szUnknownSize:
|
||||
szUnknownSize
|
||||
else:
|
||||
max(a,b)
|
||||
max(a, b)
|
||||
|
||||
proc align(arg: var OffsetAccum; value: int) =
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if value == szUnknownSize or arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize:
|
||||
arg.maxAlign = szUnknownSize
|
||||
arg.offset = szUnknownSize
|
||||
@@ -112,7 +112,7 @@ proc setOffsetsToUnknown(n: PNode) =
|
||||
for i in 0..<n.safeLen:
|
||||
setOffsetsToUnknown(n[i])
|
||||
|
||||
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum) =
|
||||
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
|
||||
@@ -196,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo
|
||||
accum.offset = szUnknownSize
|
||||
|
||||
proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
template setSize(typ, s) =
|
||||
typ.size = s
|
||||
typ.align = s
|
||||
typ.paddingAtEnd = 0
|
||||
|
||||
## computes and sets ``size`` and ``align`` members of ``typ``
|
||||
assert typ != nil
|
||||
let hasSize = typ.size != szUncomputedSize
|
||||
@@ -258,14 +263,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
|
||||
of tyArray:
|
||||
computeSizeAlign(conf, typ[1])
|
||||
let elemSize = typ[1].size
|
||||
let elemSize = typ[1].size
|
||||
let len = lengthOrd(conf, typ[0])
|
||||
if elemSize < 0:
|
||||
typ.size = elemSize
|
||||
typ.align = int16(elemSize)
|
||||
elif len < 0:
|
||||
typ.size = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
else:
|
||||
typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize)
|
||||
typ.align = typ[1].align
|
||||
@@ -314,10 +319,10 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
typ.align = int16(conf.floatInt64Align)
|
||||
elif align(length, 8) mod 8 == 0:
|
||||
typ.size = align(length, 8) div 8
|
||||
typ.align = int16(conf.floatInt64Align)
|
||||
typ.align = 1
|
||||
else:
|
||||
typ.size = align(length, 8) div 8 + 1
|
||||
typ.align = int16(conf.floatInt64Align)
|
||||
typ.align = 1
|
||||
of tyRange:
|
||||
computeSizeAlign(conf, typ[0])
|
||||
typ.size = typ[0].size
|
||||
@@ -375,10 +380,8 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo
|
||||
localError(conf, info, "union type may not have an object header")
|
||||
accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize)
|
||||
elif tfPacked in typ.flags:
|
||||
computeUnionObjectOffsetsFoldFunction(conf, typ.n, true, accum)
|
||||
else:
|
||||
computeUnionObjectOffsetsFoldFunction(conf, typ.n, false, accum)
|
||||
computeUnionObjectOffsetsFoldFunction(conf, typ.n, tfPacked in typ.flags, accum)
|
||||
elif tfPacked in typ.flags:
|
||||
accum.maxAlign = 1
|
||||
computeObjectOffsetsFoldFunction(conf, typ.n, true, accum)
|
||||
@@ -445,6 +448,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
typ.size = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
typ.paddingAtEnd = szUnknownSize
|
||||
of tyInt, tyUInt:
|
||||
setSize typ, conf.target.intSize.int16
|
||||
of tyBool, tyChar, tyUInt8, tyInt8:
|
||||
setSize typ, 1
|
||||
of tyInt16, tyUInt16:
|
||||
setSize typ, 2
|
||||
of tyInt32, tyUInt32:
|
||||
setSize typ, 4
|
||||
of tyInt64, tyUInt64:
|
||||
setSize typ, 8
|
||||
else:
|
||||
typ.size = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
@@ -482,7 +495,7 @@ template foldOffsetOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode =
|
||||
## Returns an int literal node of the given offsetof expression in `n`.
|
||||
## Falls back to `fallback`, if the `offsetof` expression can't be processed.
|
||||
let config = conf
|
||||
let node : PNode = n
|
||||
let node = n
|
||||
var dotExpr: PNode
|
||||
block findDotExpr:
|
||||
if node[1].kind == nkDotExpr:
|
||||
|
||||
@@ -221,7 +221,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType;
|
||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||
var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options)
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||
|
||||
let temp = addLocalVar(g, varSection, varInit, idgen, owner, argType,
|
||||
@@ -260,17 +260,17 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType;
|
||||
slice[0].typ = getSysType(g, n.info, tyInt) # fake type
|
||||
var fieldB = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options)
|
||||
fieldB.typ = getSysType(g, n.info, tyInt)
|
||||
objType.addField(fieldB, g.cache, idgen)
|
||||
discard objType.addField(fieldB, g.cache, idgen)
|
||||
|
||||
if getMagic(n) == mSlice:
|
||||
let a = genAddrOf(n[1], idgen)
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
|
||||
var fieldA = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options)
|
||||
fieldA.typ = getSysType(g, n.info, tyInt)
|
||||
objType.addField(fieldA, g.cache, idgen)
|
||||
discard objType.addField(fieldA, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
||||
|
||||
@@ -281,7 +281,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType;
|
||||
else:
|
||||
let a = genAddrOf(n, idgen)
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
|
||||
|
||||
@@ -299,7 +299,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType;
|
||||
# it is more efficient to pass a pointer instead:
|
||||
let a = genAddrOf(n, idgen)
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, field.typ,
|
||||
indirectAccess(castExpr, field, n.info),
|
||||
@@ -308,7 +308,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType;
|
||||
else:
|
||||
# boring case
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
||||
let threadLocal = addLocalVar(g, varSection, varInit,
|
||||
idgen, owner, field.typ,
|
||||
@@ -377,7 +377,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
|
||||
var argType = n[0].typ.skipTypes(abstractInst)
|
||||
var field = newSym(skField, getIdent(g.cache, "fn"), nextSymId idgen, owner, n.info, g.config.options)
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
|
||||
fn = indirectAccess(castExpr, field, n.info)
|
||||
elif fn.kind == nkSym and fn.sym.kind == skIterator:
|
||||
@@ -399,7 +399,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
|
||||
typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
|
||||
var field = newSym(skField, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info, g.config.options)
|
||||
field.typ = typ
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
|
||||
barrierAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
|
||||
@@ -407,7 +407,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
|
||||
if spawnKind == srFlowVar:
|
||||
var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options)
|
||||
field.typ = retType
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
fvField = newDotExpr(scratchObj, field)
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
# create flowVar:
|
||||
@@ -419,7 +419,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
|
||||
var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options)
|
||||
field.typ = newType(tyPtr, nextTypeId idgen, objType.owner)
|
||||
field.typ.rawAddSon(retType)
|
||||
objType.addField(field, g.cache, idgen)
|
||||
discard objType.addField(field, g.cache, idgen)
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest, idgen))
|
||||
|
||||
|
||||
@@ -117,10 +117,12 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
|
||||
elif sourceIdent != ident:
|
||||
result = 0
|
||||
|
||||
proc symToSuggest(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
|
||||
proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
|
||||
quality: range[0..100]; prefix: PrefixMatch;
|
||||
inTypeContext: bool; scope: int;
|
||||
useSuppliedInfo = false): Suggest =
|
||||
useSuppliedInfo = false,
|
||||
endLine: uint16 = 0,
|
||||
endCol = 0): Suggest =
|
||||
new(result)
|
||||
result.section = section
|
||||
result.quality = quality
|
||||
@@ -157,19 +159,27 @@ proc symToSuggest(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info:
|
||||
result.forth = ""
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.doc = extractDocComment(g, s)
|
||||
let infox =
|
||||
if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}:
|
||||
info
|
||||
else:
|
||||
s.info
|
||||
result.filePath = toFullPath(g.config, infox)
|
||||
result.line = toLinenumber(infox)
|
||||
result.column = toColumn(infox)
|
||||
if s.kind == skModule and s.ast.len != 0 and section != ideHighlight:
|
||||
result.filePath = toFullPath(g.config, s.ast[0].info)
|
||||
result.line = 1
|
||||
result.column = 0
|
||||
result.tokenLen = 0
|
||||
else:
|
||||
let infox =
|
||||
if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline, ideDeclaration}:
|
||||
info
|
||||
else:
|
||||
s.info
|
||||
result.filePath = toFullPath(g.config, infox)
|
||||
result.line = toLinenumber(infox)
|
||||
result.column = toColumn(infox)
|
||||
result.tokenLen = if section != ideHighlight:
|
||||
s.name.s.len
|
||||
else:
|
||||
getTokenLenFromSource(g.config, s.name.s, infox)
|
||||
result.version = g.config.suggestVersion
|
||||
result.tokenLen = if section != ideHighlight:
|
||||
s.name.s.len
|
||||
else:
|
||||
getTokenLenFromSource(g.config, s.name.s, infox)
|
||||
result.endLine = endLine
|
||||
result.endCol = endCol
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
result = $suggest.section
|
||||
@@ -203,14 +213,20 @@ proc `$`*(suggest: Suggest): string =
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version == 0:
|
||||
if suggest.version in {0, 3}:
|
||||
result.add(sep)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
|
||||
proc suggestResult(conf: ConfigRef; s: Suggest) =
|
||||
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
|
||||
result.add(sep)
|
||||
result.add($suggest.endLine)
|
||||
result.add(sep)
|
||||
result.add($suggest.endCol)
|
||||
|
||||
proc suggestResult*(conf: ConfigRef; s: Suggest) =
|
||||
if not isNil(conf.suggestionResultHook):
|
||||
conf.suggestionResultHook(s)
|
||||
else:
|
||||
@@ -424,7 +440,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
||||
t = skipTypes(t[0], skipPtrs)
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
suggestSymList(c, typ.n, field, n.info, outputs)
|
||||
|
||||
|
||||
suggestOperations(c, n, field, orig, outputs)
|
||||
if typ != orig:
|
||||
suggestOperations(c, n, field, typ, outputs)
|
||||
@@ -482,7 +498,7 @@ proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym
|
||||
if s.isNil: return
|
||||
if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags):
|
||||
suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym))
|
||||
if sfForward notin s.flags:
|
||||
if sfForward notin s.flags and g.config.suggestVersion != 3:
|
||||
suggestQuit()
|
||||
else:
|
||||
usageSym = s
|
||||
@@ -497,6 +513,8 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
|
||||
## misnamed: should be 'symDeclared'
|
||||
let conf = g.config
|
||||
when defined(nimsuggest):
|
||||
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
|
||||
|
||||
if conf.suggestVersion == 0:
|
||||
if s.allUsages.len == 0:
|
||||
s.allUsages = @[info]
|
||||
@@ -596,8 +614,7 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) =
|
||||
if sfError in s.flags: userError(conf, info, s)
|
||||
when defined(nimsuggest):
|
||||
suggestSym(c.graph, info, s, c.graph.usageSym, false)
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
styleCheckUse(conf, info, s)
|
||||
styleCheckUse(c, info, s)
|
||||
markOwnerModuleAsUsed(c, s)
|
||||
|
||||
proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
||||
@@ -692,3 +709,16 @@ proc suggestSentinel*(c: PContext) =
|
||||
|
||||
dec(c.compilesContextId)
|
||||
produceOutput(outputs, c.config)
|
||||
|
||||
when defined(nimsuggest):
|
||||
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
|
||||
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
|
||||
suggestSym(graph, info, s, graph.usageSym)
|
||||
|
||||
template getPContext(): untyped =
|
||||
when c is PContext: c
|
||||
else: c.c
|
||||
|
||||
template onDef*(info: TLineInfo; s: PSym) =
|
||||
let c = getPContext()
|
||||
onDef(c.graph, s, info)
|
||||
|
||||
@@ -57,6 +57,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
of tyVar, tyLent:
|
||||
if kind in {skProc, skFunc, skConst} and (views notin c.features):
|
||||
result = t
|
||||
elif taIsOpenArray in flags:
|
||||
result = t
|
||||
elif t.kind == tyLent and ((kind != skResult and views notin c.features) or
|
||||
kind == skParam): # lent can't be used as parameters.
|
||||
result = t
|
||||
@@ -231,7 +233,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind =
|
||||
case t.kind
|
||||
of tyVar:
|
||||
result = mutableView
|
||||
of tyLent, tyOpenArray:
|
||||
of tyLent, tyOpenArray, tyVarargs:
|
||||
result = immutableView
|
||||
of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
|
||||
tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic:
|
||||
|
||||
@@ -1145,13 +1145,14 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCstring,
|
||||
tyInt..tyUInt64, tyTyped, tyUntyped, tyVoid:
|
||||
result = sameFlags(a, b)
|
||||
if result and PickyCAliases in c.flags:
|
||||
if result and {PickyCAliases, ExactTypeDescValues} <= c.flags:
|
||||
# additional requirement for the caching of generics for importc'ed types:
|
||||
# the symbols must be identical too:
|
||||
let symFlagsA = if a.sym != nil: a.sym.flags else: {}
|
||||
let symFlagsB = if b.sym != nil: b.sym.flags else: {}
|
||||
if (symFlagsA+symFlagsB) * {sfImportc, sfExportc} != {}:
|
||||
result = symFlagsA == symFlagsB
|
||||
|
||||
of tyStatic, tyFromExpr:
|
||||
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
|
||||
if result and a.len == b.len and a.len == 1:
|
||||
@@ -1665,6 +1666,18 @@ proc isDefectException*(t: PType): bool =
|
||||
t = skipTypes(t[0], abstractPtrs)
|
||||
return false
|
||||
|
||||
proc isDefectOrCatchableError*(t: PType): bool =
|
||||
var t = t.skipTypes(abstractPtrs)
|
||||
while t.kind == tyObject:
|
||||
if t.sym != nil and t.sym.owner != nil and
|
||||
sfSystemModule in t.sym.owner.flags and
|
||||
(t.sym.name.s == "Defect" or
|
||||
t.sym.name.s == "CatchableError"):
|
||||
return true
|
||||
if t[0] == nil: break
|
||||
t = skipTypes(t[0], abstractPtrs)
|
||||
return false
|
||||
|
||||
proc isSinkTypeForParam*(t: PType): bool =
|
||||
# a parameter like 'seq[owned T]' must not be used only once, but its
|
||||
# elements must, so we detect this case here:
|
||||
@@ -1700,3 +1713,6 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
|
||||
result = allowPointerToChar
|
||||
else:
|
||||
discard
|
||||
|
||||
proc lacksMTypeField*(typ: PType): bool {.inline.} =
|
||||
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
|
||||
|
||||
@@ -479,7 +479,7 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
|
||||
# calls do construct, what we construct must be destroyed,
|
||||
# so dest cannot be a cursor:
|
||||
dest.flags.incl ownsData
|
||||
elif n.typ.kind in {tyLent, tyVar}:
|
||||
elif n.typ.kind in {tyLent, tyVar} and n.len > 1:
|
||||
# we know the result is derived from the first argument:
|
||||
var roots: seq[(PSym, int)]
|
||||
allRoots(n[1], roots, RootEscapes)
|
||||
@@ -647,13 +647,6 @@ proc deps(c: var Partitions; dest, src: PNode) =
|
||||
when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo
|
||||
c.s[vid].flags.incl preventCursor
|
||||
|
||||
const
|
||||
nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||
nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
||||
|
||||
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
|
||||
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
||||
@@ -855,7 +848,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) =
|
||||
# connect(graph, cursorVar)
|
||||
inc c.inLoop
|
||||
for child in n: computeLiveRanges(c, child)
|
||||
inc c.inLoop
|
||||
dec c.inLoop
|
||||
of nkElifBranch, nkElifExpr, nkElse, nkOfBranch:
|
||||
inc c.inConditional
|
||||
for child in n: computeLiveRanges(c, child)
|
||||
|
||||
214
compiler/vm.nim
214
compiler/vm.nim
@@ -85,9 +85,9 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
|
||||
when not defined(nimComputedGoto):
|
||||
{.pragma: computedGoto.}
|
||||
|
||||
proc ensureKind(n: var TFullReg, kind: TRegisterKind) =
|
||||
if n.kind != kind:
|
||||
n = TFullReg(kind: kind)
|
||||
proc ensureKind(n: var TFullReg, k: TRegisterKind) {.inline.} =
|
||||
if n.kind != k:
|
||||
n = TFullReg(kind: k)
|
||||
|
||||
template ensureKind(k: untyped) {.dirty.} =
|
||||
ensureKind(regs[ra], k)
|
||||
@@ -119,13 +119,13 @@ template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b)
|
||||
|
||||
proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: bool): bool =
|
||||
# nim bug: `isAssign: static bool` doesn't work, giving odd compiler error
|
||||
template fun(field, T, rkind) =
|
||||
template fun(field, typ, rkind) =
|
||||
if isAssign:
|
||||
cast[ptr T](address)[] = T(r.field)
|
||||
cast[ptr typ](address)[] = typ(r.field)
|
||||
else:
|
||||
r.ensureKind(rkind)
|
||||
let val = cast[ptr T](address)[]
|
||||
when T is SomeInteger | char:
|
||||
let val = cast[ptr typ](address)[]
|
||||
when typ is SomeInteger | char:
|
||||
r.field = BiggestInt(val)
|
||||
else:
|
||||
r.field = val
|
||||
@@ -434,8 +434,10 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
|
||||
of tyFloat..tyFloat64:
|
||||
dest.intVal = int(src.floatVal)
|
||||
else:
|
||||
let srcDist = (sizeof(src.intVal) - styp.size) * 8
|
||||
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
|
||||
let srcSize = getSize(c.config, styp)
|
||||
let destSize = getSize(c.config, desttyp)
|
||||
let srcDist = (sizeof(src.intVal) - srcSize) * 8
|
||||
let destDist = (sizeof(dest.intVal) - destSize) * 8
|
||||
var value = cast[BiggestUInt](src.intVal)
|
||||
value = (value shl srcDist) shr srcDist
|
||||
value = (value shl destDist) shr destDist
|
||||
@@ -519,6 +521,19 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool =
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
template takeAddress(reg, source) =
|
||||
reg.nodeAddr = addr source
|
||||
GC_ref source
|
||||
|
||||
proc takeCharAddress(c: PCtx, src: PNode, index: BiggestInt, pc: int): TFullReg =
|
||||
let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner)
|
||||
typ.add getSysType(c.graph, c.debug[pc], tyChar)
|
||||
var node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
|
||||
node.intVal = cast[int](src.strVal[index].addr)
|
||||
node.flags.incl nfIsPtr
|
||||
TFullReg(kind: rkNode, node: node)
|
||||
|
||||
|
||||
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
var pc = start
|
||||
var tos = tos
|
||||
@@ -635,7 +650,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNodeToReg:
|
||||
let ra = instr.regA
|
||||
let rb = instr.regB
|
||||
# opcDeref might already have loaded it into a register. XXX Let's hope
|
||||
# opcLdDeref might already have loaded it into a register. XXX Let's hope
|
||||
# this is still correct this way:
|
||||
if regs[rb].kind != rkNode:
|
||||
regs[ra] = regs[rb]
|
||||
@@ -652,6 +667,48 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
else:
|
||||
ensureKind(rkNode)
|
||||
regs[ra].node = nb
|
||||
of opcSlice:
|
||||
# A bodge, but this takes in `toOpenArray(rb, rc, rc)` and emits
|
||||
# nkTupleConstr(x, y, z) into the `regs[ra]`. These can later be used for calculating the slice we have taken.
|
||||
decodeBC(rkNode)
|
||||
let
|
||||
collection = regs[ra].node
|
||||
leftInd = regs[rb].intVal
|
||||
rightInd = regs[rc].intVal
|
||||
|
||||
proc rangeCheck(left, right: BiggestInt, safeLen: BiggestInt) =
|
||||
if left < 0:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(left, safeLen))
|
||||
|
||||
if right > safeLen:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(right, safeLen))
|
||||
|
||||
case collection.kind
|
||||
of nkTupleConstr: # slice of a slice
|
||||
let safeLen = collection[2].intVal - collection[1].intVal
|
||||
rangeCheck(leftInd, rightInd, safeLen)
|
||||
let
|
||||
leftInd = leftInd + collection[1].intVal # Slice is from the start of the old
|
||||
rightInd = rightInd + collection[1].intVal
|
||||
|
||||
regs[ra].node = newTree(
|
||||
nkTupleConstr,
|
||||
collection[0],
|
||||
newIntNode(nkIntLit, BiggestInt leftInd),
|
||||
newIntNode(nkIntLit, BiggestInt rightInd)
|
||||
)
|
||||
|
||||
else:
|
||||
let safeLen = safeArrLen(collection) - 1
|
||||
rangeCheck(leftInd, rightInd, safeLen)
|
||||
regs[ra].node = newTree(
|
||||
nkTupleConstr,
|
||||
collection,
|
||||
newIntNode(nkIntLit, BiggestInt leftInd),
|
||||
newIntNode(nkIntLit, BiggestInt rightInd)
|
||||
)
|
||||
|
||||
|
||||
of opcLdArr:
|
||||
# a = b[c]
|
||||
decodeBC(rkNode)
|
||||
@@ -659,7 +716,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
|
||||
let idx = regs[rc].intVal.int
|
||||
let src = regs[rb].node
|
||||
if src.kind in {nkStrLit..nkTripleStrLit}:
|
||||
case src.kind
|
||||
of nkTupleConstr: # refer to `of opcSlice`
|
||||
let
|
||||
left = src[1].intVal
|
||||
right = src[2].intVal
|
||||
realIndex = left + idx
|
||||
if idx in 0..(right - left):
|
||||
case src[0].kind
|
||||
of nkStrKinds:
|
||||
regs[ra].node = newIntNode(nkCharLit, ord src[0].strVal[int realIndex])
|
||||
of nkBracket:
|
||||
regs[ra].node = src[0][int realIndex]
|
||||
else:
|
||||
stackTrace(c, tos, pc, "opcLdArr internal error")
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
|
||||
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if idx <% src.strVal.len:
|
||||
regs[ra].node = newNodeI(nkCharLit, c.debug[pc])
|
||||
regs[ra].node.intVal = src.strVal[idx].ord
|
||||
@@ -676,10 +750,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
|
||||
let idx = regs[rc].intVal.int
|
||||
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
|
||||
if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len:
|
||||
regs[ra].nodeAddr = addr src.sons[idx]
|
||||
case src.kind
|
||||
of nkTupleConstr:
|
||||
let
|
||||
left = src[1].intVal
|
||||
right = src[2].intVal
|
||||
realIndex = left + idx
|
||||
if idx in 0..(right - left): # Refer to `opcSlice`
|
||||
case src[0].kind
|
||||
of nkStrKinds:
|
||||
regs[ra] = takeCharAddress(c, src[0], realIndex, pc)
|
||||
of nkBracket:
|
||||
takeAddress regs[ra], src.sons[0].sons[realIndex]
|
||||
else:
|
||||
stackTrace(c, tos, pc, "opcLdArrAddr internal error")
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1))
|
||||
if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len:
|
||||
takeAddress regs[ra], src.sons[idx]
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1))
|
||||
of opcLdStrIdx:
|
||||
decodeBC(rkInt)
|
||||
let idx = regs[rc].intVal.int
|
||||
@@ -696,13 +787,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let idx = regs[rc].intVal.int
|
||||
let s = regs[rb].node.strVal.addr # or `byaddr`
|
||||
if idx <% s[].len:
|
||||
# `makePtrType` not accessible from vm.nim
|
||||
let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner)
|
||||
typ.add getSysType(c.graph, c.debug[pc], tyChar)
|
||||
let node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
|
||||
node.intVal = cast[int](s[][idx].addr)
|
||||
node.flags.incl nfIsPtr
|
||||
regs[ra].node = node
|
||||
regs[ra] = takeCharAddress(c, regs[rb].node, idx, pc)
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s[].len-1))
|
||||
of opcWrArr:
|
||||
@@ -710,7 +795,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
decodeBC(rkNode)
|
||||
let idx = regs[rb].intVal.int
|
||||
let arr = regs[ra].node
|
||||
if arr.kind in {nkStrLit..nkTripleStrLit}:
|
||||
case arr.kind
|
||||
of nkTupleConstr: # refer to `opcSlice`
|
||||
let
|
||||
src = arr[0]
|
||||
left = arr[1].intVal
|
||||
right = arr[2].intVal
|
||||
realIndex = left + idx
|
||||
if idx in 0..(right - left):
|
||||
case src.kind
|
||||
of nkStrKinds:
|
||||
src.strVal[int(realIndex)] = char(regs[rc].intVal)
|
||||
of nkBracket:
|
||||
src[int(realIndex)] = regs[rc].node
|
||||
else:
|
||||
stackTrace(c, tos, pc, "opcWrArr internal error")
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
|
||||
of {nkStrLit..nkTripleStrLit}:
|
||||
if idx <% arr.strVal.len:
|
||||
arr.strVal[idx] = chr(regs[rc].intVal)
|
||||
else:
|
||||
@@ -745,11 +847,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of nkObjConstr:
|
||||
let n = src.sons[rc + 1]
|
||||
if n.kind == nkExprColonExpr:
|
||||
regs[ra].nodeAddr = addr n.sons[1]
|
||||
takeAddress regs[ra], n.sons[1]
|
||||
else:
|
||||
regs[ra].nodeAddr = addr src.sons[rc + 1]
|
||||
takeAddress regs[ra], src.sons[rc + 1]
|
||||
else:
|
||||
regs[ra].nodeAddr = addr src.sons[rc]
|
||||
takeAddress regs[ra], src.sons[rc]
|
||||
of opcWrObj:
|
||||
# a.b = c
|
||||
decodeBC(rkNode)
|
||||
@@ -776,7 +878,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
decodeB(rkNodeAddr)
|
||||
case regs[rb].kind
|
||||
of rkNode:
|
||||
regs[ra].nodeAddr = addr(regs[rb].node)
|
||||
takeAddress regs[ra], regs[rb].node
|
||||
of rkNodeAddr: # bug #14339
|
||||
regs[ra].nodeAddr = regs[rb].nodeAddr
|
||||
else:
|
||||
@@ -868,14 +970,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcLenSeq:
|
||||
decodeBImm(rkInt)
|
||||
#assert regs[rb].kind == nkBracket
|
||||
let high = (imm and 1) # discard flags
|
||||
let
|
||||
high = (imm and 1) # discard flags
|
||||
node = regs[rb].node
|
||||
if (imm and nimNodeFlag) != 0:
|
||||
# used by mNLen (NimNode.len)
|
||||
regs[ra].intVal = regs[rb].node.safeLen - high
|
||||
else:
|
||||
# safeArrLen also return string node len
|
||||
# used when string is passed as openArray in VM
|
||||
regs[ra].intVal = regs[rb].node.safeArrLen - high
|
||||
case node.kind
|
||||
of nkTupleConstr: # refer to `of opcSlice`
|
||||
regs[ra].intVal = node[2].intVal - node[1].intVal + 1 - high
|
||||
else:
|
||||
# safeArrLen also return string node len
|
||||
# used when string is passed as openArray in VM
|
||||
regs[ra].intVal = node.safeArrLen - high
|
||||
|
||||
of opcLenStr:
|
||||
decodeBImm(rkInt)
|
||||
assert regs[rb].kind == rkNode
|
||||
@@ -1004,6 +1113,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
decodeBC(rkInt)
|
||||
template getTyp(n): untyped =
|
||||
n.typ.skipTypes(abstractInst)
|
||||
template skipRegisterAddr(n: TFullReg): TFullReg =
|
||||
var tmp = n
|
||||
while tmp.kind == rkRegisterAddr:
|
||||
tmp = tmp.regAddr[]
|
||||
tmp
|
||||
|
||||
proc ptrEquality(n1: ptr PNode, n2: PNode): bool =
|
||||
## true if n2.intVal represents a ptr equal to n1
|
||||
let p1 = cast[int](n1)
|
||||
@@ -1017,16 +1132,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
return t2.kind in PtrLikeKinds and n2.intVal == p1
|
||||
else: return false
|
||||
|
||||
if regs[rb].kind == rkNodeAddr:
|
||||
if regs[rc].kind == rkNodeAddr:
|
||||
ret = regs[rb].nodeAddr == regs[rc].nodeAddr
|
||||
let rbReg = skipRegisterAddr(regs[rb])
|
||||
let rcReg = skipRegisterAddr(regs[rc])
|
||||
|
||||
if rbReg.kind == rkNodeAddr:
|
||||
if rcReg.kind == rkNodeAddr:
|
||||
ret = rbReg.nodeAddr == rcReg.nodeAddr
|
||||
else:
|
||||
ret = ptrEquality(regs[rb].nodeAddr, regs[rc].node)
|
||||
elif regs[rc].kind == rkNodeAddr:
|
||||
ret = ptrEquality(regs[rc].nodeAddr, regs[rb].node)
|
||||
ret = ptrEquality(rbReg.nodeAddr, rcReg.node)
|
||||
elif rcReg.kind == rkNodeAddr:
|
||||
ret = ptrEquality(rcReg.nodeAddr, rbReg.node)
|
||||
else:
|
||||
let nb = regs[rb].node
|
||||
let nc = regs[rc].node
|
||||
let nb = rbReg.node
|
||||
let nc = rcReg.node
|
||||
if nb.kind != nc.kind: discard
|
||||
elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional
|
||||
elif nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ != nil and nb.typ.kind == tyProc and sameConstant(nb, nc):
|
||||
@@ -1713,7 +1831,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[rb].node.kind != nkSym:
|
||||
stackTrace(c, tos, pc, "node is not a symbol")
|
||||
else:
|
||||
regs[ra].node.strVal = $sigHash(regs[rb].node.sym)
|
||||
regs[ra].node.strVal = $sigHash(regs[rb].node.sym, c.config)
|
||||
of opcSlurp:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
@@ -1791,14 +1909,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of 1: # getLine
|
||||
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
|
||||
of 2: # getColumn
|
||||
regs[ra].node = newIntNode(nkIntLit, n.info.col)
|
||||
regs[ra].node = newIntNode(nkIntLit, n.info.col.int)
|
||||
else:
|
||||
internalAssert c.config, false
|
||||
regs[ra].node.info = n.info
|
||||
regs[ra].node.typ = n.typ
|
||||
of opcNSetLineInfo:
|
||||
of opcNCopyLineInfo:
|
||||
decodeB(rkNode)
|
||||
regs[ra].node.info = regs[rb].node.info
|
||||
of opcNSetLineInfoLine:
|
||||
decodeB(rkNode)
|
||||
regs[ra].node.info.line = regs[rb].intVal.uint16
|
||||
of opcNSetLineInfoColumn:
|
||||
decodeB(rkNode)
|
||||
regs[ra].node.info.col = regs[rb].intVal.int16
|
||||
of opcNSetLineInfoFile:
|
||||
decodeB(rkNode)
|
||||
regs[ra].node.info.fileIndex =
|
||||
fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal)
|
||||
of opcEqIdent:
|
||||
decodeBC(rkInt)
|
||||
# aliases for shorter and easier to understand code below
|
||||
@@ -2203,6 +2331,9 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
|
||||
proc evalConstExprAux(module: PSym; idgen: IdGenerator;
|
||||
g: ModuleGraph; prc: PSym, n: PNode,
|
||||
mode: TEvalMode): PNode =
|
||||
when defined(nimsuggest):
|
||||
if g.config.expandDone():
|
||||
return n
|
||||
#if g.config.errorCounter > 0: return n
|
||||
let n = transformExpr(g, idgen, module, n)
|
||||
setupGlobalCtx(module, g, idgen)
|
||||
@@ -2264,7 +2395,6 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
else:
|
||||
var n = x
|
||||
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n[1]
|
||||
n = n.canonValue
|
||||
n.flags.incl nfIsRef
|
||||
n.typ = x.typ
|
||||
result = TFullReg(kind: rkNode, node: n)
|
||||
|
||||
@@ -81,6 +81,7 @@ type
|
||||
opcWrStrIdx,
|
||||
opcLdStrIdx, # a = b[c]
|
||||
opcLdStrIdxAddr, # a = addr(b[c])
|
||||
opcSlice, # toOpenArray(collection, left, right)
|
||||
|
||||
opcAddInt,
|
||||
opcAddImmInt,
|
||||
@@ -140,7 +141,8 @@ type
|
||||
opcNError,
|
||||
opcNWarning,
|
||||
opcNHint,
|
||||
opcNGetLineInfo, opcNSetLineInfo,
|
||||
opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine,
|
||||
opcNSetLineInfoColumn, opcNSetLineInfoFile
|
||||
opcEqIdent,
|
||||
opcStrToIdent,
|
||||
opcGetImpl,
|
||||
|
||||
@@ -441,14 +441,11 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
||||
c.gABC(n, opcAsgnInt, dest, tmp)
|
||||
freeTemp(c, tmp)
|
||||
|
||||
proc canonValue*(n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
proc rawGenLiteral(c: PCtx; n: PNode): int =
|
||||
result = c.constants.len
|
||||
#assert(n.kind != nkCall)
|
||||
n.flags.incl nfAllConst
|
||||
c.constants.add n.canonValue
|
||||
c.constants.add n
|
||||
internalAssert c.config, result < regBxMax
|
||||
|
||||
proc sameConstant*(a, b: PNode): bool =
|
||||
@@ -646,9 +643,19 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
|
||||
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
let dest = c.genx(le[0], {gfNode})
|
||||
let idx = c.genIndex(le[1], le[0].typ)
|
||||
c.gABC(le, opcWrArr, dest, idx, value)
|
||||
let
|
||||
dest = c.genx(le[0], {gfNode})
|
||||
idx = c.genIndex(le[1], le[0].typ)
|
||||
collTyp = le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
|
||||
|
||||
case collTyp.kind
|
||||
of tyString, tyCstring:
|
||||
c.gABC(le, opcWrStrIdx, dest, idx, value)
|
||||
of tyTuple:
|
||||
c.gABC(le, opcWrObj, dest, int le[1].intVal, value)
|
||||
else:
|
||||
c.gABC(le, opcWrArr, dest, idx, value)
|
||||
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(idx)
|
||||
of nkCheckedFieldExpr:
|
||||
@@ -749,18 +756,20 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
|
||||
c.gABC(n, opcNarrowS, dest, TRegister(size*8))
|
||||
|
||||
proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
||||
(t.kind in {tyUInt, tyInt} and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
(t.kind in {tyUInt, tyInt} and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
|
||||
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
genBinaryABC(c, n, dest, opc)
|
||||
@@ -1058,6 +1067,18 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of tyString: genUnaryABI(c, n, dest, opcLenStr)
|
||||
of tyCstring: genUnaryABI(c, n, dest, opcLenCstring)
|
||||
else: doAssert false, $n[1].typ.kind
|
||||
of mSlice:
|
||||
var
|
||||
d = c.genx(n[1])
|
||||
left = c.genIndex(n[2], n[1].typ)
|
||||
right = c.genIndex(n[3], n[1].typ)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opcNodeToReg, dest, d)
|
||||
c.gABC(n, opcSlice, dest, left, right)
|
||||
c.freeTemp(left)
|
||||
c.freeTemp(right)
|
||||
c.freeTemp(d)
|
||||
|
||||
of mIncl, mExcl:
|
||||
unused(c, n, dest)
|
||||
var d = c.genx(n[1])
|
||||
@@ -1088,10 +1109,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
genBinaryABC(c, n, dest, opcShlInt)
|
||||
# genNarrowU modified
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
|
||||
c.gABC(n, opcSignExtend, dest, TRegister(size*8))
|
||||
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
||||
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
||||
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
||||
@@ -1125,8 +1147,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
genUnaryABC(c, n, dest, opcBitnotInt)
|
||||
#genNarrowU modified, do not narrow signed types
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
genConv(c, n, n[1], dest)
|
||||
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
||||
@@ -1181,7 +1204,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
var d = c.genx(n[1])
|
||||
# XXX use ldNullOpcode() here?
|
||||
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
|
||||
c.gABx(n, opcNodeToReg, d, d)
|
||||
c.gABC(n, opcNodeToReg, d, d)
|
||||
c.genAsgnPatch(n[1], d)
|
||||
of mDefault:
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -1318,7 +1341,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of "copyLineInfo":
|
||||
internalAssert c.config, n.len == 3
|
||||
unused(c, n, dest)
|
||||
genBinaryStmt(c, n, opcNSetLineInfo)
|
||||
genBinaryStmt(c, n, opcNCopyLineInfo)
|
||||
of "setLine":
|
||||
internalAssert c.config, n.len == 3
|
||||
unused(c, n, dest)
|
||||
genBinaryStmt(c, n, opcNSetLineInfoLine)
|
||||
of "setColumn":
|
||||
internalAssert c.config, n.len == 3
|
||||
unused(c, n, dest)
|
||||
genBinaryStmt(c, n, opcNSetLineInfoColumn)
|
||||
of "setFile":
|
||||
internalAssert c.config, n.len == 3
|
||||
unused(c, n, dest)
|
||||
genBinaryStmt(c, n, opcNSetLineInfoFile)
|
||||
else: internalAssert c.config, false
|
||||
of mNHint:
|
||||
unused(c, n, dest)
|
||||
@@ -1399,9 +1434,6 @@ proc unneededIndirection(n: PNode): bool =
|
||||
n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef
|
||||
|
||||
proc canElimAddr(n: PNode): PNode =
|
||||
if n[0].typ.skipTypes(abstractInst).kind in {tyObject, tyTuple, tyArray}:
|
||||
# objects are reference types in the VM
|
||||
return n[0]
|
||||
case n[0].kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
var m = n[0][0]
|
||||
@@ -1493,7 +1525,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
# proc foo() = var x ...
|
||||
let s = n.sym
|
||||
if {sfCompileTime, sfGlobal} <= s.flags: return
|
||||
if s.importcCondVar: return
|
||||
if compiletimeFFI in c.config.features and s.importcCondVar: 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:
|
||||
# little hack ahead for bug #12612: assume gensym'ed variables
|
||||
@@ -1528,12 +1560,16 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
||||
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
let dest = c.genx(le[0], {gfNode})
|
||||
let idx = c.genIndex(le[1], le[0].typ)
|
||||
let tmp = c.genx(ri)
|
||||
if le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
|
||||
tyString, tyCstring}:
|
||||
let
|
||||
dest = c.genx(le[0], {gfNode})
|
||||
idx = c.genIndex(le[1], le[0].typ)
|
||||
tmp = c.genx(ri)
|
||||
collTyp = le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
|
||||
case collTyp.kind
|
||||
of tyString, tyCstring:
|
||||
c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
|
||||
of tyTuple:
|
||||
c.preventFalseAlias(le, opcWrObj, dest, int le[1].intVal, tmp)
|
||||
else:
|
||||
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
@@ -1697,9 +1733,7 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
c.freeTemp(a)
|
||||
c.freeTemp(b)
|
||||
|
||||
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
let a = c.genx(n[0], flags)
|
||||
let b = genField(c, n[1])
|
||||
proc genObjAccessAux(c: PCtx; n: PNode; a, b: int, dest: var TDest; flags: TGenFlags) =
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
if {gfNodeAddr} * flags != {}:
|
||||
c.gABC(n, opcLdObjAddr, dest, a, b)
|
||||
@@ -1712,6 +1746,11 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
c.gABC(n, opcLdObj, dest, a, b)
|
||||
c.freeTemp(a)
|
||||
|
||||
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
genObjAccessAux(c, n, c.genx(n[0], flags), genField(c, n[1]), dest, flags)
|
||||
|
||||
|
||||
|
||||
proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
internalAssert c.config, n.kind == nkCheckedFieldExpr
|
||||
# nkDotExpr to access the requested field
|
||||
@@ -1779,10 +1818,13 @@ 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[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||
if arrayType in {tyString, tyCstring}:
|
||||
case arrayType
|
||||
of tyString, tyCstring:
|
||||
let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx
|
||||
genArrAccessOpcode(c, n, dest, opc, flags)
|
||||
elif arrayType == tyTypeDesc:
|
||||
of tyTuple:
|
||||
c.genObjAccessAux(n, c.genx(n[0], flags), int n[1].intVal, dest, flags)
|
||||
of tyTypeDesc:
|
||||
c.genTypeLit(n.typ, dest)
|
||||
else:
|
||||
let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr
|
||||
@@ -1871,7 +1913,7 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||
else:
|
||||
let sa = getNullValue(s.typ, a.info, c.config)
|
||||
#if s.ast.isNil: getNullValue(s.typ, a.info)
|
||||
#else: canonValue(s.ast)
|
||||
#else: s.ast
|
||||
assert sa.kind != nkCall
|
||||
c.globals.add(sa)
|
||||
s.position = c.globals.len
|
||||
|
||||
@@ -92,7 +92,8 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
|
||||
if a[i].kind == nkRange:
|
||||
var x = copyNode(a[i][0])
|
||||
storeAny(s, t.lastSon, x, stored, conf)
|
||||
while x.intVal+1 <= a[i][1].intVal:
|
||||
inc x.intVal
|
||||
while x.intVal <= a[i][1].intVal:
|
||||
s.add(", ")
|
||||
storeAny(s, t.lastSon, x, stored, conf)
|
||||
inc x.intVal
|
||||
@@ -231,7 +232,6 @@ proc loadAny(p: var JsonParser, t: PType,
|
||||
result = newNode(nkCurly)
|
||||
while p.kind != jsonArrayEnd and p.kind != jsonEof:
|
||||
result.add loadAny(p, t.lastSon, tab, cache, conf, idgen)
|
||||
next(p)
|
||||
if p.kind == jsonArrayEnd: next(p)
|
||||
else: raiseParseErr(p, "']' end of array expected")
|
||||
of tyPtr, tyRef:
|
||||
|
||||
@@ -56,13 +56,13 @@ template macrosop(op) {.dirty.} =
|
||||
template md5op(op) {.dirty.} =
|
||||
registerCallback(c, "stdlib.md5." & astToStr(op), `op Wrapper`)
|
||||
|
||||
template wrap1f_math(op) {.dirty.} =
|
||||
template wrap1fMath(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
doAssert a.numArgs == 1
|
||||
setResult(a, op(getFloat(a, 0)))
|
||||
mathop op
|
||||
|
||||
template wrap2f_math(op) {.dirty.} =
|
||||
template wrap2fMath(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
|
||||
mathop op
|
||||
@@ -170,40 +170,40 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
proc getProjectPathWrapper(a: VmArgs) =
|
||||
setResult a, c.config.projectPath.string
|
||||
|
||||
wrap1f_math(sqrt)
|
||||
wrap1f_math(cbrt)
|
||||
wrap1f_math(ln)
|
||||
wrap1f_math(log10)
|
||||
wrap1f_math(log2)
|
||||
wrap1f_math(exp)
|
||||
wrap1f_math(arccos)
|
||||
wrap1f_math(arcsin)
|
||||
wrap1f_math(arctan)
|
||||
wrap1f_math(arcsinh)
|
||||
wrap1f_math(arccosh)
|
||||
wrap1f_math(arctanh)
|
||||
wrap2f_math(arctan2)
|
||||
wrap1f_math(cos)
|
||||
wrap1f_math(cosh)
|
||||
wrap2f_math(hypot)
|
||||
wrap1f_math(sinh)
|
||||
wrap1f_math(sin)
|
||||
wrap1f_math(tan)
|
||||
wrap1f_math(tanh)
|
||||
wrap2f_math(pow)
|
||||
wrap1f_math(trunc)
|
||||
wrap1f_math(floor)
|
||||
wrap1f_math(ceil)
|
||||
wrap1f_math(erf)
|
||||
wrap1f_math(erfc)
|
||||
wrap1f_math(gamma)
|
||||
wrap1f_math(lgamma)
|
||||
wrap1fMath(sqrt)
|
||||
wrap1fMath(cbrt)
|
||||
wrap1fMath(ln)
|
||||
wrap1fMath(log10)
|
||||
wrap1fMath(log2)
|
||||
wrap1fMath(exp)
|
||||
wrap1fMath(arccos)
|
||||
wrap1fMath(arcsin)
|
||||
wrap1fMath(arctan)
|
||||
wrap1fMath(arcsinh)
|
||||
wrap1fMath(arccosh)
|
||||
wrap1fMath(arctanh)
|
||||
wrap2fMath(arctan2)
|
||||
wrap1fMath(cos)
|
||||
wrap1fMath(cosh)
|
||||
wrap2fMath(hypot)
|
||||
wrap1fMath(sinh)
|
||||
wrap1fMath(sin)
|
||||
wrap1fMath(tan)
|
||||
wrap1fMath(tanh)
|
||||
wrap2fMath(pow)
|
||||
wrap1fMath(trunc)
|
||||
wrap1fMath(floor)
|
||||
wrap1fMath(ceil)
|
||||
wrap1fMath(erf)
|
||||
wrap1fMath(erfc)
|
||||
wrap1fMath(gamma)
|
||||
wrap1fMath(lgamma)
|
||||
|
||||
when declared(copySign):
|
||||
wrap2f_math(copySign)
|
||||
wrap2fMath(copySign)
|
||||
|
||||
when declared(signbit):
|
||||
wrap1f_math(signbit)
|
||||
wrap1fMath(signbit)
|
||||
|
||||
registerCallback c, "stdlib.math.round", proc (a: VmArgs) {.nimcall.} =
|
||||
let n = a.numArgs
|
||||
|
||||
@@ -41,7 +41,7 @@ type
|
||||
wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor",
|
||||
wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp",
|
||||
wCppNonPod = "cppNonPod",
|
||||
wImportObjC = "importobjc", wImportCompilerProc = "importcompilerproc",
|
||||
wImportObjC = "importobjc", wImportCompilerProc = "importCompilerProc",
|
||||
wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp",
|
||||
wExportNims = "exportnims",
|
||||
wIncompleteStruct = "incompleteStruct", # deprecated
|
||||
@@ -86,26 +86,26 @@ type
|
||||
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
|
||||
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
||||
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
||||
wLiftLocals = "liftlocals",
|
||||
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
||||
|
||||
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
||||
wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default",
|
||||
wDelete = "delete", wDouble = "double", wDynamic_cast = "dynamic_cast",
|
||||
wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default",
|
||||
wDelete = "delete", wDouble = "double", wDynamicCast = "dynamic_cast",
|
||||
wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float",
|
||||
wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable",
|
||||
wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private",
|
||||
wProtected = "protected", wPublic = "public", wRegister = "register",
|
||||
wReinterpret_cast = "reinterpret_cast", wRestrict = "restrict", wShort = "short",
|
||||
wSigned = "signed", wSizeof = "sizeof", wStatic_cast = "static_cast", wStruct = "struct",
|
||||
wReinterpretCast = "reinterpret_cast", wRestrict = "restrict", wShort = "short",
|
||||
wSigned = "signed", wSizeof = "sizeof", wStaticCast = "static_cast", wStruct = "struct",
|
||||
wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef",
|
||||
wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename",
|
||||
wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual",
|
||||
wVoid = "void", wVolatile = "volatile", wWchar_t = "wchar_t",
|
||||
wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t",
|
||||
|
||||
wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype",
|
||||
wNullptr = "nullptr", wNoexcept = "noexcept",
|
||||
wThread_local = "thread_local", wStatic_assert = "static_assert",
|
||||
wChar16_t = "char16_t", wChar32_t = "char32_t",
|
||||
wThreadLocal = "thread_local", wStaticAssert = "static_assert",
|
||||
wChar16 = "char16_t", wChar32 = "char32_t",
|
||||
|
||||
wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr",
|
||||
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
cppDefine "errno"
|
||||
cppDefine "unix"
|
||||
|
||||
# mangle the macro names in nimbase.h
|
||||
cppDefine "NAN_INFINITY"
|
||||
cppDefine "INF"
|
||||
cppDefine "NAN"
|
||||
|
||||
when defined(nimStrictMode):
|
||||
# xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI.
|
||||
|
||||
|
||||
@@ -44,10 +44,12 @@ path="$lib/core"
|
||||
path="$lib/pure"
|
||||
|
||||
@if not windows:
|
||||
nimblepath="/opt/nimble/pkgs2/"
|
||||
nimblepath="/opt/nimble/pkgs/"
|
||||
@else:
|
||||
# TODO:
|
||||
@end
|
||||
nimblepath="$home/.nimble/pkgs2/"
|
||||
nimblepath="$home/.nimble/pkgs/"
|
||||
|
||||
# Syncronize with compiler/commands.specialDefine
|
||||
|
||||
@@ -55,6 +55,11 @@ doc.file = """
|
||||
%
|
||||
% Compile it by: xelatex (up to 3 times to get labels generated)
|
||||
% -------
|
||||
% For example:
|
||||
% xelatex file.tex
|
||||
% xelatex file.tex
|
||||
% makeindex file
|
||||
% xelatex file.tex
|
||||
%
|
||||
\documentclass[a4paper,11pt]{article}
|
||||
\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry}
|
||||
@@ -97,7 +102,9 @@ doc.file = """
|
||||
\usepackage{parskip} % paragraphs delimited by vertical space, no indent
|
||||
\usepackage{graphicx}
|
||||
|
||||
\newcommand{\nimindexterm}[2]{#2\label{#1}}
|
||||
\usepackage{makeidx}
|
||||
\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}}
|
||||
\makeindex
|
||||
|
||||
\usepackage{dingbat} % for \carriagereturn, etc
|
||||
\usepackage{fvextra} % for code blocks (works better than original fancyvrb)
|
||||
@@ -241,5 +248,8 @@ doc.file = """
|
||||
\maketitle
|
||||
|
||||
$content
|
||||
|
||||
\printindex
|
||||
|
||||
\end{document}
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
=====================================================
|
||||
Nim -- a Compiler for Nim. https://nim-lang.org/
|
||||
|
||||
Copyright (C) 2006-2021 Andreas Rumpf. All rights reserved.
|
||||
Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -57,7 +57,8 @@ Advanced options:
|
||||
-w:on|off|list, --warnings:on|off|list
|
||||
same as `--hints` but for warnings.
|
||||
--warning:X:on|off ditto
|
||||
--warningAsError:X:on|off ditto
|
||||
--warningAsError:X:on|off
|
||||
ditto
|
||||
--styleCheck:off|hint|error
|
||||
produce hints or errors for Nim identifiers that
|
||||
do not adhere to Nim's official style guide
|
||||
@@ -122,8 +123,9 @@ Advanced options:
|
||||
--skipUserCfg:on|off do not read the user's configuration file
|
||||
--skipParentCfg:on|off do not read the parent dirs' configuration files
|
||||
--skipProjCfg:on|off do not read the project's configuration file
|
||||
--gc:refc|arc|orc|markAndSweep|boehm|go|none|regions
|
||||
select the GC to use; default is 'refc'
|
||||
--mm:orc|arc|refc|markAndSweep|boehm|go|none|regions
|
||||
select which memory management to use; default is 'refc'
|
||||
recommended is 'orc'
|
||||
--exceptions:setjmp|cpp|goto|quirky
|
||||
select the exception handling implementation
|
||||
--index:on|off turn index file generation on|off
|
||||
@@ -134,6 +136,8 @@ Advanced options:
|
||||
--cppCompileToNamespace:namespace
|
||||
use the provided namespace for the generated C++ code,
|
||||
if no namespace is provided "Nim" will be used
|
||||
--nimMainPrefix:prefix use `{prefix}NimMain` instead of `NimMain` in the produced
|
||||
C/C++ code
|
||||
--expandMacro:MACRO dump every generated AST from MACRO
|
||||
--expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations
|
||||
before the final backend phase (mostly ARC/ORC specific)
|
||||
@@ -163,4 +167,4 @@ Advanced options:
|
||||
--profileVM:on|off turn compile time VM profiler on|off
|
||||
--sinkInference:on|off turn sink parameter inference on|off (default: on)
|
||||
--panics:on|off turn panics into process terminations (default: off)
|
||||
--deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc``
|
||||
--deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc``
|
||||
|
||||
@@ -52,7 +52,7 @@ The commands to compile to either C, C++ or Objective-C are:
|
||||
The most significant difference between these commands is that if you look
|
||||
into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
|
||||
files, other than that all of them will produce a native binary for your
|
||||
project. This allows you to take the generated code and place it directly
|
||||
project. This allows you to take the generated code and place it directly
|
||||
into a project using any of these languages. Here are some typical command-
|
||||
line invocations:
|
||||
|
||||
@@ -105,7 +105,7 @@ file. However, you can also run the code with `nodejs`:idx:
|
||||
If you experience errors saying that `globalThis` is not defined, be
|
||||
sure to run a recent version of Node.js (at least 12.0).
|
||||
|
||||
|
||||
|
||||
Interfacing
|
||||
===========
|
||||
|
||||
@@ -123,7 +123,7 @@ Nim code can interface with the backend through the `Foreign function
|
||||
interface <manual.html#foreign-function-interface>`_ mainly through the
|
||||
`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++
|
||||
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>`_
|
||||
@@ -246,10 +246,8 @@ Also, C code requires you to specify a forward declaration for functions or
|
||||
the compiler will assume certain types for the return value and parameters
|
||||
which will likely make your program crash at runtime.
|
||||
|
||||
The Nim compiler can generate a C interface header through the `--header`:option:
|
||||
command-line switch. The generated header will contain all the exported
|
||||
symbols and the `NimMain` proc which you need to call before any other
|
||||
Nim code.
|
||||
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||
|
||||
|
||||
Nim invocation example from C
|
||||
@@ -269,9 +267,10 @@ Create a ``maths.c`` file with the following content:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "fib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern int fib(int a);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
NimMain();
|
||||
@@ -286,13 +285,12 @@ program:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
nim c --noMain --noLinking --header:fib.h fib.nim
|
||||
nim c --noMain --noLinking fib.nim
|
||||
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
||||
|
||||
The first command runs the Nim compiler with three special options to avoid
|
||||
generating a `main()`:c: function in the generated files, avoid linking the
|
||||
object files into a final binary, and explicitly generate a header file for C
|
||||
integration. All the generated files are placed into the ``nimcache``
|
||||
generating a `main()`:c: function in the generated files and to avoid linking the
|
||||
object files into a final binary. All the generated files are placed into the ``nimcache``
|
||||
directory. That's why the next command compiles the ``maths.c`` source plus
|
||||
all the ``.c`` files from ``nimcache``. In addition to this path, you also
|
||||
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||
@@ -302,12 +300,12 @@ also ask the Nim compiler to generate a statically linked library:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
nim c --app:staticLib --noMain --header fib.nim
|
||||
nim c --app:staticLib --noMain fib.nim
|
||||
gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
|
||||
|
||||
The Nim compiler will handle linking the source files generated in the
|
||||
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
|
||||
then link into your C program. Note that these commands are generic and will
|
||||
then link into your C program. Note that these commands are generic and will
|
||||
vary for each system. For instance, on Linux systems you will likely need to
|
||||
use `-ldl`:option: too to link in required dlopen functionality.
|
||||
|
||||
@@ -387,14 +385,8 @@ A similar thing happens with C code invoking Nim code which returns a
|
||||
proc gimme(): cstring {.exportc.} =
|
||||
result = "Hey there C code! " & $rand(100)
|
||||
|
||||
Since Nim's garbage collector is not aware of the C code, once the
|
||||
Since Nim's reference counting mechanism is not aware of the C code, once the
|
||||
`gimme` proc has finished it can reclaim the memory of the `cstring`.
|
||||
However, from a practical standpoint, the C code invoking the `gimme`
|
||||
function directly will be able to use it since Nim's garbage collector has
|
||||
not had a chance to run *yet*. This gives you enough time to make a copy for
|
||||
the C side of the program, as calling any further Nim procs *might* trigger
|
||||
garbage collection making the previously returned string garbage. Or maybe you
|
||||
are `yourself triggering the collection <gc.html>`_.
|
||||
|
||||
|
||||
Custom data types
|
||||
@@ -414,31 +406,3 @@ you can clean it up. And of course, once cleaned you should avoid accessing it
|
||||
from Nim (or C for that matter). Typically C data structures have their own
|
||||
`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping
|
||||
these for the Nim side should be enough.
|
||||
|
||||
|
||||
Thread coordination
|
||||
-------------------
|
||||
|
||||
When the `NimMain()` function is called Nim initializes the garbage
|
||||
collector to the current thread, which is usually the main thread of your
|
||||
application. If your C code later spawns a different thread and calls Nim
|
||||
code, the garbage collector will fail to work properly and you will crash.
|
||||
|
||||
As long as you don't use the threadvar emulation Nim uses native thread
|
||||
variables, of which you get a fresh version whenever you create a thread. You
|
||||
can then attach a GC to this thread via
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
system.setupForeignThreadGc()
|
||||
|
||||
It is **not** safe to disable the garbage collector and enable it after the
|
||||
call from your background thread even if the code you are calling is short
|
||||
lived.
|
||||
|
||||
Before the thread exits, you should tear down the thread's GC to prevent memory
|
||||
leaks by calling
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
system.tearDownForeignThreadGc()
|
||||
|
||||
@@ -27,11 +27,11 @@ Options:
|
||||
-a, --assertions:on|off turn assertions on|off
|
||||
--opt:none|speed|size optimize not at all or for speed|size
|
||||
Note: use -d:release for a release build!
|
||||
--debugger:native Use native debugger (gdb)
|
||||
--debugger:native use native debugger (gdb)
|
||||
--app:console|gui|lib|staticlib
|
||||
generate a console app|GUI app|DLL|static library
|
||||
-r, --run run the compiled program with given arguments
|
||||
--eval:cmd evaluates nim code directly; e.g.: `nim --eval:"echo 1"`
|
||||
--eval:cmd evaluate nim code directly; e.g.: `nim --eval:"echo 1"`
|
||||
defaults to `e` (nimscript) but customizable:
|
||||
`nim r --eval:'for a in stdin.lines: echo a'`
|
||||
--fullhelp show all command line switches
|
||||
|
||||
@@ -43,7 +43,7 @@ written as:
|
||||
dealloc(x.data)
|
||||
|
||||
proc `=trace`[T](x: var myseq[T]; env: pointer) =
|
||||
# `=trace` allows the cycle collector `--gc:orc`
|
||||
# `=trace` allows the cycle collector `--mm:orc`
|
||||
# to understand how to trace the object graph.
|
||||
if x.data != nil:
|
||||
for i in 0..<x.len: `=trace`(x.data[i], env)
|
||||
@@ -208,7 +208,7 @@ by the compiler. Notice that there is no `=` before the `{.error.}` pragma.
|
||||
`=trace` hook
|
||||
-------------
|
||||
|
||||
A custom **container** type can support Nim's cycle collector `--gc:orc` via
|
||||
A custom **container** type can support Nim's cycle collector `--mm:orc` via
|
||||
the `=trace` hook. If the container does not implement `=trace`, cyclic data
|
||||
structures which are constructed with the help of the container might leak
|
||||
memory or resources, but memory safety is not compromised.
|
||||
@@ -224,7 +224,7 @@ to calls of the built-in `=trace` operation.
|
||||
|
||||
Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates
|
||||
manually allocated resources is also used, and then only when there is a chance of cyclic
|
||||
references from items within the manually allocated resources when it is desired that `--gc:orc`
|
||||
references from items within the manually allocated resources when it is desired that `--mm:orc`
|
||||
is able to break and collect these cyclic referenced resources. Currently however, there is a
|
||||
mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically
|
||||
create a version of the other which will then conflict with the creation of the second of the
|
||||
@@ -256,7 +256,7 @@ The general pattern in using `=destroy` with `=trace` looks like:
|
||||
|
||||
# following may be other custom "hooks" as required...
|
||||
|
||||
**Note**: The `=trace` hooks (which are only used by `--gc:orc`) are currently more experimental and less refined
|
||||
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
|
||||
than the other hooks.
|
||||
|
||||
|
||||
@@ -558,10 +558,10 @@ for expressions of type `lent T` or of type `var T`.
|
||||
The .cursor annotation
|
||||
======================
|
||||
|
||||
Under the `--gc:arc|orc`:option: modes Nim's `ref` type is implemented
|
||||
Under the `--mm:arc|orc`:option: modes Nim's `ref` type is implemented
|
||||
via the same runtime "hooks" and thus via reference counting.
|
||||
This means that cyclic structures cannot be freed
|
||||
immediately (`--gc:orc`:option: ships with a cycle collector).
|
||||
immediately (`--mm:orc`:option: ships with a cycle collector).
|
||||
With the `.cursor` annotation one can break up cycles declaratively:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
@@ -22,8 +22,8 @@ The documentation consists of several documents:
|
||||
- | `Tools documentation <tools.html>`_
|
||||
| Description of some tools that come with the standard distribution.
|
||||
|
||||
- | `GC <gc.html>`_
|
||||
| Additional documentation about Nim's multi-paradigm memory management strategies
|
||||
- | `Memory management <mm.html>`_
|
||||
| Additional documentation about Nim's memory management strategies
|
||||
| and how to operate them in a realtime setting.
|
||||
|
||||
- | `Source code filters <filters.html>`_
|
||||
|
||||
@@ -37,10 +37,10 @@ parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
|
||||
| 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
| 'when' | 'var' | 'mixin'
|
||||
par = '(' optInd
|
||||
( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
| ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
| ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
| pragmaStmt
|
||||
| simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||
| simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
| (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
optPar ')'
|
||||
literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
|
||||
@@ -1616,7 +1616,7 @@ type conversions in this context:
|
||||
|
||||
myWriteln(stdout, 123, "abc", 4.0)
|
||||
# is transformed to:
|
||||
myWriteln(stdout, [$123, $"def", $4.0])
|
||||
myWriteln(stdout, [$123, $"abc", $4.0])
|
||||
|
||||
In this example `$` is applied to any argument that is passed to the
|
||||
parameter `a`. (Note that `$` applied to strings is a nop.)
|
||||
@@ -1899,7 +1899,7 @@ A small example:
|
||||
cast uncheckedAssign
|
||||
--------------------
|
||||
|
||||
Some restrictions for case objects can be disabled via a `{.cast(unsafeAssign).}` section:
|
||||
Some restrictions for case objects can be disabled via a `{.cast(uncheckedAssign).}` section:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -4506,8 +4506,8 @@ Example:
|
||||
echo "overflow!"
|
||||
except ValueError, IOError:
|
||||
echo "catch multiple exceptions!"
|
||||
except:
|
||||
echo "Unknown exception!"
|
||||
except CatchableError:
|
||||
echo "Catchable exception!"
|
||||
finally:
|
||||
close(f)
|
||||
|
||||
@@ -4518,9 +4518,6 @@ listed in an `except` clause, the corresponding statements are executed.
|
||||
The statements following the `except` clauses are called
|
||||
`exception handlers`:idx:.
|
||||
|
||||
The empty `except`:idx: clause is executed if there is an exception that is
|
||||
not listed otherwise. It is similar to an `else` clause in `if` statements.
|
||||
|
||||
If there is a `finally`:idx: clause, it is always executed after the
|
||||
exception handlers.
|
||||
|
||||
@@ -4542,7 +4539,7 @@ branch always has to be `void`:
|
||||
from std/strutils import parseInt
|
||||
|
||||
let x = try: parseInt("133a")
|
||||
except: -1
|
||||
except ValueError: -1
|
||||
finally: echo "hi"
|
||||
|
||||
|
||||
@@ -4550,7 +4547,8 @@ To prevent confusing code there is a parsing limitation; if the `try`
|
||||
follows a `(` it has to be written as a one liner:
|
||||
|
||||
.. code-block:: nim
|
||||
let x = (try: parseInt("133a") except: -1)
|
||||
from std/strutils import parseInt
|
||||
let x = (try: parseInt("133a") except ValueError: -1)
|
||||
|
||||
|
||||
Except clauses
|
||||
@@ -4594,7 +4592,7 @@ error message from `e`, and for such situations, it is enough to use
|
||||
.. code-block:: nim
|
||||
try:
|
||||
# ...
|
||||
except:
|
||||
except CatchableError:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
Custom exceptions
|
||||
@@ -4784,7 +4782,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised:
|
||||
try:
|
||||
unsafeCall()
|
||||
result = true
|
||||
except:
|
||||
except CatchableError:
|
||||
result = false
|
||||
|
||||
|
||||
@@ -5002,7 +5000,7 @@ be used:
|
||||
|
||||
See also:
|
||||
|
||||
- `Shared heap memory management <gc.html>`_.
|
||||
- `Shared heap memory management <mm.html>`_.
|
||||
|
||||
|
||||
|
||||
@@ -6488,6 +6486,19 @@ iterator in which case the overloading resolution takes place:
|
||||
write(stdout, x) # not ambiguous: uses the module C's x
|
||||
|
||||
|
||||
Packages
|
||||
--------
|
||||
A collection of modules in a file tree with an ``identifier.nimble`` file in the
|
||||
root of the tree is called a Nimble package. A valid package name can only be a
|
||||
valid Nim identifier and thus its filename is ``identifier.nimble`` where
|
||||
``identifier`` is the desired package name. A module without a ``.nimble`` file
|
||||
is assigned the package identifier: `unknown`.
|
||||
|
||||
The distinction between packages allows diagnostic compiler messages to be
|
||||
scoped to the current project's package vs foreign packages.
|
||||
|
||||
|
||||
|
||||
Compiler Messages
|
||||
=================
|
||||
|
||||
@@ -6699,11 +6710,11 @@ statement, as seen in stack backtraces:
|
||||
if not cond:
|
||||
# change run-time line information of the 'raise' statement:
|
||||
{.line: instantiationInfo().}:
|
||||
raise newException(EAssertionFailed, msg)
|
||||
raise newException(AssertionDefect, msg)
|
||||
|
||||
If the `line` pragma is used with a parameter, the parameter needs be a
|
||||
`tuple[filename: string, line: int]`. If it is used without a parameter,
|
||||
`system.InstantiationInfo()` is used.
|
||||
`system.instantiationInfo()` is used.
|
||||
|
||||
|
||||
linearScanEnd pragma
|
||||
@@ -7123,7 +7134,7 @@ The `link` pragma can be used to link an additional file with the project:
|
||||
{.link: "myfile.o".}
|
||||
|
||||
|
||||
PassC pragma
|
||||
passc pragma
|
||||
------------
|
||||
The `passc` pragma can be used to pass additional parameters to the C
|
||||
compiler like one would using the command-line switch `--passc`:option:\:
|
||||
@@ -7151,20 +7162,20 @@ the pragma resides in:
|
||||
{.localPassc: "-Wall -Werror".} # Passed when compiling A.nim.cpp
|
||||
|
||||
|
||||
PassL pragma
|
||||
passl pragma
|
||||
------------
|
||||
The `passL` pragma can be used to pass additional parameters to the linker
|
||||
like one would be using the command-line switch `--passL`:option:\:
|
||||
The `passl` pragma can be used to pass additional parameters to the linker
|
||||
like one would be using the command-line switch `--passl`:option:\:
|
||||
|
||||
.. code-block:: Nim
|
||||
{.passL: "-lSDLmain -lSDL".}
|
||||
{.passl: "-lSDLmain -lSDL".}
|
||||
|
||||
Note that one can use `gorge` from the `system module <system.html>`_ to
|
||||
embed parameters from an external command that will be executed
|
||||
during semantic analysis:
|
||||
|
||||
.. code-block:: Nim
|
||||
{.passL: gorge("pkg-config --libs sdl").}
|
||||
{.passl: gorge("pkg-config --libs sdl").}
|
||||
|
||||
|
||||
Emit pragma
|
||||
@@ -7478,7 +7489,7 @@ allows *sloppy* interfacing with libraries written in Objective C:
|
||||
.. code-block:: Nim
|
||||
# horrible example of how to interface with GNUStep ...
|
||||
|
||||
{.passL: "-lobjc".}
|
||||
{.passl: "-lobjc".}
|
||||
{.emit: """
|
||||
#include <objc/Object.h>
|
||||
@interface Greeter:Object
|
||||
|
||||
95
doc/mm.rst
Normal file
95
doc/mm.rst
Normal file
@@ -0,0 +1,95 @@
|
||||
=======================
|
||||
Nim's Memory Management
|
||||
=======================
|
||||
|
||||
.. default-role:: code
|
||||
.. include:: rstcommon.rst
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimversion|
|
||||
|
||||
..
|
||||
|
||||
|
||||
"The road to hell is paved with good intentions."
|
||||
|
||||
|
||||
Multi-paradigm Memory Management Strategies
|
||||
===========================================
|
||||
|
||||
.. default-role:: option
|
||||
|
||||
Nim offers multiple different memory management strategies.
|
||||
To choose the memory management strategy use the `--mm:` switch.
|
||||
|
||||
**The recommended switch for newly written Nim code is `--mm:orc`.**
|
||||
|
||||
|
||||
ARC/ORC
|
||||
-------
|
||||
|
||||
`--mm:orc` is a memory management mode primarily based on reference counting. Cycles
|
||||
in the object graph are handled by a "cycle collector" which is based on "trial deletion".
|
||||
Since algorithms based on "tracing" are not used, the runtime behavior is oblivious to
|
||||
the involved heap sizes.
|
||||
|
||||
The reference counting operations (= "RC ops") do not use atomic instructions and do not have to --
|
||||
instead entire subgraphs are *moved* between threads. The Nim compiler also aggressively
|
||||
optimizes away RC ops and exploits `move semantics <destructors.html#move-semantics>`_.
|
||||
|
||||
Nim performs a fair share of optimizations for ARC/ORC; you can inspect what it did
|
||||
to your time critical function via `--expandArc:functionName`.
|
||||
|
||||
`--mm:arc` uses the same mechanism as `--mm:orc`, but it leaves out the cycle collector.
|
||||
Both ARC and ORC offer deterministic performance for `hard realtime`:idx: systems, but
|
||||
ARC can be easier to reason about for people coming from Ada/C++/C -- roughly speaking
|
||||
the memory for a variable is freed when it goes "out of scope".
|
||||
|
||||
We generally advise you to use the `acyclic` annotation in order to optimize away the
|
||||
cycle collector's overhead
|
||||
but `--mm:orc` also produces more machine code than `--mm:arc`, so if you're on a target
|
||||
where code size matters and you know that your code does not produce cycles, you can
|
||||
use `--mm:arc`. Notice that the default `async`:idx: implementation produces cycles
|
||||
and leaks memory with `--mm:arc`, in other words, for `async` you need to use `--mm:orc`.
|
||||
|
||||
|
||||
|
||||
Other MM modes
|
||||
--------------
|
||||
|
||||
.. note:: The default `refc` GC is incremental, thread-local and not "stop-the-world".
|
||||
|
||||
--mm:refc This is the default memory management strategy. It's a
|
||||
deferred reference counting based garbage collector
|
||||
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
|
||||
`This document <refc.html>`_ contains further information.
|
||||
--mm:markAndSweep Simple Mark-And-Sweep based garbage collector.
|
||||
Heaps are thread-local.
|
||||
--mm:boehm Boehm based garbage collector, it offers a shared heap.
|
||||
--mm:go Go's garbage collector, useful for interoperability with Go.
|
||||
Offers a shared heap.
|
||||
|
||||
--mm:none No memory management strategy nor a garbage collector. Allocated memory is
|
||||
simply never freed. You should use `--mm:arc` instead.
|
||||
|
||||
Here is a comparison of the different memory management modes:
|
||||
|
||||
================== ======== ================= ============== ===================
|
||||
Memory Management Heap Reference Cycles Stop-The-World Command line switch
|
||||
================== ======== ================= ============== ===================
|
||||
ORC Shared Cycle Collector No `--mm:orc`
|
||||
ARC Shared Leak No `--mm:arc`
|
||||
RefC Local Cycle Collector No `--mm:refc`
|
||||
Mark & Sweep Local Cycle Collector No `--mm:markAndSweep`
|
||||
Boehm Shared Cycle Collector Yes `--mm:boehm`
|
||||
Go Shared Cycle Collector Yes `--mm:go`
|
||||
None Manual Manual Manual `--mm:none`
|
||||
================== ======== ================= ============== ===================
|
||||
|
||||
.. default-role:: code
|
||||
.. include:: rstcommon.rst
|
||||
|
||||
JavaScript's garbage collector is used for the `JavaScript and NodeJS
|
||||
<backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||
The `NimScript <nims.html>`_ target uses the memory management strategy built into
|
||||
the Nim compiler.
|
||||
74
doc/nimc.rst
74
doc/nimc.rst
@@ -165,6 +165,22 @@ ignored too. `--define:FOO`:option: and `--define:foo`:option: are identical.
|
||||
Compile-time symbols starting with the `nim` prefix are reserved for the
|
||||
implementation and should not be used elsewhere.
|
||||
|
||||
========================== ============================================
|
||||
Name Description
|
||||
========================== ============================================
|
||||
nimStdSetjmp Use the standard `setjmp()/longjmp()` library
|
||||
functions for setjmp-based exceptions. This is
|
||||
the default on most platforms.
|
||||
nimSigSetjmp Use `sigsetjmp()/siglongjmp()` for setjmp-based exceptions.
|
||||
nimRawSetjmp Use `_setjmp()/_longjmp()` on POSIX and `_setjmp()/longjmp()`
|
||||
on Windows, for setjmp-based exceptions. It's the default on
|
||||
BSDs and BSD-like platforms, where it's significantly faster
|
||||
than the standard functions.
|
||||
nimBuiltinSetjmp Use `__builtin_setjmp()/__builtin_longjmp()` for setjmp-based
|
||||
exceptions. This will not work if an exception is being thrown
|
||||
and caught inside the same procedure. Useful for benchmarking.
|
||||
========================== ============================================
|
||||
|
||||
|
||||
Configuration files
|
||||
-------------------
|
||||
@@ -371,6 +387,10 @@ of your program.
|
||||
NimMain() # initialize garbage collector memory, types and stack
|
||||
|
||||
|
||||
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||
|
||||
|
||||
Cross-compilation for iOS
|
||||
=========================
|
||||
|
||||
@@ -399,6 +419,9 @@ of your program.
|
||||
Note: XCode's "make clean" gets confused about the generated nim.c files,
|
||||
so you need to clean those files manually to do a clean build.
|
||||
|
||||
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||
|
||||
|
||||
Cross-compilation for Nintendo Switch
|
||||
=====================================
|
||||
@@ -408,13 +431,13 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option:
|
||||
and `passL`:option: command line switches to something like:
|
||||
|
||||
.. code-block:: cmd
|
||||
nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
||||
nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||
|
||||
or setup a ``nim.cfg`` file like so::
|
||||
|
||||
#nim.cfg
|
||||
--gc:orc
|
||||
--mm:orc
|
||||
--d:nimAllocPagesViaMalloc
|
||||
--passC="-I$DEVKITPRO/libnx/include"
|
||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||
@@ -485,10 +508,10 @@ Define Effect
|
||||
`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's
|
||||
own memory manager, albeit prefixing each allocation with
|
||||
its size to support clearing memory on reallocation.
|
||||
This only works with `--gc:none`:option:,
|
||||
`--gc:arc`:option: and `--gc:orc`:option:.
|
||||
This only works with `--mm:none`:option:,
|
||||
`--mm:arc`:option: and `--mm:orc`:option:.
|
||||
`useRealtimeGC` Enables support of Nim's GC for *soft* realtime
|
||||
systems. See the documentation of the `gc <gc.html>`_
|
||||
systems. See the documentation of the `mm <mm.html>`_
|
||||
for further information.
|
||||
`logGC` Enable GC logging to stdout.
|
||||
`nodejs` The JS target is actually ``node.js``.
|
||||
@@ -614,9 +637,9 @@ A good start is to use the `any` operating target together with the
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
nim c --os:any --gc:arc -d:useMalloc [...] x.nim
|
||||
nim c --os:any --mm:arc -d:useMalloc [...] x.nim
|
||||
|
||||
- `--gc:arc`:option: will enable the reference counting memory management instead
|
||||
- `--mm:arc`:option: will enable the reference counting memory management instead
|
||||
of the default garbage collector. This enables Nim to use heap memory which
|
||||
is required for strings and seqs, for example.
|
||||
|
||||
@@ -654,13 +677,46 @@ devices. This allocator gets blocks/pages of memory via a currently undocumented
|
||||
`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap`
|
||||
is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
|
||||
define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently
|
||||
only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6)
|
||||
only supported with `--mm:arc` or `--mm:orc`. (Since version 1.6)
|
||||
|
||||
nimPage256 / nimPage512 / nimPage1k
|
||||
===================================
|
||||
|
||||
Adjust the page size for Nim's GC allocator. This enables using
|
||||
`nimAllocPagesViaMalloc` on devices with less RAM. The default
|
||||
page size requires too much RAM to work.
|
||||
|
||||
Recommended settings:
|
||||
|
||||
- < 32 kB of RAM use `nimPage256`
|
||||
|
||||
- < 512 kB of RAM use `nimPage512`
|
||||
|
||||
- < 2 MB of RAM use `nimPage1k`
|
||||
|
||||
Initial testing hasn't shown much difference between 512B or 1kB page sizes
|
||||
in terms of performance or latency. Using `nimPages256` will limit the
|
||||
total amount of allocatable RAM.
|
||||
|
||||
nimMemAlignTiny
|
||||
===============
|
||||
|
||||
Sets `MemAlign` to `4` bytes which reduces the memory alignment
|
||||
to better match some embedded devices.
|
||||
|
||||
Thread stack size
|
||||
=================
|
||||
|
||||
Nim's thread API provides a simple wrapper around more advanced
|
||||
RTOS task features. Customizing the stack size and stack guard size can
|
||||
be done by setting `-d:nimThreadStackSize=16384` or `-d:nimThreadStackGuard=32`.
|
||||
|
||||
Currently only Zephyr and FreeRTOS support these configurations.
|
||||
|
||||
Nim for realtime systems
|
||||
========================
|
||||
|
||||
See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
|
||||
See the `--mm:arc` or `--mm:orc` memory management settings in `MM <mm.html>`_ for further
|
||||
information.
|
||||
|
||||
|
||||
|
||||
@@ -1,81 +1,3 @@
|
||||
=======================
|
||||
Nim's Memory Management
|
||||
=======================
|
||||
|
||||
.. default-role:: code
|
||||
.. include:: rstcommon.rst
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimversion|
|
||||
|
||||
..
|
||||
|
||||
|
||||
"The road to hell is paved with good intentions."
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
A memory-management algorithm optimal for every use-case cannot exist.
|
||||
Nim provides multiple paradigms for needs ranging from large multi-threaded
|
||||
applications, to games, hard-realtime systems and small microcontrollers.
|
||||
|
||||
This document describes how the management strategies work;
|
||||
How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:,
|
||||
and how the memory management strategies other than garbage collectors work.
|
||||
|
||||
.. note:: the default GC is incremental, thread-local and not "stop-the-world"
|
||||
|
||||
Multi-paradigm Memory Management Strategies
|
||||
===========================================
|
||||
|
||||
.. default-role:: option
|
||||
|
||||
To choose the memory management strategy use the `--gc:` switch.
|
||||
|
||||
--gc:refc This is the default GC. It's a
|
||||
deferred reference counting based garbage collector
|
||||
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
|
||||
--gc:markAndSweep Simple Mark-And-Sweep based garbage collector.
|
||||
Heaps are thread-local.
|
||||
--gc:boehm Boehm based garbage collector, it offers a shared heap.
|
||||
--gc:go Go's garbage collector, useful for interoperability with Go.
|
||||
Offers a shared heap.
|
||||
--gc:arc Plain reference counting with
|
||||
`move semantic optimizations <destructors.html#move-semantics>`_, offers a shared heap.
|
||||
It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles
|
||||
cause memory leaks, beware.
|
||||
|
||||
--gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion".
|
||||
Unfortunately, that makes its performance profile hard to reason about so it is less
|
||||
useful for hard real-time systems.
|
||||
|
||||
--gc:none No memory management strategy nor a garbage collector. Allocated memory is
|
||||
simply never freed. You should use `--gc:arc` instead.
|
||||
|
||||
|
||||
================== ======== ================= ============== ===================
|
||||
Memory Management Heap Reference Cycles Stop-The-World Command line switch
|
||||
================== ======== ================= ============== ===================
|
||||
RefC Local Cycle Collector No `--gc:refc`
|
||||
Mark & Sweep Local Cycle Collector No `--gc:markAndSweep`
|
||||
ARC Shared Leak No `--gc:arc`
|
||||
ORC Shared Cycle Collector No `--gc:orc`
|
||||
Boehm Shared Cycle Collector Yes `--gc:boehm`
|
||||
Go Shared Cycle Collector Yes `--gc:go`
|
||||
None Manual Manual Manual `--gc:none`
|
||||
================== ======== ================= ============== ===================
|
||||
|
||||
.. default-role:: code
|
||||
.. include:: rstcommon.rst
|
||||
|
||||
JavaScript's garbage collector is used for the `JavaScript and NodeJS
|
||||
<backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||
The `NimScript <nims.html>`_ target uses the memory management strategy built into
|
||||
the Nim compiler.
|
||||
|
||||
|
||||
Tweaking the refc GC
|
||||
====================
|
||||
|
||||
@@ -164,6 +86,35 @@ that up to 100 objects are traversed and freed before it checks again. Thus
|
||||
highly specialized environments or for older hardware.
|
||||
|
||||
|
||||
Thread coordination
|
||||
-------------------
|
||||
|
||||
When the `NimMain()` function is called Nim initializes the garbage
|
||||
collector to the current thread, which is usually the main thread of your
|
||||
application. If your C code later spawns a different thread and calls Nim
|
||||
code, the garbage collector will fail to work properly and you will crash.
|
||||
|
||||
As long as you don't use the threadvar emulation Nim uses native thread
|
||||
variables, of which you get a fresh version whenever you create a thread. You
|
||||
can then attach a GC to this thread via
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
system.setupForeignThreadGc()
|
||||
|
||||
It is **not** safe to disable the garbage collector and enable it after the
|
||||
call from your background thread even if the code you are calling is short
|
||||
lived.
|
||||
|
||||
Before the thread exits, you should tear down the thread's GC to prevent memory
|
||||
leaks by calling
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
system.tearDownForeignThreadGc()
|
||||
|
||||
|
||||
|
||||
Keeping track of memory
|
||||
=======================
|
||||
|
||||
@@ -178,7 +129,7 @@ Other useful procs from `system <system.html>`_ you can use to keep track of mem
|
||||
* `GC_getStatistics()` Garbage collector statistics as a human-readable string.
|
||||
|
||||
These numbers are usually only for the running thread, not for the whole heap,
|
||||
with the exception of `--gc:boehm`:option: and `--gc:go`:option:.
|
||||
with the exception of `--mm:boehm`:option: and `--mm:go`:option:.
|
||||
|
||||
In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually
|
||||
allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`.
|
||||
@@ -36,7 +36,7 @@ Options
|
||||
(for debugging)
|
||||
--failing Only show failing/ignored tests
|
||||
--targets:"c cpp js objc"
|
||||
Run tests for specified targets (default: all)
|
||||
Run tests for specified targets (default: c)
|
||||
--nim:path Use a particular nim executable (default: $PATH/nim)
|
||||
--directory:dir Change to directory dir before reading the tests
|
||||
or doing anything else.
|
||||
@@ -164,7 +164,7 @@ Example "template" **to edit** and write a Testament unittest:
|
||||
# Timeout seconds to run the test. Fractional values are supported.
|
||||
timeout: 1.5
|
||||
|
||||
# Targets to run the test into (c, cpp, objc, js).
|
||||
# Targets to run the test into (c, cpp, objc, js). Defaults to c.
|
||||
targets: "c js"
|
||||
|
||||
# flags with which to run the test, delimited by `;`
|
||||
|
||||
@@ -395,7 +395,7 @@ The `try` statement handles exceptions:
|
||||
echo "could not convert string to integer"
|
||||
except IOError:
|
||||
echo "IO error!"
|
||||
except:
|
||||
except CatchableError:
|
||||
echo "Unknown exception!"
|
||||
# reraise the unknown exception:
|
||||
raise
|
||||
@@ -426,7 +426,7 @@ module. Example:
|
||||
.. code-block:: nim
|
||||
try:
|
||||
doSomethingHere()
|
||||
except:
|
||||
except CatchableError:
|
||||
let
|
||||
e = getCurrentException()
|
||||
msg = getCurrentExceptionMsg()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user