mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
102 Commits
v2.0.16
...
pr_no_forw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52bf954ba5 | ||
|
|
a4781dc4bc | ||
|
|
c0ecdb01a9 | ||
|
|
93407096db | ||
|
|
d77ada5bdf | ||
|
|
6eb722c47d | ||
|
|
c44c8ddb44 | ||
|
|
20cbdc2741 | ||
|
|
eb83d20d0d | ||
|
|
7fababd583 | ||
|
|
98c39e8e57 | ||
|
|
fede757238 | ||
|
|
019b488e1f | ||
|
|
2e3d9cdbee | ||
|
|
ee817557ec | ||
|
|
60307cc373 | ||
|
|
299394d21a | ||
|
|
940b1607b8 | ||
|
|
ade75a1483 | ||
|
|
6c4e7835bf | ||
|
|
9296b45de4 | ||
|
|
a660c17d30 | ||
|
|
1927ae72d0 | ||
|
|
09d0fda7fd | ||
|
|
7bb2462d06 | ||
|
|
9bf605cf98 | ||
|
|
9207d77848 | ||
|
|
4c89223171 | ||
|
|
f642c9dbf1 | ||
|
|
23f3f9ae2c | ||
|
|
3f7e1d7daa | ||
|
|
48da472dd2 | ||
|
|
469c9cfab4 | ||
|
|
72bc72bf9e | ||
|
|
277393d0f1 | ||
|
|
3bb75f2dea | ||
|
|
9fed58d5a0 | ||
|
|
0bf286583a | ||
|
|
faf1c91e6a | ||
|
|
7be2e2bef5 | ||
|
|
8523b543d6 | ||
|
|
8625e71250 | ||
|
|
05f7c4f79d | ||
|
|
2aab03bdfb | ||
|
|
a6610745d8 | ||
|
|
baf350493b | ||
|
|
fa58d23080 | ||
|
|
6ec1c80779 | ||
|
|
91c3221855 | ||
|
|
46e94c83d4 | ||
|
|
5ec81d076b | ||
|
|
d53a89e453 | ||
|
|
5334dc921f | ||
|
|
989da75b84 | ||
|
|
c622e58db9 | ||
|
|
28b2e429ef | ||
|
|
ce079a8da4 | ||
|
|
3aaef9e4cf | ||
|
|
d136af0122 | ||
|
|
73e661d01b | ||
|
|
10a6e4c236 | ||
|
|
bf5d173bc6 | ||
|
|
4c6be40b34 | ||
|
|
37d8f32ae9 | ||
|
|
47d06d3d4c | ||
|
|
0219c5a607 | ||
|
|
b4b555d8d1 | ||
|
|
260b4236fc | ||
|
|
b5b4b48c94 | ||
|
|
fe9ae2c69a | ||
|
|
614a18cd05 | ||
|
|
26eb0a944f | ||
|
|
e7b4c7cddb | ||
|
|
93ced31353 | ||
|
|
53586d1f32 | ||
|
|
67122a9cb6 | ||
|
|
d2b197bdcd | ||
|
|
f18e4c4050 | ||
|
|
95c751a9e4 | ||
|
|
137d608d7d | ||
|
|
b2c3b8f931 | ||
|
|
7bf7496557 | ||
|
|
e0396900ed | ||
|
|
9872453365 | ||
|
|
e15e19308e | ||
|
|
873eaa3f65 | ||
|
|
db435a4a79 | ||
|
|
73a29d72e3 | ||
|
|
26f183043f | ||
|
|
3efabd3ec6 | ||
|
|
7c2a2c8dc8 | ||
|
|
fb7acd6600 | ||
|
|
d37b620757 | ||
|
|
14bc3f3268 | ||
|
|
8d8d75706c | ||
|
|
6b913b4741 | ||
|
|
b40da812f7 | ||
|
|
825a0e7df4 | ||
|
|
f3a7622514 | ||
|
|
da368885da | ||
|
|
1d2c27d2e6 | ||
|
|
a23e53b490 |
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -71,5 +71,6 @@ body:
|
||||
which should give more context on a compiler crash.
|
||||
- If it's a regression, you can help us by identifying which version introduced the bug,
|
||||
see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
|
||||
or at least try known past releases (eg `choosenim 1.2.0`).
|
||||
or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
|
||||
via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
|
||||
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)
|
||||
|
||||
8
.github/workflows/ci_bench.yml
vendored
8
.github/workflows/ci_bench.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
os: [ubuntu-20.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
node-version: '16.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
4
.github/workflows/ci_docs.yml
vendored
4
.github/workflows/ci_docs.yml
vendored
@@ -43,11 +43,11 @@ jobs:
|
||||
target: [linux, windows, osx]
|
||||
include:
|
||||
- target: linux
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-20.04
|
||||
- target: windows
|
||||
os: windows-2019
|
||||
- target: osx
|
||||
os: macos-13
|
||||
os: macos-11
|
||||
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
76
.github/workflows/ci_gcc14.yml
vendored
76
.github/workflows/ci_gcc14.yml
vendored
@@ -1,76 +0,0 @@
|
||||
name: GCC 14
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60 # refs bug #18178
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt update -qq
|
||||
sudo apt remove needrestart
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
- name: 'Install dependencies (Linux amd64 gcc 14)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo add-apt-repository universe
|
||||
sudo apt update -qq
|
||||
sudo apt install -y gcc-14 g++-14 libpcre3 liblapack-dev
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
nimInternalInstallDepsWindows
|
||||
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'NIM_TESTAMENT_DISABLE_SSL'
|
||||
shell: bash
|
||||
run: echo "NIM_TESTAMENT_DISABLE_SSL=1" >> $GITHUB_ENV
|
||||
|
||||
- name: 'System information'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimCiSystemInfo
|
||||
|
||||
- name: 'Build csourcesAny'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
|
||||
|
||||
- name: 'koch, Run CI'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimInternalBuildKochAndRunCI
|
||||
9
.github/workflows/ci_packages.yml
vendored
9
.github/workflows/ci_packages.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, macos-13]
|
||||
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 }})'
|
||||
@@ -32,10 +32,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
node-version: '16.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
@@ -48,7 +48,6 @@ jobs:
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
# XXX can't find boehm and gtk on macos 13
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
|
||||
19
.github/workflows/ci_publish.yml
vendored
19
.github/workflows/ci_publish.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04]
|
||||
os: [ubuntu-20.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v4
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ''
|
||||
node-version: '16.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
@@ -34,6 +34,17 @@ jobs:
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
nimInternalInstallDepsWindows
|
||||
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
vmImage: 'ubuntu-20.04'
|
||||
CPU: amd64
|
||||
# regularly breaks, refs bug #17325
|
||||
# Linux_i386:
|
||||
@@ -29,23 +29,23 @@ jobs:
|
||||
# vmImage: 'ubuntu-18.04'
|
||||
# CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-13'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-13'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64_batch0_3:
|
||||
vmImage: 'windows-2025'
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
# see also: `NIM_TEST_PACKAGES`
|
||||
NIM_TESTAMENT_BATCH: "0_3"
|
||||
Windows_amd64_batch1_3:
|
||||
vmImage: 'windows-2025'
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
NIM_TESTAMENT_BATCH: "1_3"
|
||||
Windows_amd64_batch2_3:
|
||||
vmImage: 'windows-2025'
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
NIM_TESTAMENT_BATCH: "2_3"
|
||||
|
||||
@@ -80,12 +80,10 @@ jobs:
|
||||
- bash: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
echo_run sudo add-apt-repository universe
|
||||
echo_run sudo apt-get update -qq
|
||||
echo_run sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
echo_run sudo apt-get install --no-install-recommends -yq \
|
||||
gcc-14 g++-14 libpcre3 liblapack-dev libpcre3 liblapack-dev libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
echo_run sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
|
||||
echo_run sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
displayName: 'Install dependencies (amd64 Linux)'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
|
||||
|
||||
@@ -102,12 +100,12 @@ jobs:
|
||||
Pin-Priority: 1001
|
||||
EOF
|
||||
|
||||
# echo_run sudo apt-get update -qq
|
||||
echo_run sudo apt-get update -qq || echo "failed, see bug #17343"
|
||||
# echo_run sudo apt-fast update -qq
|
||||
echo_run sudo apt-fast update -qq || echo "failed, see bug #17343"
|
||||
# `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get:
|
||||
# `could not load: libffi.so` during dynamic loading.
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
echo_run sudo apt-get install --no-install-recommends --allow-downgrades -yq \
|
||||
echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
|
||||
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
|
||||
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386
|
||||
|
||||
@@ -132,7 +130,6 @@ jobs:
|
||||
- bash: brew install boehmgc make sfml
|
||||
displayName: 'Install dependencies (OSX)'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin'))
|
||||
# XXX can't find boehm on macos 13
|
||||
|
||||
- bash: |
|
||||
set -e
|
||||
|
||||
@@ -24,6 +24,6 @@ if not exist %nim_csources% (
|
||||
cd ..
|
||||
copy /y bin\nim.exe %nim_csources%
|
||||
)
|
||||
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
|
||||
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
|
||||
koch tools --skipUserCfg --skipParentCfg --hints:off
|
||||
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
|
||||
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
|
||||
koch tools --skipUserCfg --skipParentCfg --hints:off
|
||||
|
||||
100
changelog.md
100
changelog.md
@@ -3,9 +3,6 @@
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
|
||||
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
|
||||
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
@@ -14,12 +11,6 @@
|
||||
|
||||
[//]: # "Additions:"
|
||||
|
||||
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
|
||||
- Added `setLenUninit` to system, which doesn't initalize
|
||||
slots when enlarging a sequence.
|
||||
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
|
||||
- Added Viewport API for the JavaScript targets in the `dom` module.
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
|
||||
|
||||
@@ -30,97 +21,6 @@ slots when enlarging a sequence.
|
||||
|
||||
|
||||
|
||||
- The experimental option `--experimental:openSym` has been added to allow
|
||||
captured symbols in generic routine and template bodies respectively to be
|
||||
replaced by symbols injected locally by templates/macros at instantiation
|
||||
time. `bind` may be used to keep the captured symbols over the injected ones
|
||||
regardless of enabling the option, but other methods like renaming the
|
||||
captured symbols should be used instead so that the code is not affected by
|
||||
context changes.
|
||||
|
||||
Since this change may affect runtime behavior, the experimental switch
|
||||
`openSym` needs to be enabled; and a warning is given in the case where an
|
||||
injected symbol would replace a captured symbol not bound by `bind` and
|
||||
the experimental switch isn't enabled.
|
||||
|
||||
```nim
|
||||
const value = "captured"
|
||||
template foo(x: int, body: untyped): untyped =
|
||||
let value {.inject.} = "injected"
|
||||
body
|
||||
|
||||
proc old[T](): string =
|
||||
foo(123):
|
||||
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
|
||||
echo old[int]() # "captured"
|
||||
|
||||
template oldTempl(): string =
|
||||
block:
|
||||
foo(123):
|
||||
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
|
||||
echo oldTempl() # "captured"
|
||||
|
||||
{.experimental: "openSym".}
|
||||
|
||||
proc bar[T](): string =
|
||||
foo(123):
|
||||
return value
|
||||
assert bar[int]() == "injected" # previously it would be "captured"
|
||||
|
||||
proc baz[T](): string =
|
||||
bind value
|
||||
foo(123):
|
||||
return value
|
||||
assert baz[int]() == "captured"
|
||||
|
||||
template barTempl(): string =
|
||||
block:
|
||||
foo(123):
|
||||
value
|
||||
assert barTempl() == "injected" # previously it would be "captured"
|
||||
|
||||
template bazTempl(): string =
|
||||
bind value
|
||||
block:
|
||||
foo(123):
|
||||
value
|
||||
assert bazTempl() == "captured"
|
||||
```
|
||||
|
||||
This option also generates a new node kind `nnkOpenSym` which contains
|
||||
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
|
||||
modified `nnkOpenSymChoice` node but macros that want to support the
|
||||
experimental feature should still handle `nnkOpenSym`, as the node kind would
|
||||
simply not be generated as opposed to being removed.
|
||||
|
||||
Another experimental switch `genericsOpenSym` exists that enables this behavior
|
||||
at instantiation time, meaning templates etc can enable it specifically when
|
||||
they are being called. However this does not generate `nnkOpenSym` nodes
|
||||
(unless the other switch is enabled) and so doesn't reflect the regular
|
||||
behavior of the switch.
|
||||
|
||||
```nim
|
||||
const value = "captured"
|
||||
template foo(x: int, body: untyped): untyped =
|
||||
let value {.inject.} = "injected"
|
||||
{.push experimental: "genericsOpenSym".}
|
||||
body
|
||||
{.pop.}
|
||||
|
||||
proc bar[T](): string =
|
||||
foo(123):
|
||||
return value
|
||||
echo bar[int]() # "injected"
|
||||
|
||||
template barTempl(): string =
|
||||
block:
|
||||
var res: string
|
||||
foo(123):
|
||||
res = value
|
||||
res
|
||||
assert barTempl() == "injected"
|
||||
```
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
|
||||
`sink` for optimization purposes.
|
||||
|
||||
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fulfill its promises.
|
||||
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
|
||||
|
||||
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
|
||||
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
|
||||
|
||||
12
changelogs/changelog_2_2_0.md
Normal file
12
changelogs/changelog_2_2_0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v2.2.0 - 2023-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
## Language changes
|
||||
|
||||
## Compiler changes
|
||||
|
||||
## Tool changes
|
||||
|
||||
@@ -3,7 +3,7 @@ import std/[strutils, os, osproc, parseutils, strformat]
|
||||
|
||||
proc main() =
|
||||
var msg = ""
|
||||
const cmd = "./koch boot --gc:orc -d:release"
|
||||
const cmd = "./koch boot --mm:orc -d:release"
|
||||
|
||||
let (output, exitCode) = execCmdEx(cmd)
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind =
|
||||
# x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant
|
||||
# x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant
|
||||
template collectImportantNodes(result, n) =
|
||||
var result: seq[PNode]
|
||||
var result: seq[PNode] = @[]
|
||||
var n = n
|
||||
while true:
|
||||
case n.kind
|
||||
|
||||
@@ -114,6 +114,8 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
# use expensive type check:
|
||||
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
|
||||
result = arMaybe
|
||||
else:
|
||||
result = arNo
|
||||
of nkBracketExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
if a.len >= 2 and b.len >= 2:
|
||||
@@ -149,7 +151,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
result = isPartOf(a[1], b[1])
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
else: discard
|
||||
else: result = arNo
|
||||
# Calls return a new location, so a default of ``arNo`` is fine.
|
||||
else:
|
||||
# go down recursively; this is quite demanding:
|
||||
@@ -165,6 +167,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
|
||||
of DerefKinds:
|
||||
# a* !<| b[] iff
|
||||
result = arNo
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a, b[0])
|
||||
if result == arNo: result = arMaybe
|
||||
@@ -186,7 +189,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a[0], b)
|
||||
if result == arNo: result = arMaybe
|
||||
else: discard
|
||||
else:
|
||||
result = arNo
|
||||
else: result = arNo
|
||||
of nkObjConstr:
|
||||
result = arNo
|
||||
for i in 1..<b.len:
|
||||
@@ -204,4 +209,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
of nkBracket:
|
||||
if b.len > 0:
|
||||
result = isPartOf(a, b[0])
|
||||
else: discard
|
||||
else:
|
||||
result = arNo
|
||||
else: result = arNo
|
||||
|
||||
253
compiler/ast.nim
253
compiler/ast.nim
@@ -10,7 +10,7 @@
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
lineinfos, hashes, options, ropes, idents, int128, tables, wordrecg
|
||||
lineinfos, hashes, options, ropes, idents, int128, tables
|
||||
from strutils import toLowerAscii
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -227,7 +227,6 @@ type
|
||||
nkModuleRef # for .rod file support: A (moduleId, itemId) pair
|
||||
nkReplayAction # for .rod file support: A replay action
|
||||
nkNilRodNode # for .rod file support: a 'nil' PNode
|
||||
nkOpenSym # container for captured sym that can be overriden by local symbols
|
||||
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
@@ -315,8 +314,9 @@ type
|
||||
# an infinite loop, this flag is used as a sentinel to stop it.
|
||||
sfVirtual # proc is a C++ virtual function
|
||||
sfByCopy # param is marked as pass bycopy
|
||||
sfMember # proc is a C++ member of a type
|
||||
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
|
||||
sfWasGenSym # symbol was 'gensym'ed
|
||||
sfToplevelDecl
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
@@ -349,6 +349,7 @@ const
|
||||
sfBase* = sfDiscriminant
|
||||
sfCustomPragma* = sfRegister # symbol is custom pragma template
|
||||
sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
|
||||
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
@@ -518,9 +519,6 @@ type
|
||||
nfFirstWrite # this node is a first write
|
||||
nfHasComment # node has a comment
|
||||
nfSkipFieldChecking # node skips field visable checking
|
||||
nfDisabledOpenSym # temporary: node should be nkOpenSym but cannot
|
||||
# because openSym experimental switch is disabled
|
||||
# gives warning instead
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
|
||||
@@ -644,7 +642,7 @@ const
|
||||
skError* = skUnknown
|
||||
|
||||
var
|
||||
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam}
|
||||
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam, tfSendable}
|
||||
## type flags that are essential for type equality.
|
||||
## This is now a variable because for emulation of version:1.0 we
|
||||
## might exclude {tfGcSafe, tfNoSideEffect}.
|
||||
@@ -904,7 +902,6 @@ type
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
@@ -962,7 +959,7 @@ type
|
||||
kind*: TTypeKind # kind of type
|
||||
callConv*: TCallingConvention # for procs
|
||||
flags*: TTypeFlags # flags of the type
|
||||
sons*: TTypeSeq # base types, etc.
|
||||
sons: TTypeSeq # base types, etc.
|
||||
n*: PNode # node for types:
|
||||
# for range types a nkRange node
|
||||
# for record types a nkRecord node
|
||||
@@ -1043,6 +1040,8 @@ proc comment*(n: PNode): string =
|
||||
if nfHasComment in n.flags and not gconfig.useIc:
|
||||
# IC doesn't track comments, see `packed_ast`, so this could fail
|
||||
result = gconfig.comments[n.nodeId]
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc `comment=`*(n: PNode, a: string) =
|
||||
let id = n.nodeId
|
||||
@@ -1093,8 +1092,7 @@ const
|
||||
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
|
||||
nfFromTemplate, nfDefaultRefsParam,
|
||||
nfExecuteOnReload, nfLastRead,
|
||||
nfFirstWrite, nfSkipFieldChecking,
|
||||
nfDisabledOpenSym}
|
||||
nfFirstWrite, nfSkipFieldChecking}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
@@ -1110,7 +1108,7 @@ const
|
||||
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCommand, nkCallStrLit, nkHiddenCallConv}
|
||||
nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
|
||||
nkClosedSymChoice, nkOpenSym}
|
||||
nkClosedSymChoice}
|
||||
|
||||
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
|
||||
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
||||
@@ -1138,7 +1136,6 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
|
||||
of nkSym: a.sym.name
|
||||
of nkIdent: a.ident
|
||||
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
|
||||
of nkOpenSym: getPIdent(a.sons[0])
|
||||
else: nil
|
||||
|
||||
const
|
||||
@@ -1231,6 +1228,7 @@ proc getDeclPragma*(n: PNode): PNode =
|
||||
case n.kind
|
||||
of routineDefs:
|
||||
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
|
||||
else: result = nil
|
||||
of nkTypeDef:
|
||||
#[
|
||||
type F3*{.deprecated: "x3".} = int
|
||||
@@ -1250,6 +1248,8 @@ proc getDeclPragma*(n: PNode): PNode =
|
||||
]#
|
||||
if n[0].kind == nkPragmaExpr:
|
||||
result = n[0][1]
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
# support as needed for `nkIdentDefs` etc.
|
||||
result = nil
|
||||
@@ -1258,16 +1258,19 @@ proc getDeclPragma*(n: PNode): PNode =
|
||||
|
||||
proc extractPragma*(s: PSym): PNode =
|
||||
## gets the pragma node of routine/type/var/let/const symbol `s`
|
||||
if s.kind in routineKinds: # bug #24167
|
||||
if s.ast[pragmasPos] != nil and s.ast[pragmasPos].kind != nkEmpty:
|
||||
result = s.ast[pragmasPos]
|
||||
else:
|
||||
result = nil
|
||||
if s.kind in routineKinds:
|
||||
result = s.ast[pragmasPos]
|
||||
elif s.kind in {skType, skVar, skLet, skConst}:
|
||||
if s.ast != nil and s.ast.len > 0:
|
||||
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
|
||||
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
|
||||
result = s.ast[0][1]
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
assert result == nil or result.kind == nkPragma
|
||||
|
||||
proc skipPragmaExpr*(n: PNode): PNode =
|
||||
@@ -1460,9 +1463,6 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result.typ = sym.typ
|
||||
result.info = info
|
||||
|
||||
proc newOpenSym*(n: PNode): PNode {.inline.} =
|
||||
result = newTreeI(nkOpenSym, n.info, n)
|
||||
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
@@ -1471,42 +1471,7 @@ proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = castToInt64(intVal)
|
||||
|
||||
proc lastSon*(n: Indexable): Indexable {.inline.} = n.sons[^1]
|
||||
template setLastSon*(n: PNode, s: PNode) = n.sons[^1] = s
|
||||
|
||||
template firstSon*(n: PNode): PNode = n.sons[0]
|
||||
template secondSon*(n: PNode): PNode = n.sons[1]
|
||||
|
||||
template hasSon*(n: PNode): bool = n.len > 0
|
||||
template has2Sons*(n: PNode): bool = n.len > 1
|
||||
|
||||
proc replaceFirstSon*(n, newson: PNode) {.inline.} =
|
||||
n.sons[0] = newson
|
||||
|
||||
proc replaceSon*(n: PNode; i: int; newson: PNode) {.inline.} =
|
||||
n.sons[i] = newson
|
||||
|
||||
proc last*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
|
||||
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
proc skipModifier*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
|
||||
proc indexType*(n: PType): PType {.inline.} = n.sons[0]
|
||||
proc baseClass*(n: PType): PType {.inline.} = n.sons[0]
|
||||
|
||||
proc base*(t: PType): PType {.inline.} =
|
||||
result = t.sons[0]
|
||||
|
||||
proc returnType*(n: PType): PType {.inline.} = n.sons[0]
|
||||
proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r
|
||||
proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx
|
||||
|
||||
proc firstParamType*(n: PType): PType {.inline.} = n.sons[1]
|
||||
proc firstGenericParam*(n: PType): PType {.inline.} = n.sons[1]
|
||||
|
||||
proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
|
||||
proc genericHead*(n: PType): PType {.inline.} = n.sons[0]
|
||||
proc lastSon*(n: Indexable): Indexable = n.sons[^1]
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
## Used throughout the compiler code to test whether a type tree contains or
|
||||
@@ -1514,7 +1479,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
## last child nodes of a type tree need to be searched. This is a really hot
|
||||
## path within the compiler!
|
||||
result = t
|
||||
while result.kind in kinds: result = last(result)
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
let kind = skipTypes(typ, abstractVarRange).kind
|
||||
@@ -1535,7 +1500,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newNode(nkIntLit)
|
||||
of tyStatic: # that's a pre-existing bug, will fix in another PR
|
||||
result = newNode(nkIntLit)
|
||||
else: doAssert false, $kind
|
||||
else: raiseAssert $kind
|
||||
result.intVal = intVal
|
||||
result.typ = typ
|
||||
|
||||
@@ -1573,116 +1538,31 @@ proc `$`*(s: PSym): string =
|
||||
else:
|
||||
result = "<nil>"
|
||||
|
||||
when false:
|
||||
iterator items*(t: PType): PType =
|
||||
for i in 0..<t.sons.len: yield t.sons[i]
|
||||
|
||||
iterator pairs*(n: PType): tuple[i: int, n: PType] =
|
||||
for i in 0..<n.sons.len: yield (i, n.sons[i])
|
||||
|
||||
when true:
|
||||
proc len*(n: PType): int {.inline.} =
|
||||
result = n.sons.len
|
||||
|
||||
proc sameTupleLengths*(a, b: PType): bool {.inline.} =
|
||||
result = a.sons.len == b.sons.len
|
||||
|
||||
iterator tupleTypePairs*(a, b: PType): (int, PType, PType) =
|
||||
for i in 0 ..< a.sons.len:
|
||||
yield (i, a.sons[i], b.sons[i])
|
||||
|
||||
iterator underspecifiedPairs*(a, b: PType; start = 0; without = 0): (PType, PType) =
|
||||
# XXX Figure out with what typekinds this is called.
|
||||
for i in start ..< min(a.sons.len, b.sons.len) + without:
|
||||
yield (a.sons[i], b.sons[i])
|
||||
|
||||
proc signatureLen*(t: PType): int {.inline.} =
|
||||
result = t.sons.len
|
||||
|
||||
proc paramsLen*(t: PType): int {.inline.} =
|
||||
result = t.sons.len - 1
|
||||
|
||||
proc genericParamsLen*(t: PType): int {.inline.} =
|
||||
assert t.kind == tyGenericInst
|
||||
result = t.sons.len - 2 # without 'head' and 'body'
|
||||
|
||||
proc genericInvocationParamsLen*(t: PType): int {.inline.} =
|
||||
assert t.kind == tyGenericInvocation
|
||||
result = t.sons.len - 1 # without 'head'
|
||||
|
||||
proc kidsLen*(t: PType): int {.inline.} =
|
||||
result = t.sons.len
|
||||
|
||||
proc genericParamHasConstraints*(t: PType): bool {.inline.} = t.sons.len > 0
|
||||
|
||||
proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0
|
||||
proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0
|
||||
proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1
|
||||
|
||||
proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0]
|
||||
|
||||
iterator genericInstParams*(t: PType): (bool, PType) =
|
||||
for i in 1..<t.sons.len-1:
|
||||
yield (i!=1, t.sons[i])
|
||||
|
||||
iterator genericInstParamPairs*(a, b: PType): (int, PType, PType) =
|
||||
for i in 1..<min(a.sons.len, b.sons.len)-1:
|
||||
yield (i-1, a.sons[i], b.sons[i])
|
||||
|
||||
iterator genericInvocationParams*(t: PType): (bool, PType) =
|
||||
for i in 1..<t.sons.len:
|
||||
yield (i!=1, t.sons[i])
|
||||
|
||||
iterator genericInvocationAndBodyElements*(a, b: PType): (PType, PType) =
|
||||
for i in 1..<a.sons.len:
|
||||
yield (a.sons[i], b.sons[i-1])
|
||||
|
||||
iterator genericInvocationParamPairs*(a, b: PType): (bool, PType, PType) =
|
||||
for i in 1..<a.sons.len:
|
||||
if i >= b.sons.len:
|
||||
yield (false, nil, nil)
|
||||
else:
|
||||
yield (true, a.sons[i], b.sons[i])
|
||||
|
||||
iterator genericBodyParams*(t: PType): (int, PType) =
|
||||
for i in 0..<t.sons.len-1:
|
||||
yield (i, t.sons[i])
|
||||
|
||||
iterator userTypeClassInstParams*(t: PType): (bool, PType) =
|
||||
for i in 1..<t.sons.len-1:
|
||||
yield (i!=1, t.sons[i])
|
||||
|
||||
iterator ikids*(t: PType): (int, PType) =
|
||||
for i in 0..<t.sons.len: yield (i, t.sons[i])
|
||||
|
||||
const
|
||||
FirstParamAt* = 1
|
||||
FirstGenericParamAt* = 1
|
||||
|
||||
iterator paramTypes*(t: PType): (int, PType) =
|
||||
for i in FirstParamAt..<t.sons.len: yield (i, t.sons[i])
|
||||
|
||||
iterator paramTypePairs*(a, b: PType): (PType, PType) =
|
||||
for i in FirstParamAt..<a.sons.len: yield (a.sons[i], b.sons[i])
|
||||
|
||||
template paramTypeToNodeIndex*(x: int): int = x
|
||||
|
||||
iterator kids*(t: PType): PType =
|
||||
iterator items*(t: PType): PType =
|
||||
for i in 0..<t.sons.len: yield t.sons[i]
|
||||
|
||||
iterator signature*(t: PType): PType =
|
||||
# yields return type + parameter types
|
||||
for i in 0..<t.sons.len: yield t.sons[i]
|
||||
iterator pairs*(n: PType): tuple[i: int, n: PType] =
|
||||
for i in 0..<n.sons.len: yield (i, n.sons[i])
|
||||
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
|
||||
result = PType(kind: kind, owner: owner, size: defaultSize,
|
||||
align: defaultAlignment, itemId: id,
|
||||
uniqueId: id)
|
||||
uniqueId: id, sons: sons)
|
||||
when false:
|
||||
if result.itemId.module == 55 and result.itemId.item == 2:
|
||||
echo "KNID ", kind
|
||||
writeStackTrace()
|
||||
|
||||
template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
|
||||
newType(kind, id, owner, parent.sons)
|
||||
|
||||
proc newType*(prev: PType, sons: seq[PType]): PType =
|
||||
result = prev
|
||||
result.sons = sons
|
||||
|
||||
proc addSon*(father, son: PType) =
|
||||
# todo fixme: in IC, `son` might be nil
|
||||
father.sons.add(son)
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(typeof(a.k)): a.k = b.k
|
||||
@@ -1748,19 +1628,13 @@ proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLi
|
||||
result.loc = s.loc
|
||||
result.annex = s.annex
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initStrTable*(): TStrTable =
|
||||
result = TStrTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newIdTable*: TIdTable =
|
||||
initIdTable(result)
|
||||
proc initIdTable*(): TIdTable =
|
||||
result = TIdTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc resetIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
@@ -1768,23 +1642,23 @@ proc resetIdTable*(x: var TIdTable) =
|
||||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initObjectSet*(): TObjectSet =
|
||||
result = TObjectSet(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initIdNodeTable*(): TIdNodeTable =
|
||||
result = TIdNodeTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initNodeTable*(): TNodeTable =
|
||||
result = TNodeTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
|
||||
result = t
|
||||
var i = maxIters
|
||||
while result.kind in kinds:
|
||||
result = last(result)
|
||||
result = lastSon(result)
|
||||
dec i
|
||||
if i == 0: return nil
|
||||
|
||||
@@ -1793,7 +1667,7 @@ proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
|
||||
result = t
|
||||
while result != nil and result.kind in kinds:
|
||||
if result.len == 0: return nil
|
||||
result = last(result)
|
||||
result = lastSon(result)
|
||||
|
||||
proc isGCedMem*(t: PType): bool {.inline.} =
|
||||
result = t.kind in {tyString, tyRef, tySequence} or
|
||||
@@ -1962,6 +1836,7 @@ proc hasNilSon*(n: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
||||
result = false
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind in kinds
|
||||
@@ -2062,15 +1937,13 @@ proc skipGenericOwner*(s: PSym): PSym =
|
||||
## Generic instantiations are owned by their originating generic
|
||||
## symbol. This proc skips such owners and goes straight to the owner
|
||||
## of the generic itself (the module or the enclosing proc).
|
||||
result = if s.kind == skModule:
|
||||
s
|
||||
elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
|
||||
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
|
||||
s.owner.owner
|
||||
else:
|
||||
s.owner
|
||||
|
||||
proc originatingModule*(s: PSym): PSym =
|
||||
result = s
|
||||
result = s.owner
|
||||
while result.kind != skModule: result = result.owner
|
||||
|
||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||
@@ -2132,7 +2005,7 @@ proc toObject*(typ: PType): PType =
|
||||
## cases should be a ``tyObject``).
|
||||
## Otherwise ``typ`` is simply returned as-is.
|
||||
let t = typ.skipTypes({tyAlias, tyGenericInst})
|
||||
if t.kind == tyRef: t.elementType
|
||||
if t.kind == tyRef: t.lastSon
|
||||
else: typ
|
||||
|
||||
proc toObjectFromRefPtrGeneric*(typ: PType): PType =
|
||||
@@ -2149,7 +2022,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
|
||||
result = typ
|
||||
while true:
|
||||
case result.kind
|
||||
of tyGenericBody: result = result.last
|
||||
of tyGenericBody: result = result.lastSon
|
||||
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
|
||||
# automatic dereferencing is deep, refs #18298.
|
||||
else: break
|
||||
@@ -2165,9 +2038,11 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
|
||||
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
|
||||
|
||||
proc skipColon*(n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
@@ -109,7 +109,7 @@ type
|
||||
data*: TIIPairSeq
|
||||
|
||||
|
||||
proc initIiTable*(x: var TIITable)
|
||||
proc initIITable*(x: var TIITable)
|
||||
proc iiTableGet*(t: TIITable, key: int): int
|
||||
proc iiTablePut*(t: var TIITable, key, val: int)
|
||||
|
||||
@@ -197,6 +197,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||
result = nil
|
||||
|
||||
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
|
||||
result = false
|
||||
if a[0] != b[0]: return false
|
||||
var alen = a.len - 1
|
||||
while alen > 0 and a[alen] != '`': dec(alen)
|
||||
@@ -226,10 +227,11 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
|
||||
## Named parameters are special because a named parameter can be
|
||||
## gensym'ed and then they have '\`<number>' suffix that we need to
|
||||
## ignore, see compiler / evaltempl.nim, snippet:
|
||||
## ```
|
||||
## ```nim
|
||||
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
|
||||
## if c.instLines: actual.info else: templ.info)
|
||||
## ```
|
||||
result = nil
|
||||
for i in 1..<list.len:
|
||||
let it = list[i].sym
|
||||
if it.name.id == ident.id or
|
||||
@@ -327,8 +329,10 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): Rope =
|
||||
var sonsRope: Rope
|
||||
if n == nil:
|
||||
result = ""
|
||||
sonsRope = rope("null")
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ""
|
||||
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
|
||||
strutils.toHex(cast[int](n), sizeof(n) * 2))]
|
||||
else:
|
||||
@@ -890,7 +894,7 @@ proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
|
||||
result = nextIter(ti, tab)
|
||||
|
||||
iterator items*(tab: TStrTable): PSym =
|
||||
var it: TTabIter = default(TTabIter)
|
||||
var it: TTabIter
|
||||
var s = initTabIter(it, tab)
|
||||
while s != nil:
|
||||
yield s
|
||||
@@ -1054,7 +1058,16 @@ proc iiTablePut(t: var TIITable, key, val: int) =
|
||||
iiTableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
proc isAddrNode*(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkAddr, nkHiddenAddr: true
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
|
||||
else: false
|
||||
else: false
|
||||
|
||||
proc listSymbolNames*(symbols: openArray[PSym]): string =
|
||||
result = ""
|
||||
for sym in symbols:
|
||||
if result.len > 0:
|
||||
result.add ", "
|
||||
|
||||
@@ -24,12 +24,6 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
|
||||
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
|
||||
result.add "]"
|
||||
|
||||
proc addTypeNodeDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
|
||||
result.add " [$1" % typ.kind.toHumanStr
|
||||
if typ.sym != nil:
|
||||
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
|
||||
result.add "]"
|
||||
|
||||
proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) =
|
||||
if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ)
|
||||
|
||||
|
||||
@@ -87,5 +87,6 @@ const populationCount: array[uint8, uint8] = block:
|
||||
arr
|
||||
|
||||
proc bitSetCard*(x: TBitSet): BiggestInt =
|
||||
result = 0
|
||||
for it in x:
|
||||
result.inc int(populationCount[it])
|
||||
|
||||
@@ -38,6 +38,7 @@ template less(a, b): bool = cmp(a, b) < 0
|
||||
template eq(a, b): bool = cmp(a, b) == 0
|
||||
|
||||
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
|
||||
result = default(Val)
|
||||
var x = b.root
|
||||
while x.isInternal:
|
||||
for j in 0..<x.entries:
|
||||
|
||||
@@ -24,7 +24,6 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
|
||||
|
||||
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
|
||||
result = false
|
||||
var n = le
|
||||
while true:
|
||||
# do NOT follow nkHiddenDeref here!
|
||||
@@ -47,6 +46,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
# cannot analyse the location; assume the worst
|
||||
return true
|
||||
|
||||
result = false
|
||||
if le != nil:
|
||||
for i in 1..<ri.len:
|
||||
let r = ri[i]
|
||||
@@ -83,16 +83,12 @@ 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:
|
||||
var flags: TAssignmentFlags = {}
|
||||
if typ[0].kind in {tyOpenArray, tyVarargs}:
|
||||
# perhaps generate no temp if the call doesn't have side effects
|
||||
flags.incl needTempForOpenArray
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if params.len != 0: pl.add(", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
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)
|
||||
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
@@ -100,8 +96,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
@@ -119,30 +114,26 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone and p.splitDecls == 0:
|
||||
getTempCpp(p, typ[0], d, pl)
|
||||
d = getTempCpp(p, typ[0], pl)
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
elif isHarmlessStore(p, canRaise, d):
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, flags) # no need for deep copying
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, tmp, list, flags) # no need for deep copying
|
||||
genAssignment(p, tmp, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
else:
|
||||
@@ -150,37 +141,27 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
line(p, cpsStmts, pl)
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
|
||||
|
||||
proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||
var x = n
|
||||
while true:
|
||||
case x.kind
|
||||
of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
|
||||
x = x[0]
|
||||
of nkHiddenStdConv:
|
||||
x = x[1]
|
||||
else:
|
||||
break
|
||||
while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}:
|
||||
x = x[0]
|
||||
if x.kind == nkSym and x.sym.kind == skParam:
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
var a, b, c: TLoc
|
||||
initLocExpr(p, q[1], a)
|
||||
initLocExpr(p, q[2], b)
|
||||
initLocExpr(p, q[3], c)
|
||||
# bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
|
||||
# are mapped into ctPtrToArray, the dereference of which is skipped
|
||||
# in the `genDeref`. We need to skip these ptrs here
|
||||
let ty = skipTypes(a.t, abstractVar+{tyPtr, tyRef})
|
||||
var a = initLocExpr(p, q[1])
|
||||
var b = initLocExpr(p, q[2])
|
||||
var c = initLocExpr(p, q[3])
|
||||
# but first produce the required index checks:
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c, ty)
|
||||
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)]
|
||||
case ty.kind
|
||||
@@ -219,6 +200,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
|
||||
lengthExpr)
|
||||
else:
|
||||
result = ("", "")
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
@@ -238,8 +220,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
|
||||
result.add x & ", " & y
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||
var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(n):
|
||||
@@ -285,18 +266,17 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
|
||||
# Also don't regress for non ARC-builds, too risky.
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
getSize(p.config, a.lode.typ) < 1024:
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
|
||||
@@ -308,40 +288,25 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
openArrayLoc(p, param.typ, n, result)
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
|
||||
(optByRef notin param.options or not p.module.compileToCpp):
|
||||
initLocExpr(p, n, a)
|
||||
a = initLocExpr(p, n)
|
||||
if n.kind in {nkCharLit..nkNilLit}:
|
||||
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
|
||||
else:
|
||||
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
|
||||
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
|
||||
n.kind == nkHiddenAddr:
|
||||
# bug #23748: we need to introduce a temporary here. The expression type
|
||||
# will be a reference in C++ and we cannot create a temporary reference
|
||||
# variable. Thus, we create a temporary pointer variable instead.
|
||||
let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
|
||||
if needsIndirect:
|
||||
n.typ = n.typ.exactReplica
|
||||
n.typ.flags.incl tfVarIsPtr
|
||||
initLocExprSingleUse(p, n, a)
|
||||
a = withTmpIfNeeded(p, a, needsTmp)
|
||||
if needsIndirect: a.flags.incl lfIndirect
|
||||
a = initLocExprSingleUse(p, n[0])
|
||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
||||
let callee = call[0]
|
||||
if callee.kind == nkSym and
|
||||
{sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
|
||||
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {} and
|
||||
needsIndirect:
|
||||
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
|
||||
addAddrLoc(p.config, a, result)
|
||||
else:
|
||||
addRdLoc(a, result)
|
||||
else:
|
||||
initLocExprSingleUse(p, n, a)
|
||||
if param.typ.kind in abstractPtrs:
|
||||
let typ = skipTypes(param.typ, abstractPtrs)
|
||||
if typ.sym != nil and sfImportc in typ.sym.flags:
|
||||
a.r = "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
|
||||
a = initLocExprSingleUse(p, n)
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
@@ -350,12 +315,13 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
else:
|
||||
initLocExprSingleUse(p, n, a)
|
||||
a = initLocExprSingleUse(p, n)
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
|
||||
import aliasanalysis
|
||||
|
||||
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
|
||||
result = false
|
||||
for p in potentialWrites:
|
||||
if p.aliases(n) != no or n.aliases(p) != no:
|
||||
return true
|
||||
@@ -411,23 +377,21 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
|
||||
# We must generate temporaries in cases like #14396
|
||||
# to keep the strict Left-To-Right evaluation
|
||||
var needTmp = newSeq[bool](ri.len - 1)
|
||||
var potentialWrites: seq[PNode]
|
||||
var potentialWrites: seq[PNode] = @[]
|
||||
for i in countdown(ri.len - 1, 1):
|
||||
if ri[i].skipTrivialIndirections.kind == nkSym:
|
||||
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
|
||||
else:
|
||||
#if not ri[i].typ.isCompileTimeOnly:
|
||||
var potentialReads: seq[PNode]
|
||||
var potentialReads: seq[PNode] = @[]
|
||||
getPotentialReads(ri[i], potentialReads)
|
||||
for n in potentialReads:
|
||||
if not needTmp[i - 1]:
|
||||
needTmp[i - 1] = potentialAlias(n, potentialWrites)
|
||||
getPotentialWrites(ri[i], false, potentialWrites)
|
||||
when false:
|
||||
# this optimization is wrong, see bug #23748
|
||||
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
|
||||
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
|
||||
|
||||
var oldLen = result.len
|
||||
for i in 1..<ri.len:
|
||||
@@ -451,9 +415,8 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
res = res & "_actual".rope
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
# this is a hotspot in the compiler
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -475,8 +438,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
|
||||
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
|
||||
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
@@ -501,7 +463,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
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)
|
||||
d = getTemp(p, typ[0], needsInit=true)
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
@@ -509,17 +471,15 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
elif isHarmlessStore(p, canRaise, d):
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
if tfIterator in typ.flags:
|
||||
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
@@ -527,11 +487,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp)
|
||||
var tmp: TLoc = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
if tfIterator in typ.flags:
|
||||
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
@@ -699,7 +657,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
var idx, stars: int
|
||||
var idx, stars: int = 0
|
||||
if scanCppGenericSlot(pat, i, idx, stars):
|
||||
var t = resolveStarsInCppType(typ, idx, stars)
|
||||
if t == nil: result.add("void")
|
||||
@@ -713,8 +671,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
result.add(substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -736,10 +693,9 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
@@ -759,8 +715,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var pl = "["
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
@@ -802,24 +757,22 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||
if d.k in {locTemp, locNone}:
|
||||
# We already got a temp. Great, special case it:
|
||||
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
||||
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add("Result: ")
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("]")
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, ri, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, ri, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,8 +57,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
specializeResetT(p, accessor, lastSon(typ))
|
||||
of tyArray:
|
||||
let arraySize = lengthOrd(p.config, typ[0])
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.r, arraySize])
|
||||
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
|
||||
@@ -83,7 +82,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
|
||||
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
@@ -95,9 +94,9 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
of ctInt8, ctInt16, ctInt32, ctInt64:
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
else:
|
||||
doAssert false, "unexpected set type kind"
|
||||
raiseAssert "unexpected set type kind"
|
||||
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
|
||||
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
|
||||
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
|
||||
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
|
||||
|
||||
@@ -18,7 +18,7 @@ proc registerTraverseProc(p: BProc, v: PSym) =
|
||||
var traverseProc = ""
|
||||
if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and
|
||||
optOwnedRefs notin p.config.globalOptions and
|
||||
containsManagedMemory(v.loc.t):
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
# we register a specialized marked proc here; this has the advantage
|
||||
# that it works out of the box for thread local storage then :-)
|
||||
traverseProc = genTraverseProcForGlobal(p.module, v, v.info)
|
||||
@@ -50,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
result = true
|
||||
|
||||
proc inExceptBlockLen(p: BProc): int =
|
||||
result = 0
|
||||
for x in p.nestedTryStmts:
|
||||
if x.inExcept: result.inc
|
||||
|
||||
@@ -71,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
|
||||
proc endBlock(p: BProc)
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
@@ -83,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
# check only the first son
|
||||
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
|
||||
let hcrCond = if forHcr: getTempName(p.module) else: ""
|
||||
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
|
||||
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
|
||||
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
|
||||
let isGlobalInBlock = forHcr and p.blocks.len > 2
|
||||
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
|
||||
@@ -95,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
startBlock(p)
|
||||
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n[^1], tup)
|
||||
var tup = initLocExpr(p, n[^1])
|
||||
var t = tup.t.skipTypes(abstractInst)
|
||||
for i in 0..<n.len-2:
|
||||
let vn = n[i]
|
||||
@@ -108,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
else:
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
|
||||
initLoc(field, locExpr, vn, tup.storage)
|
||||
var field = initLoc(locExpr, vn, tup.storage)
|
||||
if t.kind == tyTuple:
|
||||
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||
else:
|
||||
@@ -169,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
|
||||
proc endBlock(p: BProc) =
|
||||
let topBlock = p.blocks.len - 1
|
||||
let frameLen = p.blocks[topBlock].frameLen
|
||||
var blockEnd: Rope
|
||||
var blockEnd: Rope = ""
|
||||
if frameLen > 0:
|
||||
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
|
||||
if p.blocks[topBlock].label.len != 0:
|
||||
@@ -244,8 +244,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
# switch (x.state) {
|
||||
# case 0: goto STATE0;
|
||||
# ...
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
||||
p.flags.incl beforeRetNeeded
|
||||
lineF(p, cpsStmts, "case -1:$n", [])
|
||||
@@ -264,13 +263,13 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
|
||||
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLoc(d, locExpr, n, OnUnknown)
|
||||
d = initLoc(locExpr, n, OnUnknown)
|
||||
|
||||
if n[0].kind == nkClosure:
|
||||
initLocExpr(p, n[0][1], a)
|
||||
a = initLocExpr(p, n[0][1])
|
||||
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
|
||||
else:
|
||||
initLocExpr(p, n[0], a)
|
||||
a = initLocExpr(p, n[0])
|
||||
# the environment is guaranteed to contain the 'state' field at offset 1:
|
||||
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
|
||||
|
||||
@@ -341,7 +340,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
# Only do this for complex types that may need a call to `objectInit`
|
||||
if sfThread in v.flags and emulatedThreadVars(p.config) and
|
||||
isComplexValueType(v.typ):
|
||||
initLocExprSingleUse(p.module.preInitProc, vn, loc)
|
||||
loc = initLocExprSingleUse(p.module.preInitProc, vn)
|
||||
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
|
||||
# Alternative construction using default constructor (which may zeromem):
|
||||
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
||||
@@ -362,7 +361,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
line(p, cpsStmts, decl)
|
||||
else:
|
||||
initLocExprSingleUse(p, value, tmp)
|
||||
tmp = initLocExprSingleUse(p, value)
|
||||
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
|
||||
return
|
||||
assignLocalVar(p, vn)
|
||||
@@ -408,8 +407,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
|
||||
proc genClosureVar(p: BProc, a: PNode) =
|
||||
var immediateAsgn = a[2].kind != nkEmpty
|
||||
var v: TLoc
|
||||
initLocExpr(p, a[0], v)
|
||||
var v: TLoc = initLocExpr(p, a[0])
|
||||
genLineDir(p, a)
|
||||
if immediateAsgn:
|
||||
loadInto(p, a[0], a[2], v)
|
||||
@@ -444,7 +442,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
a: TLoc
|
||||
lelse: TLabel
|
||||
if not isEmptyType(n.typ) and d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
d = getTemp(p, n.typ)
|
||||
genLineDir(p, n)
|
||||
let lend = getLabel(p)
|
||||
for it in n.sons:
|
||||
@@ -452,7 +450,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
|
||||
if it.len == 2:
|
||||
startBlock(p)
|
||||
initLocExprSingleUse(p, it[0], a)
|
||||
a = initLocExprSingleUse(p, it[0])
|
||||
lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
@@ -520,7 +518,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
# wrapped inside stmt lists by inject destructors won't be recognised
|
||||
let n = n.flattenStmts()
|
||||
var casePos = -1
|
||||
var arraySize: int
|
||||
var arraySize: int = 0
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind == nkCaseStmt:
|
||||
@@ -554,8 +552,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
genStmts(p, n[j])
|
||||
|
||||
let caseStmt = n[casePos]
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt[0], a)
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
# first goto:
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
|
||||
@@ -593,8 +590,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
else:
|
||||
genStmts(p, it)
|
||||
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt[0], a)
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
endBlock(p)
|
||||
|
||||
@@ -622,7 +618,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
p.breakIdx = startBlock(p, "while (1) {$n")
|
||||
p.blocks[p.breakIdx].isLoop = true
|
||||
initLocExpr(p, t[0], a)
|
||||
a = initLocExpr(p, t[0])
|
||||
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
|
||||
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
|
||||
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
|
||||
@@ -641,7 +637,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
# bug #4505: allocate the temp in the outer scope
|
||||
# so that it can escape the generated {}:
|
||||
if d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
d = getTemp(p, n.typ)
|
||||
d.flags.incl(lfEnforceDeref)
|
||||
preserveBreakIdx:
|
||||
p.breakIdx = startBlock(p)
|
||||
@@ -661,14 +657,13 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
|
||||
preserveBreakIdx:
|
||||
let forLoopVar = t[0].sym
|
||||
var rangeA, rangeB: TLoc
|
||||
assignLocalVar(p, t[0])
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t[1]
|
||||
assert(call.len == 4 or call.len == 5)
|
||||
initLocExpr(p, call[1], rangeA)
|
||||
initLocExpr(p, call[2], rangeB)
|
||||
var rangeA = initLocExpr(p, call[1])
|
||||
var rangeB = initLocExpr(p, call[2])
|
||||
|
||||
# $n at the beginning because of #9710
|
||||
if call.len == 4: # procName(a, b, annotation)
|
||||
@@ -685,8 +680,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
rangeA.rdLoc, rangeB.rdLoc,
|
||||
call[3].getStr.rope])
|
||||
else: # `||`(a, b, step, annotation)
|
||||
var step: TLoc
|
||||
initLocExpr(p, call[3], step)
|
||||
var step: TLoc = initLocExpr(p, call[3])
|
||||
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
|
||||
"for ($1 = $2; $1 <= $3; $1 += $4)",
|
||||
[forLoopVar.loc.rdLoc,
|
||||
@@ -756,8 +750,7 @@ proc raiseInstr(p: BProc; result: var Rope) =
|
||||
|
||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
if t[0].kind != nkEmpty:
|
||||
var a: TLoc
|
||||
initLocExprSingleUse(p, t[0], a)
|
||||
var a: TLoc = initLocExprSingleUse(p, t[0])
|
||||
finallyActions(p)
|
||||
var e = rdLoc(a)
|
||||
discard getTypeDesc(p.module, t[0].typ)
|
||||
@@ -787,12 +780,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
var x, y: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
if b[i].kind == nkRange:
|
||||
initLocExpr(p, b[i][0], x)
|
||||
initLocExpr(p, b[i][1], y)
|
||||
x = initLocExpr(p, b[i][0])
|
||||
y = initLocExpr(p, b[i][1])
|
||||
lineCg(p, cpsStmts, rangeFormat,
|
||||
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
|
||||
else:
|
||||
initLocExpr(p, b[i], x)
|
||||
x = initLocExpr(p, b[i])
|
||||
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
|
||||
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
@@ -834,8 +827,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
|
||||
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: FormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t[0], a)
|
||||
var a: TLoc = initLocExpr(p, t[0])
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
@@ -845,8 +837,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
var x: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
assert(b[i].kind != nkRange)
|
||||
initLocExpr(p, b[i], x)
|
||||
var j: int
|
||||
x = initLocExpr(p, b[i])
|
||||
var j: int = 0
|
||||
case b[i].kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
j = int(hashString(p.config, b[i].strVal) and high(branches))
|
||||
@@ -869,8 +861,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[Rope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
|
||||
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in 1..<t.len:
|
||||
inc(p.labels)
|
||||
@@ -906,6 +897,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||
|
||||
proc branchHasTooBigRange(b: PNode): bool =
|
||||
result = false
|
||||
for it in b:
|
||||
# last son is block
|
||||
if (it.kind == nkRange) and
|
||||
@@ -913,6 +905,7 @@ proc branchHasTooBigRange(b: PNode): bool =
|
||||
return true
|
||||
|
||||
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
result = 0
|
||||
for i in 1..<n.len:
|
||||
var branch = n[i]
|
||||
var stmtBlock = lastSon(branch)
|
||||
@@ -948,8 +941,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
var splitPoint = ifSwitchSplitPoint(p, n)
|
||||
|
||||
# generate if part (might be empty):
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
|
||||
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
eqFormat = "if ($1 == $2) goto $3;$n",
|
||||
@@ -971,18 +963,15 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
hasDefault = true
|
||||
exprBlock(p, branch.lastSon, d)
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
if not hasDefault:
|
||||
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
|
||||
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
|
||||
elif hasAssume in CC[p.config.cCompiler].props:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n", [])
|
||||
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n", [])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
if lend != "": fixLabel(p, lend)
|
||||
|
||||
proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
genLineDir(p, t)
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
case skipTypes(t[0].typ, abstractVarRange).kind
|
||||
of tyString:
|
||||
genStringCase(p, t, tyString, d)
|
||||
@@ -1033,7 +1022,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.module.includeHeader("<exception>")
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
genLineDir(p, t)
|
||||
|
||||
inc(p.labels, 2)
|
||||
@@ -1198,7 +1187,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
|
||||
expr(p, body, d)
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
genLineDir(p, t)
|
||||
cgsym(p.module, "popCurrentExceptionEx")
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
@@ -1276,7 +1265,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
p.flags.incl nimErrorFlagAccessed
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
|
||||
expr(p, t[0], d)
|
||||
|
||||
@@ -1383,7 +1372,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# propagateCurrentException();
|
||||
#
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
let quirkyExceptions = p.config.exc == excQuirky or
|
||||
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
|
||||
if not quirkyExceptions:
|
||||
@@ -1392,7 +1381,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.flags.incl noSafePoints
|
||||
genLineDir(p, t)
|
||||
cgsym(p.module, "Exception")
|
||||
var safePoint: Rope
|
||||
var safePoint: Rope = ""
|
||||
if not quirkyExceptions:
|
||||
safePoint = getTempName(p.module)
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
||||
@@ -1495,8 +1484,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
of nkSym:
|
||||
var sym = it.sym
|
||||
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
|
||||
var a: TLoc
|
||||
initLocExpr(p, it, a)
|
||||
var a: TLoc = initLocExpr(p, it)
|
||||
res.add($rdLoc(a))
|
||||
elif sym.kind == skType:
|
||||
res.add($getTypeDesc(p.module, sym.typ))
|
||||
@@ -1508,8 +1496,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
res.add($getTypeDesc(p.module, it.typ))
|
||||
else:
|
||||
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
|
||||
var a: TLoc
|
||||
initLocExpr(p, it, a)
|
||||
var a: TLoc = initLocExpr(p, it)
|
||||
res.add($a.rdLoc)
|
||||
|
||||
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
|
||||
@@ -1611,11 +1598,10 @@ when false:
|
||||
expr(p, call, d)
|
||||
|
||||
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
var a, tmp: TLoc
|
||||
var dotExpr = e[0]
|
||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
|
||||
initLocExpr(p, e[0], a)
|
||||
getTemp(p, a.t, tmp)
|
||||
var a = initLocExpr(p, e[0])
|
||||
var tmp: TLoc = getTemp(p, a.t)
|
||||
expr(p, e[1], tmp)
|
||||
if p.inUncheckedAssignSection == 0:
|
||||
let field = dotExpr[1].sym
|
||||
@@ -1633,9 +1619,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
else:
|
||||
let le = e[0]
|
||||
let ri = e[1]
|
||||
var a: TLoc
|
||||
var a: TLoc = initLoc(locNone, le, OnUnknown)
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
|
||||
initLoc(a, locNone, le, OnUnknown)
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
a.flags.incl(lfPrepareForMutation)
|
||||
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
|
||||
@@ -1647,7 +1632,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
loadInto(p, le, ri, a)
|
||||
|
||||
proc genStmts(p: BProc, t: PNode) =
|
||||
var a: TLoc
|
||||
var a: TLoc = default(TLoc)
|
||||
|
||||
let isPush = p.config.hasHint(hintExtendedContext)
|
||||
if isPush: pushInfoContext(p.config, t.info)
|
||||
|
||||
@@ -21,7 +21,7 @@ const
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
|
||||
proc genCaseRange(p: BProc, branch: PNode)
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
typ: PType) =
|
||||
@@ -74,8 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
genTraverseProc(c, accessor, lastSon(typ))
|
||||
of tyArray:
|
||||
let arraySize = lengthOrd(c.p.config, typ[0])
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
@@ -119,12 +118,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
var p = c.p
|
||||
assert typ.kind == tySequence
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
var a: TLoc
|
||||
a.r = accessor
|
||||
var a: TLoc = TLoc(r: accessor)
|
||||
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.r, lenExpr(c.p, a)])
|
||||
|
||||
@@ -54,31 +54,13 @@ proc mangleField(m: BModule; name: PIdent): string =
|
||||
if isKeyword(name):
|
||||
result.add "_0"
|
||||
|
||||
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
|
||||
result = "_Z" # Common prefix in Itanium ABI
|
||||
result.add encodeSym(m, s, makeUnique)
|
||||
if s.typ.len > 1: #we dont care about the return param
|
||||
for i in 1..<s.typ.len:
|
||||
if s.typ[i].isNil: continue
|
||||
result.add encodeType(m, s.typ[i])
|
||||
|
||||
if result in m.g.mangledPrcs:
|
||||
result = mangleProc(m, s, true)
|
||||
else:
|
||||
m.g.mangledPrcs.incl(result)
|
||||
|
||||
proc fillBackendName(m: BModule; s: PSym) =
|
||||
if s.loc.r == "":
|
||||
var result: Rope
|
||||
if not m.compileToCpp and s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
|
||||
m.g.config.symbolFiles == disabledSf:
|
||||
result = mangleProc(m, s, false).rope
|
||||
else:
|
||||
result = s.name.s.mangle.rope
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_u"
|
||||
result.addInt s.itemId.item # s.disamb #
|
||||
var result = s.name.s.mangle.rope
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_u"
|
||||
result.addInt s.itemId.item # s.disamb #
|
||||
if m.hcrOn:
|
||||
result.add '_'
|
||||
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
|
||||
@@ -224,8 +206,12 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
|
||||
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = mapType(conf, lastSon typ, isParam)
|
||||
else: doAssert(false, "mapType: " & $typ.kind)
|
||||
else: doAssert(false, "mapType: " & $typ.kind)
|
||||
else:
|
||||
result = ctVoid
|
||||
doAssert(false, "mapType: " & $typ.kind)
|
||||
else:
|
||||
result = ctVoid
|
||||
doAssert(false, "mapType: " & $typ.kind)
|
||||
|
||||
|
||||
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||
@@ -270,15 +256,9 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
|
||||
{tyVar, tyLent, tyRef, tyPtr})
|
||||
of ctStruct:
|
||||
let t = skipTypes(rettype, typedescInst)
|
||||
if rettype.isImportedCppType or t.isImportedCppType or
|
||||
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
|
||||
# prevents nrvo for cdecl procs; # bug #23401
|
||||
result = false
|
||||
else:
|
||||
result = containsGarbageCollectedRef(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t)) or
|
||||
(getSize(conf, rettype) == szUnknownSize and (t.sym == nil or sfImportc notin t.sym.flags))
|
||||
|
||||
if rettype.isImportedCppType or t.isImportedCppType: return false
|
||||
result = containsGarbageCollectedRef(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||
else: result = false
|
||||
|
||||
const
|
||||
@@ -346,7 +326,9 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
|
||||
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0])
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
|
||||
else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
|
||||
else:
|
||||
result = ""
|
||||
internalError(m.config, "tyStatic for getSimpleTypeDesc")
|
||||
of tyGenericInst, tyAlias, tySink, tyOwned:
|
||||
result = getSimpleTypeDesc(m, lastSon typ)
|
||||
else: result = ""
|
||||
@@ -495,11 +477,11 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
|
||||
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
|
||||
num = j
|
||||
if j > high(arg) + 1:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
else:
|
||||
res.add(arg[j-1])
|
||||
else:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
var start = i
|
||||
while i < frmt.len:
|
||||
if frmt[i] != c: inc(i)
|
||||
@@ -511,12 +493,12 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
s.constraint.strVal
|
||||
|
||||
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string,
|
||||
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false;) =
|
||||
let t = prc.typ
|
||||
let isCtor = sfConstructor in prc.flags
|
||||
if isCtor:
|
||||
if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
|
||||
rettype = ""
|
||||
elif t[0] == nil or isInvalidReturnType(m.config, t):
|
||||
rettype = "void"
|
||||
@@ -525,8 +507,8 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
|
||||
rettype = getTypeDescAux(m, t[0], check, dkResult)
|
||||
else:
|
||||
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)])
|
||||
var types, names, args: seq[string]
|
||||
if not isCtor:
|
||||
var types, names, args: seq[string] = @[]
|
||||
if not isCtor:
|
||||
var this = t.n[1].sym
|
||||
fillParamName(m, this)
|
||||
fillLoc(this.loc, locParam, t.n[1],
|
||||
@@ -573,6 +555,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
|
||||
|
||||
multiFormat(params, @['\'', '#'], [types, names])
|
||||
multiFormat(superCall, @['\'', '#'], [types, names])
|
||||
multiFormat(name, @['\'', '#'], [types, names]) #so we can ~'1 on members
|
||||
if params == "()":
|
||||
if types.len == 0:
|
||||
params = "(void)"
|
||||
@@ -666,13 +649,6 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
|
||||
result = rope(mangleField(m, field.name))
|
||||
if result == "": internalError(m.config, field.info, "mangleRecFieldName")
|
||||
|
||||
proc hasCppCtor(m: BModule; typ: PType): bool =
|
||||
result = false
|
||||
if m.compileToCpp and typ != nil and typ.itemId in m.g.graph.memberProcsPerType:
|
||||
for prc in m.g.graph.memberProcsPerType[typ.itemId]:
|
||||
if sfConstructor in prc.flags:
|
||||
return true
|
||||
|
||||
proc genRecordFieldsAux(m: BModule; n: PNode,
|
||||
rectype: PType,
|
||||
check: var IntSet; result: var Rope; unionPrefix = "") =
|
||||
@@ -737,7 +713,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
if fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ):
|
||||
if fieldType.isOrHasImportedCppType():
|
||||
result.addf("\t$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
|
||||
else:
|
||||
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
|
||||
@@ -750,9 +726,9 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
|
||||
genRecordFieldsAux(m, typ.n, typ, check, result)
|
||||
if typ.itemId in m.g.graph.memberProcsPerType:
|
||||
let procs = m.g.graph.memberProcsPerType[typ.itemId]
|
||||
var isDefaultCtorGen, isCtorGen: bool
|
||||
var isDefaultCtorGen, isCtorGen: bool = false
|
||||
for prc in procs:
|
||||
var header: Rope
|
||||
var header: Rope = ""
|
||||
if sfConstructor in prc.flags:
|
||||
isCtorGen = true
|
||||
if prc.typ.n.len == 1:
|
||||
@@ -760,7 +736,7 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
|
||||
genMemberProcHeader(m, prc, header, false, true)
|
||||
result.addf "$1;$n", [header]
|
||||
if isCtorGen and not isDefaultCtorGen:
|
||||
var ch: IntSet = default(IntSet)
|
||||
var ch: IntSet
|
||||
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
|
||||
|
||||
proc fillObjectFields*(m: BModule; typ: PType) =
|
||||
@@ -768,13 +744,12 @@ proc fillObjectFields*(m: BModule; typ: PType) =
|
||||
# this fact here.
|
||||
var check = initIntSet()
|
||||
discard getRecordFields(m, typ, check)
|
||||
if typ.baseClass != nil:
|
||||
fillObjectFields(m, typ.baseClass.skipTypes(skipPtrs))
|
||||
|
||||
proc mangleDynLibProc(sym: PSym): Rope
|
||||
|
||||
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
|
||||
check: var IntSet, hasField:var bool): Rope =
|
||||
check: var IntSet, hasField:var bool): Rope =
|
||||
result = ""
|
||||
if typ.kind == tyObject:
|
||||
if typ[0] == nil:
|
||||
if lacksMTypeField(typ):
|
||||
@@ -815,7 +790,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
|
||||
structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ)
|
||||
else:
|
||||
structOrUnion = structOrUnion(typ)
|
||||
var baseType: string
|
||||
var baseType: string = ""
|
||||
if typ[0] != nil:
|
||||
baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
|
||||
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
|
||||
@@ -872,7 +847,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||
# Make sure the index refers to one of the generic params of the type.
|
||||
# XXX: we should catch this earlier and report it as a semantic error.
|
||||
if idx >= typ.len:
|
||||
doAssert false, "invalid apostrophe type parameter index"
|
||||
raiseAssert "invalid apostrophe type parameter index"
|
||||
|
||||
result = typ[idx]
|
||||
for i in 1..stars:
|
||||
@@ -906,6 +881,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
|
||||
let sig = hashType(origTyp, m.config)
|
||||
|
||||
result = "" # todo move `result = getTypePre(m, t, sig)` here ?
|
||||
defer: # defer is the simplest in this case
|
||||
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
|
||||
addAbiCheck(m, t, result)
|
||||
@@ -986,7 +962,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
of tyProc:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.typeCache[sig] = result
|
||||
var rettype, desc: Rope
|
||||
var rettype, desc: Rope = ""
|
||||
genProcParams(m, t, rettype, desc, check, true, true)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure: # procedure vars may need a closure!
|
||||
@@ -1063,7 +1039,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
while i < cppName.len:
|
||||
if cppName[i] == '\'':
|
||||
var chunkEnd = i-1
|
||||
var idx, stars: int
|
||||
var idx, stars: int = 0
|
||||
if scanCppGenericSlot(cppName, i, idx, stars):
|
||||
result.add cppName.substr(chunkStart, chunkEnd)
|
||||
chunkStart = i
|
||||
@@ -1143,7 +1119,7 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope =
|
||||
assert t.kind == tyProc
|
||||
var check = initIntSet()
|
||||
result = getTempName(m)
|
||||
var rettype, desc: Rope
|
||||
var rettype, desc: Rope = ""
|
||||
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure or kind != clFull:
|
||||
@@ -1173,11 +1149,19 @@ proc isReloadable(m: BModule; prc: PSym): bool =
|
||||
proc isNonReloadable(m: BModule; prc: PSym): bool =
|
||||
return m.hcrOn and sfNonReloadable in prc.flags
|
||||
|
||||
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) =
|
||||
var afterParams: string
|
||||
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) =
|
||||
var afterParams: string = ""
|
||||
if scanf(val, "$*($*)$s$*", name, params, afterParams):
|
||||
if name.strip() == "operator" and params == "": #isFunctor?
|
||||
parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true)
|
||||
return
|
||||
isFnConst = afterParams.find("const") > -1
|
||||
isOverride = afterParams.find("override") > -1
|
||||
isMemberVirtual = name.find("virtual ") > -1
|
||||
if isMemberVirtual:
|
||||
name = name.replace("virtual ", "")
|
||||
if isFunctor:
|
||||
name = "operator ()"
|
||||
if isCtor:
|
||||
discard scanf(afterParams, ":$s$*", superCall)
|
||||
else:
|
||||
@@ -1186,28 +1170,28 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
|
||||
params = "(" & params & ")"
|
||||
|
||||
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
|
||||
assert {sfVirtual, sfConstructor} * prc.flags != {}
|
||||
assert sfCppMember * prc.flags != {}
|
||||
let isCtor = sfConstructor in prc.flags
|
||||
let isVirtual = not isCtor
|
||||
var check = initIntSet()
|
||||
fillBackendName(m, prc)
|
||||
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
|
||||
var memberOp = "#." #only virtual
|
||||
var typ: PType
|
||||
if isCtor:
|
||||
typ = prc.typ.sons[0]
|
||||
typ = prc.typ[0]
|
||||
else:
|
||||
typ = prc.typ.sons[1]
|
||||
typ = prc.typ[1]
|
||||
if typ.kind == tyPtr:
|
||||
typ = typ[0]
|
||||
memberOp = "#->"
|
||||
var typDesc = getTypeDescWeak(m, typ, check, dkParam)
|
||||
let asPtrStr = rope(if asPtr: "_PTR" else: "")
|
||||
var name, params, rettype, superCall: string
|
||||
var isFnConst, isOverride: bool
|
||||
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor)
|
||||
genMemberProcParams(m, prc, superCall, rettype, params, check, true, false)
|
||||
var fnConst, override: string
|
||||
var name, params, rettype, superCall: string = ""
|
||||
var isFnConst, isOverride, isMemberVirtual: bool = false
|
||||
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
|
||||
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
|
||||
let isVirtual = sfVirtual in prc.flags or isMemberVirtual
|
||||
var fnConst, override: string = ""
|
||||
if isCtor:
|
||||
name = typDesc
|
||||
if isFnConst:
|
||||
@@ -1219,7 +1203,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
|
||||
override = " override"
|
||||
superCall = ""
|
||||
else:
|
||||
if isVirtual:
|
||||
if not isCtor:
|
||||
prc.loc.r = "$1$2(@)" % [memberOp, name]
|
||||
elif superCall != "":
|
||||
superCall = " : " & superCall
|
||||
@@ -1236,7 +1220,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false)
|
||||
var check = initIntSet()
|
||||
fillBackendName(m, prc)
|
||||
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
|
||||
var rettype, params: Rope
|
||||
var rettype, params: Rope = ""
|
||||
genProcParams(m, prc.typ, rettype, params, check, true, false)
|
||||
# handle the 2 options for hotcodereloading codegen - function pointer
|
||||
# (instead of forward declaration) or header for function body with "_actual" postfix
|
||||
@@ -1437,7 +1421,7 @@ proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo
|
||||
else:
|
||||
genTypeInfoAuxBase(m, typ, origType, name, rope("0"), info)
|
||||
var tmp = getNimNode(m)
|
||||
if (not isImportedType(typ)) or tfCompleteStruct in typ.flags:
|
||||
if not isImportedType(typ):
|
||||
genObjectFields(m, typ, origType, typ.n, tmp, info)
|
||||
m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
|
||||
var t = typ[0]
|
||||
@@ -1476,7 +1460,7 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
|
||||
genTypeInfoAux(m, typ, typ, name, info)
|
||||
var nodePtrs = getTempName(m) & "_" & $typ.n.len
|
||||
genTNimNodeArray(m, nodePtrs, rope(typ.n.len))
|
||||
var enumNames, specialCases: Rope
|
||||
var enumNames, specialCases: Rope = ""
|
||||
var firstNimNode = m.typeNodes
|
||||
var hasHoles = false
|
||||
for i in 0..<typ.n.len:
|
||||
@@ -1555,6 +1539,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||
result = it.sym.name.s
|
||||
else:
|
||||
var p = m.owner
|
||||
result = ""
|
||||
if p != nil and p.kind == skPackage:
|
||||
result.add p.name.s & "."
|
||||
result.add m.name.s & "."
|
||||
@@ -1596,7 +1581,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
|
||||
))
|
||||
)
|
||||
else:
|
||||
let addrOf = newNodeIT(nkHiddenAddr, info, theProc.typ[1])
|
||||
let addrOf = newNodeIT(nkAddr, info, theProc.typ[1])
|
||||
addrOf.add newDeref(newTreeIT(
|
||||
nkCast, info, castType, newNodeIT(nkType, info, castType),
|
||||
newSymNode(dest)
|
||||
@@ -1787,7 +1772,7 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
|
||||
return prefixTI.rope & result & ")".rope
|
||||
|
||||
m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
|
||||
if m.compileToCpp:
|
||||
if m.compileToCpp or m.hcrOn:
|
||||
genTypeInfoV2OldImpl(m, t, origType, result, info)
|
||||
else:
|
||||
genTypeInfoV2Impl(m, t, origType, result, info)
|
||||
@@ -1942,11 +1927,8 @@ proc genTypeSection(m: BModule, n: PNode) =
|
||||
if len(n[i]) == 0: continue
|
||||
if n[i][0].kind != nkPragmaExpr: continue
|
||||
for p in 0..<n[i][0].len:
|
||||
if (n[i][0][p].kind notin {nkSym, nkPostfix}): continue
|
||||
var s = n[i][0][p]
|
||||
if s.kind == nkPostfix:
|
||||
s = n[i][0][p][1]
|
||||
if {sfExportc, sfCompilerProc} * s.sym.flags == {sfExportc}:
|
||||
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.sym.kind))
|
||||
if (n[i][0][p].kind != nkSym): continue
|
||||
if sfExportc in n[i][0][p].sym.flags:
|
||||
discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
|
||||
if m.g.generatedHeader != nil:
|
||||
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.sym.kind))
|
||||
discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
|
||||
|
||||
@@ -13,21 +13,22 @@ import
|
||||
ast, types, hashes, strutils, msgs, wordrecg,
|
||||
platform, trees, options, cgendata
|
||||
|
||||
import std/[hashes, strutils, formatfloat]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
result = getPragmaStmt(n[i], w)
|
||||
if result != nil: break
|
||||
of nkPragma:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
if whichPragma(n[i]) == w: return n[i]
|
||||
else: discard
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||
result = getPragmaStmt(n, w) != nil
|
||||
@@ -123,10 +124,10 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
var pt = skipTypes(s.typ, typedescInst)
|
||||
assert skResult != s.kind
|
||||
|
||||
|
||||
#note precedence: params override types
|
||||
if optByRef in s.options: return true
|
||||
elif sfByCopy in s.flags: return false
|
||||
elif sfByCopy in s.flags: return false
|
||||
elif tfByRef in pt.flags: return true
|
||||
elif tfByCopy in pt.flags: return false
|
||||
case pt.kind
|
||||
@@ -134,9 +135,6 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
|
||||
# forwarded objects are *always* passed by pointers for consistency!
|
||||
result = true
|
||||
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
# bug #23354:
|
||||
result = false
|
||||
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
|
||||
result = true # requested anyway
|
||||
elif (tfFinal in pt.flags) and (pt[0] == nil):
|
||||
@@ -153,64 +151,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
|
||||
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
|
||||
|
||||
proc encodeName*(name: string): string =
|
||||
result = mangle(name)
|
||||
result = $result.len & result
|
||||
|
||||
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
|
||||
result = if name == "": s.name.s else: name
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_u"
|
||||
result.add $s.itemId.item
|
||||
|
||||
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
|
||||
#Module::Type
|
||||
var name = s.name.s
|
||||
if makeUnique:
|
||||
name = makeUnique(m, s, name)
|
||||
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
|
||||
|
||||
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
|
||||
proc encodeType*(m: BModule; t: PType): string =
|
||||
result = ""
|
||||
var kindName = ($t.kind)[2..^1]
|
||||
kindName[0] = toLower($kindName[0])[0]
|
||||
case t.kind
|
||||
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
|
||||
result = encodeSym(m, t.sym)
|
||||
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
|
||||
result = encodeName(t[0].sym.name.s)
|
||||
result.add "I"
|
||||
for i in 1..<t.len - 1:
|
||||
result.add encodeType(m, t[i])
|
||||
result.add "E"
|
||||
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
|
||||
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
|
||||
result =
|
||||
case t.kind:
|
||||
of tySequence: encodeName("seq")
|
||||
else: encodeName(kindName)
|
||||
result.add "I"
|
||||
for i in 0..<t.len:
|
||||
let s = t[i]
|
||||
if s.isNil: continue
|
||||
result.add encodeType(m, s)
|
||||
result.add "E"
|
||||
of tyRange:
|
||||
var val = "range_"
|
||||
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
|
||||
val.addFloat t.n[0].floatVal
|
||||
val.add "_"
|
||||
val.addFloat t.n[1].floatVal
|
||||
else:
|
||||
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
|
||||
result = encodeName(val)
|
||||
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
|
||||
result = encodeName(kindName)
|
||||
of tyAlias, tyInferred, tyOwned:
|
||||
result = encodeType(m, t.elementType)
|
||||
else:
|
||||
assert false, "encodeType " & $t.kind
|
||||
|
||||
|
||||
@@ -30,12 +30,6 @@ import strutils except `%`, addf # collides with ropes.`%`
|
||||
from ic / ic import ModuleBackendFlag
|
||||
import dynlib
|
||||
|
||||
const
|
||||
# we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
|
||||
postprocessDirStart = '\1'
|
||||
postprocessDirSep = '\31'
|
||||
postprocessDirEnd = '\23'
|
||||
|
||||
when not declared(dynlib.libCandidates):
|
||||
proc libCandidates(s: string, dest: var seq[string]) =
|
||||
## given a library name pattern `s` write possible library names to `dest`.
|
||||
@@ -67,12 +61,10 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
|
||||
var ms = getModule(s)
|
||||
result = m.g.modules[ms.position]
|
||||
|
||||
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) =
|
||||
result.k = k
|
||||
result.storage = s
|
||||
result.lode = lode
|
||||
result.r = ""
|
||||
result.flags = flags
|
||||
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
|
||||
result = TLoc(k: k, storage: s, lode: lode,
|
||||
r: "", flags: flags
|
||||
)
|
||||
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
|
||||
# fills the loc if it is not already initialized
|
||||
@@ -272,28 +264,24 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
result = toLinenumber(info)
|
||||
if result < 0: result = 0 # negative numbers are not allowed in #line
|
||||
|
||||
proc genPostprocessDir(field1, field2, field3: string): string =
|
||||
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
|
||||
|
||||
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
|
||||
assert line >= 0
|
||||
if optLineDir in conf.options and line > 0:
|
||||
if fileIdx == InvalidFileIdx:
|
||||
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
|
||||
else:
|
||||
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
|
||||
r.addf("\n#line $2 $1\n",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
|
||||
assert line >= 0
|
||||
if optLineDir in p.config.options and line > 0:
|
||||
if fileIdx == InvalidFileIdx:
|
||||
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
|
||||
if lastFileIndex == info.fileIndex:
|
||||
r.addf("\n#line $1\n", [rope(line)])
|
||||
else:
|
||||
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
|
||||
r.addf("\n#line $2 $1\n",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
|
||||
if optLineDir in conf.options:
|
||||
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
|
||||
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
|
||||
|
||||
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
if p.lastLineInfo.line != info.line or
|
||||
@@ -301,14 +289,17 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
p.lastLineInfo.line = info.line
|
||||
p.lastLineInfo.fileIndex = info.fileIndex
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
|
||||
if optLineDir in conf.options:
|
||||
let lastFileIndex = p.lastLineInfo.fileIndex
|
||||
if freshLineInfo(p, info):
|
||||
genCLineDir(r, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
|
||||
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
|
||||
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
if p == p.module.preInitProc: return
|
||||
let line = t.info.safeLineNm
|
||||
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
@@ -316,11 +307,16 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
let lastFileIndex = p.lastLineInfo.fileIndex
|
||||
let freshLine = freshLineInfo(p, t.info)
|
||||
if freshLine:
|
||||
genCLineDir(p.s(cpsStmts), t.info.fileIndex, line, p, t.info, lastFileIndex)
|
||||
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
|
||||
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
|
||||
if freshLine:
|
||||
line(p, cpsStmts, genPostprocessDir("nimln", $line, $t.info.fileIndex.int32))
|
||||
if lastFileIndex == t.info.fileIndex:
|
||||
linefmt(p, cpsStmts, "nimln_($1);",
|
||||
[line])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "nimlf_($1, $2);",
|
||||
[line, quotedFilename(p.config, t.info)])
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
|
||||
@@ -406,8 +402,6 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||
type
|
||||
TAssignmentFlag = enum
|
||||
needToCopy
|
||||
needToCopySinkParam
|
||||
needTempForOpenArray
|
||||
TAssignmentFlags = set[TAssignmentFlag]
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
|
||||
@@ -439,7 +433,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
||||
of frEmbedded:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
var tmp: TLoc
|
||||
var tmp: TLoc = default(TLoc)
|
||||
if mode == constructRefObj:
|
||||
let objType = t.skipTypes(abstractInst+{tyRef})
|
||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
|
||||
@@ -487,8 +481,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
if containsGcRef:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
@@ -518,8 +511,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
if containsGarbageCollectedRef(loc.t):
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
@@ -546,17 +538,14 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
if not immediateAsgn:
|
||||
constructLoc(p, v.loc)
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
|
||||
storage: OnStack, flags: {})
|
||||
if p.module.compileToCpp and isOrHasImportedCppType(t):
|
||||
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
else:
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
result.flags = {}
|
||||
constructLoc(p, result, not needsInit)
|
||||
when false:
|
||||
# XXX Introduce a compiler switch in order to detect these easily.
|
||||
@@ -567,25 +556,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
|
||||
writeStackTrace()
|
||||
|
||||
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
|
||||
storage: OnStack, flags: {})
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
result.flags = {}
|
||||
|
||||
proc getIntTemp(p: BProc, result: var TLoc) =
|
||||
proc getIntTemp(p: BProc): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
|
||||
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
|
||||
flags: {})
|
||||
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
|
||||
result.k = locTemp
|
||||
result.storage = OnStack
|
||||
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
|
||||
result.flags = {}
|
||||
|
||||
proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
result = ""
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
fillLocalName(p, s)
|
||||
@@ -653,7 +638,7 @@ proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
|
||||
let s = vn.sym
|
||||
fillBackendName(p.module, s)
|
||||
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
|
||||
var decl: Rope
|
||||
var decl: Rope = ""
|
||||
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
|
||||
genGlobalVarDecl(p, vn, td, "", decl)
|
||||
decl.add " " & $s.loc.r
|
||||
@@ -742,12 +727,12 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
|
||||
proc raiseExit(p: BProc)
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) =
|
||||
initLoc(result, locNone, e, OnUnknown, flags)
|
||||
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown, flags)
|
||||
expr(p, e, result)
|
||||
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e, OnUnknown)
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown)
|
||||
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
|
||||
# We cannot check for tfNoSideEffect here because of mutable parameters.
|
||||
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
|
||||
@@ -838,8 +823,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
var p = newProc(nil, m)
|
||||
p.options.excl optStackTrace
|
||||
p.flags.incl nimErrorFlagDisabled
|
||||
var dest: TLoc
|
||||
initLoc(dest, locTemp, lib.path, OnStack)
|
||||
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
|
||||
dest.r = getTempName(m)
|
||||
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
|
||||
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
|
||||
@@ -874,11 +858,10 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
inc(m.labels, 2)
|
||||
if isCall:
|
||||
let n = lib.path
|
||||
var a: TLoc
|
||||
initLocExpr(m.initProc, n[0], a)
|
||||
var a: TLoc = initLocExpr(m.initProc, n[0])
|
||||
var params = rdLoc(a) & "("
|
||||
for i in 1..<n.len-1:
|
||||
initLocExpr(m.initProc, n[i], a)
|
||||
a = initLocExpr(m.initProc, n[i])
|
||||
params.add(rdLoc(a))
|
||||
params.add(", ")
|
||||
let load = "\t$1 = ($2) ($3$4));$n" %
|
||||
@@ -993,19 +976,11 @@ proc closureSetup(p: BProc, prc: PSym) =
|
||||
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
|
||||
[rdLoc(env.loc), getTypeDesc(p.module, env.typ)])
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
|
||||
declarativeDefs
|
||||
|
||||
proc containsResult(n: PNode): bool =
|
||||
result = false
|
||||
case n.kind
|
||||
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
|
||||
discard
|
||||
of nkReturnStmt:
|
||||
for i in 0..<n.len:
|
||||
if containsResult(n[i]): return true
|
||||
result = n.len > 0 and n[0].kind == nkEmpty
|
||||
of nkSym:
|
||||
if n.sym.kind == skResult:
|
||||
result = true
|
||||
@@ -1013,7 +988,12 @@ proc containsResult(n: PNode): bool =
|
||||
for i in 0..<n.len:
|
||||
if containsResult(n[i]): return true
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
|
||||
declarativeDefs
|
||||
|
||||
proc easyResultAsgn(n: PNode): PNode =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
var i = 0
|
||||
@@ -1032,7 +1012,7 @@ proc easyResultAsgn(n: PNode): PNode =
|
||||
type
|
||||
InitResultEnum = enum Unknown, InitSkippable, InitRequired
|
||||
|
||||
proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
proc allPathsAsgnResult(n: PNode): InitResultEnum =
|
||||
# Exceptions coming from calls don't have not be considered here:
|
||||
#
|
||||
# proc bar(): string = raise newException(...)
|
||||
@@ -1047,7 +1027,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
# echo "a was not written to"
|
||||
#
|
||||
template allPathsInBranch(it) =
|
||||
let a = allPathsAsgnResult(p, it)
|
||||
let a = allPathsAsgnResult(it)
|
||||
case a
|
||||
of InitRequired: return InitRequired
|
||||
of InitSkippable: discard
|
||||
@@ -1059,20 +1039,14 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
for it in n:
|
||||
result = allPathsAsgnResult(p, it)
|
||||
result = allPathsAsgnResult(it)
|
||||
if result != Unknown: return result
|
||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||
if n[0].kind == nkSym and n[0].sym.kind == skResult:
|
||||
if not containsResult(n[1]):
|
||||
if allPathsAsgnResult(p, n[1]) == InitRequired:
|
||||
result = InitRequired
|
||||
else:
|
||||
result = InitSkippable
|
||||
if not containsResult(n[1]): result = InitSkippable
|
||||
else: result = InitRequired
|
||||
elif containsResult(n):
|
||||
result = InitRequired
|
||||
else:
|
||||
result = allPathsAsgnResult(p, n[1])
|
||||
of nkReturnStmt:
|
||||
if n.len > 0:
|
||||
if n[0].kind == nkEmpty and result != InitSkippable:
|
||||
@@ -1081,7 +1055,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
# initialized. This avoids cases like #9286 where this heuristic lead to
|
||||
# wrong code being generated.
|
||||
result = InitRequired
|
||||
else: result = allPathsAsgnResult(p, n[0])
|
||||
else: result = allPathsAsgnResult(n[0])
|
||||
of nkIfStmt, nkIfExpr:
|
||||
var exhaustive = false
|
||||
result = InitSkippable
|
||||
@@ -1107,9 +1081,9 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
of nkWhileStmt:
|
||||
# some dubious code can assign the result in the 'while'
|
||||
# condition and that would be fine. Everything else isn't:
|
||||
result = allPathsAsgnResult(p, n[0])
|
||||
result = allPathsAsgnResult(n[0])
|
||||
if result == Unknown:
|
||||
result = allPathsAsgnResult(p, n[1])
|
||||
result = allPathsAsgnResult(n[1])
|
||||
# we cannot assume that the 'while' loop is really executed at least once:
|
||||
if result == InitSkippable: result = Unknown
|
||||
of harmless:
|
||||
@@ -1134,21 +1108,9 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
allPathsInBranch(n[0])
|
||||
for i in 1..<n.len:
|
||||
if n[i].kind == nkFinally:
|
||||
result = allPathsAsgnResult(p, n[i].lastSon)
|
||||
result = allPathsAsgnResult(n[i].lastSon)
|
||||
else:
|
||||
allPathsInBranch(n[i].lastSon)
|
||||
of nkCallKinds:
|
||||
if canRaiseDisp(p, n[0]):
|
||||
result = InitRequired
|
||||
else:
|
||||
for i in 0..<n.safeLen:
|
||||
allPathsInBranch(n[i])
|
||||
of nkRaiseStmt:
|
||||
result = InitRequired
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
# TODO: more checks might need to be covered like overflow, indexDefect etc.
|
||||
# bug #22852
|
||||
result = InitRequired
|
||||
else:
|
||||
for i in 0..<n.safeLen:
|
||||
allPathsInBranch(n[i])
|
||||
@@ -1156,7 +1118,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
result = getTypeDesc(m, prc.loc.t)
|
||||
if prc.typ.callConv == ccClosure:
|
||||
var rettype, params: Rope
|
||||
var rettype, params: Rope = ""
|
||||
var check = initIntSet()
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
result = "$1(*)$2" % [rettype, params]
|
||||
@@ -1174,7 +1136,8 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = newRopeAppender()
|
||||
if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
|
||||
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
|
||||
if isCppMember:
|
||||
genMemberProcHeader(m, prc, header)
|
||||
else:
|
||||
genProcHeader(m, prc, header)
|
||||
@@ -1197,20 +1160,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
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)
|
||||
var a: TLoc
|
||||
initLocExprSingleUse(p, val, a)
|
||||
var a: TLoc = initLocExprSingleUse(p, val)
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
|
||||
else:
|
||||
# declare the result symbol:
|
||||
assignLocalVar(p, resNode)
|
||||
assert(res.loc.r != "")
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
allPathsAsgnResult(p, procBody) == InitSkippable:
|
||||
# In an ideal world the codegen could rely on injectdestructors doing its job properly
|
||||
# and then the analysis step would not be required.
|
||||
discard "result init optimized out"
|
||||
else:
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
elif sfConstructor in prc.flags:
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
@@ -1224,7 +1180,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
# global is either 'nil' or points to valid memory and so the RC operation
|
||||
# succeeds without touching not-initialized memory.
|
||||
if sfNoInit in prc.flags: discard
|
||||
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
|
||||
elif allPathsAsgnResult(procBody) == InitSkippable: discard
|
||||
else:
|
||||
resetLoc(p, res.loc)
|
||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||
@@ -1240,13 +1196,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
|
||||
prc.info = tmpInfo
|
||||
|
||||
var generatedProc: Rope
|
||||
var generatedProc: Rope = ""
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if isNoReturn(p.module, prc):
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
@@ -1291,7 +1247,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return
|
||||
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if sym.itemId.module != m.module.position and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
@@ -1470,17 +1426,21 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
|
||||
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
|
||||
## Returns a mangled module name.
|
||||
result = ""
|
||||
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 = ""
|
||||
result.add mangleModuleName(m.g.config, m.filename).mangle
|
||||
|
||||
proc getSomeInitName(m: BModule, suffix: string): Rope =
|
||||
if not m.hcrOn:
|
||||
result = getSomeNameForModule(m)
|
||||
else:
|
||||
result = ""
|
||||
result.add suffix
|
||||
|
||||
proc getInitName(m: BModule): Rope =
|
||||
@@ -1499,10 +1459,10 @@ proc genMainProc(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var preMainCode: Rope
|
||||
var preMainCode: Rope = ""
|
||||
if m.hcrOn:
|
||||
proc loadLib(handle: string, name: string): Rope =
|
||||
result = ""
|
||||
let prc = magicsys.getCompilerProc(m.g.graph, name)
|
||||
assert prc != nil
|
||||
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
|
||||
@@ -1526,7 +1486,7 @@ proc genMainProc(m: BModule) =
|
||||
else:
|
||||
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
|
||||
|
||||
var posixCmdLine: Rope
|
||||
var posixCmdLine: Rope = ""
|
||||
if optNoMain notin m.config.globalOptions:
|
||||
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
|
||||
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
|
||||
@@ -1810,7 +1770,7 @@ proc genDatInitCode(m: BModule) =
|
||||
|
||||
# we don't want to break into such init code - could happen if a line
|
||||
# directive from a function written by the user spills after itself
|
||||
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
|
||||
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
if m.s[i].len != 0:
|
||||
@@ -1851,7 +1811,7 @@ proc genInitCode(m: BModule) =
|
||||
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
|
||||
# we don't want to break into such init code - could happen if a line
|
||||
# directive from a function written by the user spills after itself
|
||||
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
|
||||
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
|
||||
if m.typeNodes > 0:
|
||||
if m.hcrOn:
|
||||
appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName])
|
||||
@@ -1966,40 +1926,6 @@ proc genInitCode(m: BModule) =
|
||||
|
||||
registerModuleToMain(m.g, m)
|
||||
|
||||
proc postprocessCode(conf: ConfigRef, r: var Rope) =
|
||||
# find the first directive
|
||||
var f = r.find(postprocessDirStart)
|
||||
if f == -1:
|
||||
return
|
||||
|
||||
var
|
||||
nimlnDirLastF = ""
|
||||
|
||||
var res: Rope = r.substr(0, f - 1)
|
||||
while f != -1:
|
||||
var
|
||||
e = r.find(postprocessDirEnd, f + 1)
|
||||
dir = r.substr(f + 1, e - 1).split(postprocessDirSep)
|
||||
case dir[0]
|
||||
of "nimln":
|
||||
if dir[2] == nimlnDirLastF:
|
||||
res.add("nimln_(" & dir[1] & ");")
|
||||
else:
|
||||
res.add("nimlf_(" & dir[1] & ", " & quotedFilename(conf, dir[2].parseInt.FileIndex) & ");")
|
||||
nimlnDirLastF = dir[2]
|
||||
else:
|
||||
raiseAssert "unexpected postprocess directive"
|
||||
|
||||
# find the next directive
|
||||
f = r.find(postprocessDirStart, e + 1)
|
||||
# copy the code until the next directive
|
||||
if f != -1:
|
||||
res.add(r.substr(e + 1, f - 1))
|
||||
else:
|
||||
res.add(r.substr(e + 1))
|
||||
|
||||
r = res
|
||||
|
||||
proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
var moduleIsEmpty = true
|
||||
|
||||
@@ -2028,17 +1954,9 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
if m.config.cppCustomNamespace.len > 0:
|
||||
closeNamespaceNim(result)
|
||||
|
||||
if optLineDir in m.config.options:
|
||||
var srcFileDefs = ""
|
||||
for fi in 0..m.config.m.fileInfos.high:
|
||||
srcFileDefs.add("#define FX_" & $fi & " " & makeSingleLineCString(toFullPath(m.config, fi.FileIndex)) & "\n")
|
||||
result = srcFileDefs & result
|
||||
|
||||
if moduleIsEmpty:
|
||||
result = ""
|
||||
|
||||
postprocessCode(m.config, result)
|
||||
|
||||
proc initProcOptions(m: BModule): TOptions =
|
||||
let opts = m.config.options
|
||||
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
|
||||
@@ -2063,7 +1981,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
result.preInitProc = newProc(nil, result)
|
||||
result.preInitProc.flags.incl nimErrorFlagDisabled
|
||||
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
|
||||
initNodeTable(result.dataCache)
|
||||
result.dataCache = initNodeTable()
|
||||
result.typeStack = @[]
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
@@ -2240,6 +2158,7 @@ proc updateCachedModule(m: BModule) =
|
||||
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
## Also called from IC.
|
||||
result = nil
|
||||
if sfMainModule in m.module.flags:
|
||||
# phase ordering problem here: We need to announce this
|
||||
# dependency to 'nimTestErrorFlag' before system.c has been written to disk.
|
||||
|
||||
@@ -135,7 +135,6 @@ type
|
||||
# unconditionally...
|
||||
# nimtvDeps is VERY hard to cache because it's
|
||||
# not a list of IDs nor can it be made to be one.
|
||||
mangledPrcs*: HashSet[string]
|
||||
|
||||
TCGen = object of PPassContext # represents a C source file
|
||||
s*: TCFileSections # sections of the C file
|
||||
@@ -149,7 +148,7 @@ type
|
||||
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
|
||||
# would be ideal but for some reason enums
|
||||
# don't seem to get cached so it'd generate
|
||||
# 1 ABI check per occurrence in code
|
||||
# 1 ABI check per occurence in code
|
||||
forwTypeCache*: TypeCache # cache for forward declarations of types
|
||||
declaredThings*: IntSet # things we have declared in this .c file
|
||||
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||
|
||||
@@ -44,6 +44,8 @@ proc getDispatcher*(s: PSym): PSym =
|
||||
if dispatcherPos < s.ast.len:
|
||||
result = s.ast[dispatcherPos].sym
|
||||
doAssert sfDispatcher in result.flags
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
result = n
|
||||
@@ -62,6 +64,7 @@ type
|
||||
MethodResult = enum No, Invalid, Yes
|
||||
|
||||
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
|
||||
result = No
|
||||
if a.name.id != b.name.id: return
|
||||
if a.typ.len != b.typ.len:
|
||||
return
|
||||
@@ -95,8 +98,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
|
||||
return No
|
||||
if result == Yes:
|
||||
# check for return type:
|
||||
# ignore flags of return types; # bug #22673
|
||||
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
|
||||
if not sameTypeOrNil(a.typ[0], b.typ[0]):
|
||||
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
|
||||
# infer 'auto' from the base to make it consistent:
|
||||
b.typ[0] = a.typ[0]
|
||||
@@ -150,7 +152,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
|
||||
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
|
||||
|
||||
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
var witness: PSym
|
||||
var witness: PSym = nil
|
||||
for i in 0..<g.methods.len:
|
||||
let disp = g.methods[i].dispatcher
|
||||
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
|
||||
@@ -179,6 +181,7 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
|
||||
proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
result = false
|
||||
var t = methods[0].typ[col].skipTypes(skipPtrs)
|
||||
if t.kind == tyObject:
|
||||
for i in 1..high(methods):
|
||||
@@ -187,6 +190,7 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
result = 0
|
||||
for col in 1..<a.typ.len:
|
||||
if contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ[col], skipPtrs)
|
||||
|
||||
@@ -163,7 +163,7 @@ type
|
||||
|
||||
const
|
||||
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
|
||||
nkCommentStmt, nkMixinStmt, nkBindStmt, nkTypeOfExpr} + procDefs
|
||||
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
|
||||
|
||||
proc newStateAccess(ctx: var Ctx): PNode =
|
||||
if ctx.stateVarSym.isNil:
|
||||
@@ -258,8 +258,9 @@ proc hasYields(n: PNode): bool =
|
||||
of nkYieldStmt:
|
||||
result = true
|
||||
of nkSkip:
|
||||
discard
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYields:
|
||||
result = true
|
||||
@@ -325,7 +326,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
||||
var ifBranch: PNode
|
||||
|
||||
if c.len > 1:
|
||||
var cond: PNode
|
||||
var cond: PNode = nil
|
||||
for i in 0..<c.len - 1:
|
||||
assert(c[i].kind == nkType)
|
||||
let nextCond = newTree(nkCall,
|
||||
@@ -388,19 +389,22 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
|
||||
proc hasYieldsInExpressions(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkSkip:
|
||||
discard
|
||||
result = false
|
||||
of nkStmtListExpr:
|
||||
if isEmptyType(n.typ):
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYieldsInExpressions:
|
||||
return true
|
||||
else:
|
||||
result = n.hasYields
|
||||
of nkCast:
|
||||
result = false
|
||||
for i in 1..<n.len:
|
||||
if n[i].hasYieldsInExpressions:
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYieldsInExpressions:
|
||||
return true
|
||||
@@ -495,7 +499,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
|
||||
if ns:
|
||||
needsSplit = true
|
||||
var tmp: PSym
|
||||
var tmp: PSym = nil
|
||||
let isExpr = not isEmptyType(n.typ)
|
||||
if isExpr:
|
||||
tmp = ctx.newTempVar(n.typ)
|
||||
@@ -1361,6 +1365,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
|
||||
else:
|
||||
result.add it
|
||||
of nkRaiseStmt:
|
||||
result = nil
|
||||
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
|
||||
else:
|
||||
result = n
|
||||
|
||||
@@ -55,11 +55,6 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
if conf.cmd == cmdNimscript:
|
||||
incl(conf.globalOptions, optWasNimscript)
|
||||
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
|
||||
# restores `conf.notes` after loading config files
|
||||
# because it has overwrites the notes when compiling the system module which
|
||||
# is a foreign module compared to the project
|
||||
if conf.cmd in cmdBackends:
|
||||
conf.notes = conf.mainPackageNotes
|
||||
|
||||
if not self.suggestMode:
|
||||
let scriptFile = conf.projectFull.changeFileExt("nims")
|
||||
|
||||
@@ -184,7 +184,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string; conf: ConfigRef) =
|
||||
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
|
||||
var i = 0
|
||||
var notes: set[TMsgKind]
|
||||
var notes: set[TMsgKind] = {}
|
||||
var isBracket = false
|
||||
if i < arg.len and arg[i] == '[':
|
||||
isBracket = true
|
||||
@@ -205,11 +205,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
|
||||
let x = findStr(noteMin, noteMax, id, errUnknown)
|
||||
if x != errUnknown: notes = {TNoteKind(x)}
|
||||
else:
|
||||
if isSomeHint:
|
||||
message(conf, info, hintUnknownHint, id)
|
||||
else:
|
||||
localError(conf, info, "unknown $#: $#" % [name, id])
|
||||
else: localError(conf, info, "unknown $#: $#" % [name, id])
|
||||
case id.normalize
|
||||
of "all": # other note groups would be easy to support via additional cases
|
||||
notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}
|
||||
@@ -267,13 +263,17 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "none": result = conf.selectedGC == gcNone
|
||||
of "stack", "regions": result = conf.selectedGC == gcRegions
|
||||
of "atomicarc": result = conf.selectedGC == gcAtomicArc
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
of "opt":
|
||||
case arg.normalize
|
||||
of "speed": result = contains(conf.options, optOptimizeSpeed)
|
||||
of "size": result = contains(conf.options, optOptimizeSize)
|
||||
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||
of "verbosity": result = $conf.verbosity == arg
|
||||
of "app":
|
||||
case arg.normalize
|
||||
@@ -283,7 +283,9 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
not contains(conf.globalOptions, optGenGuiApp)
|
||||
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
|
||||
not contains(conf.globalOptions, optGenGuiApp)
|
||||
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||
of "dynliboverride":
|
||||
result = isDynlibOverride(conf, arg)
|
||||
of "exceptions":
|
||||
@@ -292,8 +294,12 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "setjmp": result = conf.exc == excSetjmp
|
||||
of "quirky": result = conf.exc == excQuirky
|
||||
of "goto": result = conf.exc == excGoto
|
||||
else: localError(conf, info, errInvalidExceptionSystem % arg)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errInvalidExceptionSystem % arg)
|
||||
else:
|
||||
result = false
|
||||
invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
|
||||
case switch.normalize
|
||||
@@ -339,10 +345,14 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
|
||||
result = contains(conf.options, optTrMacros)
|
||||
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
||||
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
|
||||
of "nilseqs", "nilchecks", "taintmode":
|
||||
warningOptionNoop(switch)
|
||||
result = false
|
||||
of "panics": result = contains(conf.globalOptions, optPanics)
|
||||
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
else:
|
||||
result = false
|
||||
invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||
notRelativeToProj = false): AbsoluteDir =
|
||||
@@ -384,7 +394,8 @@ proc makeAbsolute(s: string): AbsoluteFile =
|
||||
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
|
||||
info: TLineInfo) =
|
||||
## set tracking info, common code for track, trackDirty, & ideTrack
|
||||
var ln, col: int
|
||||
var ln: int = 0
|
||||
var col: int = 0
|
||||
if parseUtils.parseInt(line, ln) <= 0:
|
||||
localError(conf, info, errInvalidNumber % line)
|
||||
if parseUtils.parseInt(column, col) <= 0:
|
||||
@@ -595,8 +606,8 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf: ConfigRef) =
|
||||
var
|
||||
key, val: string
|
||||
var key = ""
|
||||
var val = ""
|
||||
case switch.normalize
|
||||
of "eval":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
@@ -611,8 +622,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
for path in nimbleSubs(conf, arg):
|
||||
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
|
||||
else: processPath(conf, path, info), info)
|
||||
of "nimblepath", "babelpath":
|
||||
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
|
||||
of "nimblepath":
|
||||
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
var path = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
@@ -622,8 +632,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
nimblePath(conf, path, info)
|
||||
path = nimbleDir / RelativeDir"pkgs"
|
||||
nimblePath(conf, path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
|
||||
of "nonimblepath":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
disableNimblePath(conf)
|
||||
of "clearnimblepath":
|
||||
@@ -1113,7 +1122,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
|
||||
var cmd, arg: string
|
||||
var cmd = ""
|
||||
var arg = ""
|
||||
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
|
||||
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
|
||||
|
||||
@@ -1140,7 +1150,10 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
config.arguments = cmdLineRest(p)
|
||||
result = true
|
||||
elif pass != passCmd2: setCommandEarly(config, p.key)
|
||||
elif pass != passCmd2:
|
||||
setCommandEarly(config, p.key)
|
||||
result = false
|
||||
else: result = false
|
||||
else:
|
||||
if pass == passCmd1: config.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
@@ -1151,4 +1164,6 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
config.arguments = cmdLineRest(p)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
inc argsCount
|
||||
|
||||
@@ -121,8 +121,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
for i in 0..<a.len:
|
||||
if not matchType(c, f[i], a[i], m): return false
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of tyGenericInvocation:
|
||||
result = false
|
||||
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
|
||||
if sameType(f[0], a[0]) and f.len == a.len-1:
|
||||
for i in 1 ..< f.len:
|
||||
@@ -156,15 +159,17 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
result = matchType(c, old, ak, m)
|
||||
if m.magic == mArrPut and ak.kind == tyGenericParam:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
|
||||
|
||||
of tyVar, tySink, tyLent, tyOwned:
|
||||
# modifiers in the concept must be there in the actual implementation
|
||||
# too but not vice versa.
|
||||
if a.kind == f.kind:
|
||||
result = matchType(c, f.sons[0], a.sons[0], m)
|
||||
result = matchType(c, f[0], a[0], m)
|
||||
elif m.magic == mArrPut:
|
||||
result = matchType(c, f.sons[0], a, m)
|
||||
result = matchType(c, f[0], a, m)
|
||||
else:
|
||||
result = false
|
||||
of tyEnum, tyObject, tyDistinct:
|
||||
@@ -185,6 +190,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
m.inferred.setLen oldLen
|
||||
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
|
||||
tyGenericInst:
|
||||
result = false
|
||||
let ak = a.skipTypes(ignorableForArgType - {f.kind})
|
||||
if ak.kind == f.kind and f.len == ak.len:
|
||||
for i in 0..<ak.len:
|
||||
@@ -209,6 +215,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
if not result:
|
||||
m.inferred.setLen oldLen
|
||||
else:
|
||||
result = false
|
||||
for i in 0..<f.len:
|
||||
result = matchType(c, f[i], a, m)
|
||||
if result: break # and remember the binding!
|
||||
@@ -257,7 +264,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
|
||||
m.inferred.setLen oldLen
|
||||
return false
|
||||
|
||||
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
|
||||
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
|
||||
m.inferred.setLen oldLen
|
||||
return false
|
||||
|
||||
@@ -314,7 +321,7 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
|
||||
|
||||
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TIdTable; invocation: PType): bool =
|
||||
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
|
||||
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
|
||||
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fullfill the
|
||||
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
|
||||
## (typeVar, instance) pairs. ('typeVar' is usually simply written as a generic 'T'.)
|
||||
## 'invocation' can be nil for atomic concepts. For non-atomic concepts, it contains the
|
||||
|
||||
@@ -143,6 +143,7 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||
defineSymbol("nimHasCstringCase")
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
defineSymbol("nimHasWarnCastSizes") # deadcode
|
||||
defineSymbol("nimHasOutParams")
|
||||
@@ -157,9 +158,6 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimAllowNonVarDestructor")
|
||||
defineSymbol("nimHasQuirky")
|
||||
defineSymbol("nimHasEnsureMove")
|
||||
defineSymbol("nimHasNoReturnError")
|
||||
|
||||
defineSymbol("nimHasCastExtendedVm")
|
||||
defineSymbol("nimHasGenericsOpenSym2")
|
||||
defineSymbol("nimUseStrictDefs")
|
||||
defineSymbol("nimHasNolineTooLong")
|
||||
defineSymbol("nimHasGenericsOpenSym3")
|
||||
|
||||
@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
let sub = "lib/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
else:
|
||||
start += sub.len
|
||||
let base = s[start..^1]
|
||||
@@ -105,11 +105,6 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
g.config = graph.config
|
||||
g.graph = graph
|
||||
result = PGen(module: module, config: graph.config, graph: graph)
|
||||
if graph.backend == nil:
|
||||
graph.backend = Backend(dotGraph: "")
|
||||
result = g
|
||||
|
||||
@@ -60,6 +60,7 @@ type
|
||||
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
|
||||
# for debugging purposes
|
||||
# first iteration: compute all necessary labels:
|
||||
result = ""
|
||||
var jumpTargets = initIntSet()
|
||||
let last = if last < 0: c.len-1 else: min(last, c.len-1)
|
||||
for i in start..last:
|
||||
@@ -111,7 +112,7 @@ proc patch(c: var Con, p: TPosition) =
|
||||
proc gen(c: var Con; n: PNode)
|
||||
|
||||
proc popBlock(c: var Con; oldLen: int) =
|
||||
var exits: seq[TPosition]
|
||||
var exits: seq[TPosition] = @[]
|
||||
exits.add c.gotoI()
|
||||
for f in c.blocks[oldLen].breakFixups:
|
||||
c.patch(f[0])
|
||||
@@ -263,7 +264,7 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
|
||||
if c.blocks[i].isTryBlock:
|
||||
c.blocks[i].raiseFixups.add lab1
|
||||
else:
|
||||
var trailingFinales: seq[PNode]
|
||||
var trailingFinales: seq[PNode] = @[]
|
||||
if c.inTryStmt > 0:
|
||||
# Ok, we are in a try, lets see which (if any) try's we break out from:
|
||||
for b in countdown(c.blocks.high, i):
|
||||
@@ -469,7 +470,7 @@ proc gen(c: var Con; n: PNode) =
|
||||
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
|
||||
gen(c, n[1])
|
||||
of nkVarSection, nkLetSection: genVarSection(c, n)
|
||||
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
|
||||
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
|
||||
else: discard
|
||||
|
||||
when false:
|
||||
|
||||
@@ -170,6 +170,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
|
||||
|
||||
proc prettyString(a: object): string =
|
||||
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
|
||||
result = ""
|
||||
for k, v in fieldPairs(a):
|
||||
result.add k & ": " & $v & "\n"
|
||||
|
||||
@@ -215,12 +216,16 @@ proc whichType(d: PDoc; n: PNode): PSym =
|
||||
if n.kind == nkSym:
|
||||
if d.types.strTableContains(n.sym):
|
||||
result = n.sym
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
for i in 0..<n.safeLen:
|
||||
let x = whichType(d, n[i])
|
||||
if x != nil: return x
|
||||
|
||||
proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
result = nil
|
||||
let params = p.ast[paramsPos]
|
||||
template check(i) =
|
||||
result = whichType(d, params[i])
|
||||
@@ -343,7 +348,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics") and
|
||||
conf.configVars.hasKey("doc.plausibleAnalytics"):
|
||||
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
|
||||
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics"):
|
||||
result.analytics = """
|
||||
@@ -368,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
result.jEntriesFinal = newJArray()
|
||||
initStrTable result.types
|
||||
result.types = initStrTable()
|
||||
result.onTestSnippet =
|
||||
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
|
||||
if conf.docCmd == docCmdSkip: return
|
||||
@@ -435,6 +440,8 @@ proc genComment(d: PDoc, n: PNode): PRstNode =
|
||||
d.conf, d.sharedState)
|
||||
except ERecoverableError:
|
||||
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
|
||||
if n == nil: return nil
|
||||
@@ -469,6 +476,7 @@ proc getPlainDocstring(n: PNode): string =
|
||||
elif startsWith(n.comment, "##"):
|
||||
result = n.comment
|
||||
else:
|
||||
result = ""
|
||||
for i in 0..<n.safeLen:
|
||||
result = getPlainDocstring(n[i])
|
||||
if result.len > 0: return
|
||||
@@ -484,9 +492,8 @@ proc externalDep(d: PDoc; module: PSym): string =
|
||||
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
|
||||
renderFlags: TRenderFlags = {};
|
||||
procLink: string) =
|
||||
var r: TSrcGen
|
||||
var r: TSrcGen = initTokRender(n, renderFlags)
|
||||
var literal = ""
|
||||
initTokRender(r, n, renderFlags)
|
||||
var kind = tkEof
|
||||
var tokenPos = 0
|
||||
var procTokenPos = 0
|
||||
@@ -600,7 +607,9 @@ proc runAllExamples(d: PDoc) =
|
||||
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
|
||||
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
|
||||
|
||||
proc quoted(a: string): string = result.addQuoted(a)
|
||||
proc quoted(a: string): string =
|
||||
result = ""
|
||||
result.addQuoted(a)
|
||||
|
||||
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
|
||||
# xxx expose in compiler/lineinfos.nim
|
||||
@@ -726,7 +735,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
|
||||
let (rdoccmd, code) = prepareExample(d, n, topLevel)
|
||||
var msg = "Example:"
|
||||
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
|
||||
var s: string
|
||||
var s: string = ""
|
||||
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
|
||||
"\n\n\\textbf{$1}\n", [msg])
|
||||
dest.add s
|
||||
@@ -821,7 +830,7 @@ proc getName(n: PNode): string =
|
||||
result = "`"
|
||||
for i in 0..<n.len: result.add(getName(n[i]))
|
||||
result = "`"
|
||||
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getName(n[0])
|
||||
else:
|
||||
result = ""
|
||||
@@ -839,7 +848,7 @@ proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
|
||||
var r = ""
|
||||
for i in 0..<n.len: r.add(getNameIdent(cache, n[i]).s)
|
||||
result = getIdent(cache, r)
|
||||
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getNameIdent(cache, n[0])
|
||||
else:
|
||||
result = nil
|
||||
@@ -853,7 +862,7 @@ proc getRstName(n: PNode): PRstNode =
|
||||
of nkAccQuoted:
|
||||
result = getRstName(n[0])
|
||||
for i in 1..<n.len: result.text.add(getRstName(n[i]).text)
|
||||
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getRstName(n[0])
|
||||
else:
|
||||
result = nil
|
||||
@@ -942,14 +951,17 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
|
||||
if n[1].kind in {nkStrLit..nkTripleStrLit}:
|
||||
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
|
||||
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
|
||||
else:
|
||||
result = ""
|
||||
else:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
|
||||
type DocFlags = enum
|
||||
kDefault
|
||||
kForceExport
|
||||
|
||||
proc genSeeSrc(d: PDoc, path: string, line: int): string =
|
||||
result = ""
|
||||
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0:
|
||||
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
|
||||
@@ -991,7 +1003,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
result.symKind = k.toHumanStr
|
||||
if k in routineKinds:
|
||||
var
|
||||
paramTypes: seq[string]
|
||||
paramTypes: seq[string] = @[]
|
||||
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
|
||||
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
|
||||
# In some rare cases (system.typeof) parameter type is not set for default:
|
||||
@@ -1016,8 +1028,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
genNode = n[miscPos][1] # FIXME: what is index 1?
|
||||
if genNode != nil:
|
||||
var literal = ""
|
||||
var r: TSrcGen
|
||||
initTokRender(r, genNode, {renderNoBody, renderNoComments,
|
||||
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
var kind = tkEof
|
||||
while true:
|
||||
@@ -1038,15 +1049,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
var result = ""
|
||||
var literal, plainName = ""
|
||||
var kind = tkEof
|
||||
var comm: ItemPre
|
||||
var comm: ItemPre = default(ItemPre)
|
||||
if n.kind in routineDefs:
|
||||
getAllRunnableExamples(d, n, comm)
|
||||
else:
|
||||
comm.add genRecComment(d, n)
|
||||
|
||||
var r: TSrcGen
|
||||
# Obtain the plain rendered string for hyperlink titles.
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
@@ -1154,7 +1164,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
|
||||
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
|
||||
if nonExports:
|
||||
renderFlags.incl renderNonExportedFields
|
||||
initTokRender(r, n, renderFlags)
|
||||
r = initTokRender(n, renderFlags)
|
||||
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm != nil:
|
||||
@@ -1186,9 +1196,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
|
||||
result.json["signature"]["genericParams"] = newJArray()
|
||||
for genericParam in n[genericParamsPos]:
|
||||
var param = %{"name": %($genericParam)}
|
||||
if genericParam.sym.typ.sons.len > 0:
|
||||
if genericParam.sym.typ.len > 0:
|
||||
param["types"] = newJArray()
|
||||
for kind in genericParam.sym.typ.sons:
|
||||
for kind in genericParam.sym.typ:
|
||||
param["types"].add %($kind)
|
||||
result.json["signature"]["genericParams"].add param
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
@@ -1283,6 +1293,8 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
|
||||
let s = n[namePos].sym
|
||||
if tfReturnsNew in s.typ.flags:
|
||||
result = newIdentNode(getIdent(cache, "new"), n.info)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
|
||||
let spec = effectSpec(x, effectType)
|
||||
@@ -1305,6 +1317,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
|
||||
|
||||
result = newTreeI(nkExprColonExpr, n.info,
|
||||
newIdentNode(getIdent(cache, $effectType), n.info), effects)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
|
||||
let s = n[namePos].sym
|
||||
@@ -1318,6 +1332,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
|
||||
if effects.len > 0:
|
||||
result = newTreeI(nkExprColonExpr, n.info,
|
||||
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentRaises*(cache: IdentCache; n: PNode) =
|
||||
if n[namePos].kind != nkSym: return
|
||||
@@ -1391,7 +1407,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
|
||||
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
|
||||
of nkCallKinds:
|
||||
var comm: ItemPre
|
||||
var comm: ItemPre = default(ItemPre)
|
||||
getAllRunnableExamples(d, n, comm)
|
||||
if comm.len != 0: d.modDescPre.add(comm)
|
||||
else: discard
|
||||
@@ -1500,7 +1516,7 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
overloadChoices.sort(cmp)
|
||||
var nameContent = ""
|
||||
for item in overloadChoices:
|
||||
var itemDesc: string
|
||||
var itemDesc: string = ""
|
||||
renderItemPre(d, item.descRst, itemDesc)
|
||||
nameContent.add(
|
||||
getConfigVar(d.conf, "doc.item") % (
|
||||
@@ -1526,7 +1542,7 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
for i, entry in d.jEntriesPre:
|
||||
if entry.rst != nil:
|
||||
let resolved = resolveSubs(d.sharedState, entry.rst)
|
||||
var str: string
|
||||
var str: string = ""
|
||||
renderRstToOut(d[], resolved, str)
|
||||
entry.json[entry.rstField] = %str
|
||||
d.jEntriesPre[i].rst = nil
|
||||
@@ -1641,7 +1657,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
|
||||
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
|
||||
var overloadChoices = d.tocTable[kind][plainName]
|
||||
overloadChoices.sort(cmp)
|
||||
var content: string
|
||||
var content: string = ""
|
||||
for item in overloadChoices:
|
||||
content.add item.content
|
||||
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
|
||||
@@ -1672,7 +1688,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
|
||||
|
||||
proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
var
|
||||
code, content: string
|
||||
code, content: string = ""
|
||||
title = ""
|
||||
var j = 0
|
||||
var toc = ""
|
||||
@@ -1781,7 +1797,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
|
||||
|
||||
proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
runAllExamples(d)
|
||||
var modDesc: string
|
||||
var modDesc: string = ""
|
||||
for desc in d.modDescFinal:
|
||||
modDesc &= desc
|
||||
let content = %*{"orig": d.filename,
|
||||
@@ -1793,7 +1809,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
else:
|
||||
let dir = d.destFile.splitFile.dir
|
||||
createDir(dir)
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, d.destFile, fmWrite):
|
||||
write(f, $content)
|
||||
close(f)
|
||||
|
||||
@@ -39,10 +39,12 @@ template closeImpl(body: untyped) {.dirty.} =
|
||||
discard
|
||||
|
||||
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
result = nil
|
||||
closeImpl:
|
||||
writeOutput(g.doc, useWarning, groupedToc)
|
||||
|
||||
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
result = nil
|
||||
closeImpl:
|
||||
writeOutputJson(g.doc, useWarning)
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
|
||||
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
|
||||
result = obj
|
||||
else:
|
||||
result = nil
|
||||
for x in obj:
|
||||
result = searchObjCaseImpl(x, field)
|
||||
if result != nil: break
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import ast, types, options, tables, dynlib, msgs, lineinfos
|
||||
from os import getAppFilename
|
||||
import pkg/libffi
|
||||
import libffi/libffi
|
||||
|
||||
when defined(windows):
|
||||
const libcDll = "msvcrt.dll"
|
||||
@@ -37,9 +37,10 @@ else:
|
||||
var gExeHandle = loadLib()
|
||||
|
||||
proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer =
|
||||
result = nil
|
||||
if dll in cache:
|
||||
return cache[dll]
|
||||
var libs: seq[string]
|
||||
var libs: seq[string] = @[]
|
||||
libCandidates(dll, libs)
|
||||
for c in libs:
|
||||
result = loadLib(c)
|
||||
@@ -61,7 +62,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||
let lib = sym.annex
|
||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
globalError(conf, sym.info, "dynlib needs to be a string lit")
|
||||
var theAddr: pointer
|
||||
var theAddr: pointer = nil
|
||||
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
|
||||
libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll
|
||||
# first try this exe itself:
|
||||
@@ -108,6 +109,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
|
||||
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
|
||||
of ccCDecl: result = DEFAULT_ABI
|
||||
else:
|
||||
result = default(TABI)
|
||||
globalError(conf, info, "cannot map calling convention to FFI")
|
||||
|
||||
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
|
||||
@@ -132,6 +134,8 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
|
||||
result = sizeof(pointer)
|
||||
elif v.len != 0:
|
||||
result = v.len * packSize(conf, v[0], typ[1])
|
||||
else:
|
||||
result = 0
|
||||
else:
|
||||
result = getSize(conf, typ).int
|
||||
|
||||
@@ -140,6 +144,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
|
||||
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
result = getField(conf, n[i], position)
|
||||
if result != nil: return
|
||||
@@ -154,7 +159,8 @@ proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
|
||||
else: internalError(conf, n.info, "getField(record case branch)")
|
||||
of nkSym:
|
||||
if n.sym.position == position: result = n.sym
|
||||
else: discard
|
||||
else: result = nil
|
||||
else: result = nil
|
||||
|
||||
proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
|
||||
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
|
||||
@@ -356,6 +362,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
|
||||
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
|
||||
else:
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
of tyFloat: awf(nkFloatLit, rd(float, x))
|
||||
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
|
||||
@@ -381,6 +388,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
n[0] = unpack(conf, p, typ.lastSon, n[0])
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
of tyObject, tyTuple:
|
||||
result = unpackObject(conf, x, typ, n)
|
||||
@@ -398,6 +406,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
result = unpack(conf, x, typ.lastSon, n)
|
||||
else:
|
||||
# XXX what to do with 'array' here?
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
|
||||
proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
|
||||
@@ -423,7 +432,7 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
|
||||
proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
|
||||
internalAssert conf, call[0].kind == nkPtrLit
|
||||
|
||||
var cif: TCif = default(TCif)
|
||||
var cif: TCif
|
||||
var sig: ParamList = default(ParamList)
|
||||
# use the arguments' types for varargs support:
|
||||
for i in 1..<call.len:
|
||||
@@ -436,7 +445,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
|
||||
mapType(conf, typ[0]), sig) != OK:
|
||||
globalError(conf, call.info, "error in FFI call")
|
||||
|
||||
var args: ArgList
|
||||
var args: ArgList = default(ArgList)
|
||||
let fn = cast[pointer](call[0].intVal)
|
||||
for i in 1..<call.len:
|
||||
var t = call[i].typ
|
||||
@@ -463,7 +472,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
info: TLineInfo): PNode =
|
||||
internalAssert conf, fn.kind == nkPtrLit
|
||||
|
||||
var cif: TCif = default(TCif)
|
||||
var cif: TCif
|
||||
var sig: ParamList = default(ParamList)
|
||||
for i in 0..len-1:
|
||||
var aTyp = args[i+start].typ
|
||||
@@ -478,7 +487,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
mapType(conf, fntyp[0]), sig) != OK:
|
||||
globalError(conf, info, "error in FFI call")
|
||||
|
||||
var cargs: ArgList
|
||||
var cargs: ArgList = default(ArgList)
|
||||
let fn = cast[pointer](fn.intVal)
|
||||
for i in 0..len-1:
|
||||
let t = args[i+start].typ
|
||||
|
||||
@@ -56,7 +56,6 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
# internalAssert c.config, false
|
||||
idTablePut(c.mapping, s, x)
|
||||
if sfGenSym in s.flags:
|
||||
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
|
||||
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
|
||||
if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
@@ -188,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
ctx.genSymOwner = genSymOwner
|
||||
ctx.config = conf
|
||||
ctx.ic = ic
|
||||
initIdTable(ctx.mapping)
|
||||
ctx.mapping = initIdTable()
|
||||
ctx.instID = instID[]
|
||||
ctx.idgen = idgen
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, suga
|
||||
import std / strutils except addf
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
import std/syncio
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
@@ -33,7 +33,6 @@ type
|
||||
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
|
||||
hasDeclspec, # CC has __declspec(X)
|
||||
hasAttribute, # CC has __attribute__((X))
|
||||
hasBuiltinUnreachable # CC has __builtin_unreachable
|
||||
TInfoCCProps* = set[TInfoCCProp]
|
||||
TInfoCC* = tuple[
|
||||
name: string, # the short name of the compiler
|
||||
@@ -96,7 +95,7 @@ compiler gcc:
|
||||
produceAsm: gnuAsmListing,
|
||||
cppXsupport: "-std=gnu++17 -funsigned-char",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasAttribute, hasBuiltinUnreachable})
|
||||
hasAttribute})
|
||||
|
||||
# GNU C and C++ Compiler
|
||||
compiler nintendoSwitchGCC:
|
||||
@@ -123,7 +122,7 @@ compiler nintendoSwitchGCC:
|
||||
produceAsm: gnuAsmListing,
|
||||
cppXsupport: "-std=gnu++17 -funsigned-char",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasAttribute, hasBuiltinUnreachable})
|
||||
hasAttribute})
|
||||
|
||||
# LLVM Frontend for GCC/G++
|
||||
compiler llvmGcc:
|
||||
@@ -452,11 +451,6 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
|
||||
proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string =
|
||||
result = conf.compileOptions
|
||||
|
||||
if (conf.cCompiler == ccGcc or conf.cCompiler == ccCLang) and
|
||||
conf.selectedGC == gcRefc:
|
||||
# bug #10625
|
||||
addOpt(result, "-fno-omit-frame-pointer")
|
||||
|
||||
for option in conf.compileOptionsCmd:
|
||||
if strutils.find(result, option, 0) < 0:
|
||||
addOpt(result, option)
|
||||
@@ -492,6 +486,10 @@ proc vccplatform(conf: ConfigRef): string =
|
||||
of cpuArm: " --platform:arm"
|
||||
of cpuAmd64: " --platform:amd64"
|
||||
else: ""
|
||||
else:
|
||||
result = ""
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc getLinkOptions(conf: ConfigRef): string =
|
||||
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
|
||||
@@ -540,7 +538,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
|
||||
# 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 major: int
|
||||
var major: int = 0
|
||||
discard parseInt(s, major)
|
||||
result = major >= 5
|
||||
else:
|
||||
@@ -650,7 +648,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
|
||||
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
|
||||
let currentHash = footprint(conf, cfile)
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, hashFile.string, fmRead):
|
||||
let oldHash = parseSecureHash(f.readLine())
|
||||
close(f)
|
||||
@@ -785,6 +783,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
|
||||
raise
|
||||
|
||||
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
|
||||
result = @[]
|
||||
when defined(macosx):
|
||||
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
|
||||
# if needed, add an option to skip or override location
|
||||
@@ -867,6 +866,7 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
|
||||
result = conf.getNimcacheDir / RelativeFile(targetName)
|
||||
|
||||
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
|
||||
result = ""
|
||||
if conf.hasHint(hintCC):
|
||||
if optListCmd in conf.globalOptions or conf.verbosity > 1:
|
||||
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
|
||||
@@ -889,15 +889,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef) =
|
||||
var
|
||||
linkCmd: string
|
||||
linkCmd: string = ""
|
||||
extraCmds: seq[string]
|
||||
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
return # speed up that call if only compiling and no script shall be
|
||||
# generated
|
||||
#var c = cCompiler
|
||||
var script: Rope = ""
|
||||
var cmds: TStringSeq
|
||||
var prettyCmds: TStringSeq
|
||||
var cmds: TStringSeq = default(TStringSeq)
|
||||
var prettyCmds: TStringSeq = default(TStringSeq)
|
||||
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
|
||||
|
||||
for idx, it in conf.toCompile:
|
||||
@@ -998,7 +998,7 @@ type BuildCache = object
|
||||
depfiles: seq[(string, string)]
|
||||
nimexe: string
|
||||
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
var linkFiles = collect(for it in conf.externalToLink:
|
||||
var it = it
|
||||
if conf.noAbsolutePaths: it = it.extractFilename
|
||||
@@ -1019,21 +1019,18 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
|
||||
currentDir: getCurrentDir())
|
||||
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
|
||||
bcache.cmdline = conf.commandLine
|
||||
for it in conf.m.fileInfos:
|
||||
bcache.depfiles = collect(for it in conf.m.fileInfos:
|
||||
let path = it.fullPath.string
|
||||
if isAbsolute(path): # TODO: else?
|
||||
if path in deps:
|
||||
bcache.depfiles.add (path, deps[path])
|
||||
else: # backup for configs etc.
|
||||
bcache.depfiles.add (path, $secureHashFile(path))
|
||||
|
||||
(path, $secureHashFile(path)))
|
||||
bcache.nimexe = hashNimExe()
|
||||
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
|
||||
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
|
||||
|
||||
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
|
||||
result = false
|
||||
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
|
||||
var bcache: BuildCache
|
||||
var bcache: BuildCache = default(BuildCache)
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except IOError, OSError, ValueError:
|
||||
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
|
||||
@@ -1049,7 +1046,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
|
||||
if $secureHashFile(file) != hash: return true
|
||||
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
var bcache: BuildCache
|
||||
var bcache: BuildCache = default(BuildCache)
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except ValueError, KeyError, JsonKindError:
|
||||
let e = getCurrentException()
|
||||
@@ -1062,7 +1059,8 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
globalError(conf, gCmdLineInfo,
|
||||
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
|
||||
[outputCurrent, output, jsonFile.string])
|
||||
var cmds, prettyCmds: TStringSeq
|
||||
var cmds: TStringSeq = default(TStringSeq)
|
||||
var prettyCmds: TStringSeq= default(TStringSeq)
|
||||
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
|
||||
for (name, cmd) in bcache.compile:
|
||||
cmds.add cmd
|
||||
@@ -1072,6 +1070,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
|
||||
|
||||
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
|
||||
result = ""
|
||||
for it in list:
|
||||
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])
|
||||
|
||||
|
||||
@@ -201,17 +201,15 @@ proc parseLine(p: var TTmplParser) =
|
||||
|
||||
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
|
||||
call: PNode): PLLStream =
|
||||
var p: TTmplParser
|
||||
p.config = conf
|
||||
p.info = newLineInfo(conf, filename, 0, 0)
|
||||
p.outp = llStreamOpen("")
|
||||
p.inp = stdin
|
||||
p.subsChar = charArg(conf, call, "subschar", 1, '$')
|
||||
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
|
||||
p.emit = strArg(conf, call, "emit", 3, "result.add")
|
||||
p.conc = strArg(conf, call, "conc", 4, " & ")
|
||||
p.toStr = strArg(conf, call, "tostring", 5, "$")
|
||||
p.x = newStringOfCap(120)
|
||||
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
|
||||
outp: llStreamOpen(""), inp: stdin,
|
||||
subsChar: charArg(conf, call, "subschar", 1, '$'),
|
||||
nimDirective: charArg(conf, call, "metachar", 2, '#'),
|
||||
emit: strArg(conf, call, "emit", 3, "result.add"),
|
||||
conc: strArg(conf, call, "conc", 4, " & "),
|
||||
toStr: strArg(conf, call, "tostring", 5, "$"),
|
||||
x: newStringOfCap(120)
|
||||
)
|
||||
# do not process the first line which contains the directive:
|
||||
if llStreamReadLine(p.inp, p.x):
|
||||
inc p.info.line
|
||||
|
||||
@@ -29,23 +29,30 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
|
||||
return n[i]
|
||||
|
||||
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
|
||||
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkCharLit: result = chr(int(x.intVal))
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = default(char)
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = ""
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
|
||||
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = false
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
|
||||
var pattern = strArg(conf, call, "startswith", 1, "")
|
||||
|
||||
@@ -29,10 +29,11 @@ proc readOutput(p: Process): (string, int) =
|
||||
|
||||
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
|
||||
let workingDir = parentDir(toFullPath(conf, info))
|
||||
result = ("", 0)
|
||||
if cache.len > 0:
|
||||
let h = secureHash(cmd & "\t" & input & "\t" & cache)
|
||||
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if optForceFullMake notin conf.globalOptions and open(f, filename):
|
||||
result = (f.readAll, 0)
|
||||
f.close
|
||||
|
||||
@@ -51,6 +51,10 @@ proc isLet(n: PNode): bool =
|
||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||
abstractInst).kind notin {tyVar}:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isVar(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
|
||||
@@ -136,6 +140,8 @@ proc neg(n: PNode; o: Operators): PNode =
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
# leave not (a == 4) as it is
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
@@ -330,6 +336,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result = n
|
||||
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of someLe+someLt:
|
||||
if isLetLocation(n[1], true) or isLetLocation(n[2], true):
|
||||
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
|
||||
@@ -337,12 +345,18 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
|
||||
# XXX Rethink this whole idea of 'usefulFact' for semparallel
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of mIsNil:
|
||||
if isLetLocation(n[1], false) or isVar(n[1]):
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of someIn:
|
||||
if isLetLocation(n[1], true):
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of mAnd:
|
||||
let
|
||||
a = usefulFact(n[1], o)
|
||||
@@ -356,10 +370,14 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
else:
|
||||
result = nil
|
||||
of mNot:
|
||||
let a = usefulFact(n[1], o)
|
||||
if a != nil:
|
||||
result = a.neg(o)
|
||||
else:
|
||||
result = nil
|
||||
of mOr:
|
||||
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
|
||||
# with that knowledge...
|
||||
@@ -376,6 +394,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result[1] = a
|
||||
result[2] = b
|
||||
result = result.neg(o)
|
||||
else:
|
||||
result = nil
|
||||
elif n.kind == nkSym and n.sym.kind == skLet:
|
||||
# consider:
|
||||
# let a = 2 < x
|
||||
@@ -384,8 +404,12 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
# We make can easily replace 'a' by '2 < x' here:
|
||||
if n.sym.astdef != nil:
|
||||
result = usefulFact(n.sym.astdef, o)
|
||||
else:
|
||||
result = nil
|
||||
elif n.kind == nkStmtListExpr:
|
||||
result = usefulFact(n.lastSon, o)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
type
|
||||
TModel* = object
|
||||
@@ -451,8 +475,9 @@ proc hasSubTree(n, x: PNode): bool =
|
||||
of nkEmpty..nkNilLit:
|
||||
result = n.sameTree(x)
|
||||
of nkFormalParams:
|
||||
discard
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
for i in 0..<n.len:
|
||||
if hasSubTree(n[i], x): return true
|
||||
|
||||
@@ -483,6 +508,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
|
||||
proc valuesUnequal(a, b: PNode): bool =
|
||||
if a.isValue and b.isValue:
|
||||
result = not sameValue(a, b)
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc impliesEq(fact, eq: PNode): TImplication =
|
||||
let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
|
||||
@@ -493,16 +520,26 @@ proc impliesEq(fact, eq: PNode): TImplication =
|
||||
# this is not correct; consider: a == b; a == 1 --> unknown!
|
||||
if sameTree(fact[2], eq[val]): result = impYes
|
||||
elif valuesUnequal(fact[2], eq[val]): result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], eq[loc]):
|
||||
if sameTree(fact[1], eq[val]): result = impYes
|
||||
elif valuesUnequal(fact[1], eq[val]): result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of mInSet:
|
||||
# remember: mInSet is 'contains' so the set comes first!
|
||||
if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
|
||||
if inSet(fact[1], eq[val]): result = impYes
|
||||
else: result = impNo
|
||||
of mNot, mOr, mAnd: assert(false, "impliesEq")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesEq")
|
||||
else: result = impUnknown
|
||||
|
||||
proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
@@ -512,13 +549,19 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
var value = newIntNode(c.kind, firstOrd(nil, x.typ))
|
||||
# don't iterate too often:
|
||||
if c.intVal - value.intVal < 1000:
|
||||
var i, pos, neg: int
|
||||
var i, pos, neg: int = 0
|
||||
while value.intVal <= c.intVal:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
@@ -529,17 +572,23 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
let max = lastOrd(nil, x.typ)
|
||||
# don't iterate too often:
|
||||
if max - getInt(value) < toInt128(1000):
|
||||
var i, pos, neg: int
|
||||
var i, pos, neg: int = 0
|
||||
while value.intVal <= max:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc compareSets(a, b: PNode): TImplication =
|
||||
if equalSets(nil, a, b): result = impYes
|
||||
elif intersectSets(nil, a, b).len == 0: result = impNo
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesIn(fact, loc, aSet: PNode): TImplication =
|
||||
case fact[0].sym.magic
|
||||
@@ -550,22 +599,32 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
|
||||
elif sameTree(fact[2], loc):
|
||||
if inSet(aSet, fact[1]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
of mInSet:
|
||||
if sameTree(fact[2], loc):
|
||||
result = compareSets(fact[1], aSet)
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], loc):
|
||||
result = leImpliesIn(fact[1], fact[2], aSet)
|
||||
elif sameTree(fact[2], loc):
|
||||
result = geImpliesIn(fact[2], fact[1], aSet)
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], loc):
|
||||
result = leImpliesIn(fact[1], fact[2].pred, aSet)
|
||||
elif sameTree(fact[2], loc):
|
||||
# 4 < x --> 3 <= x
|
||||
result = geImpliesIn(fact[2], fact[1].pred, aSet)
|
||||
of mNot, mOr, mAnd: assert(false, "impliesIn")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesIn")
|
||||
else: result = impUnknown
|
||||
|
||||
proc valueIsNil(n: PNode): TImplication =
|
||||
if n.kind == nkNilLit: impYes
|
||||
@@ -577,13 +636,19 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
|
||||
of mIsNil:
|
||||
if sameTree(fact[1], eq[1]):
|
||||
result = impYes
|
||||
else:
|
||||
result = impUnknown
|
||||
of someEq:
|
||||
if sameTree(fact[1], eq[1]):
|
||||
result = valueIsNil(fact[2].skipConv)
|
||||
elif sameTree(fact[2], eq[1]):
|
||||
result = valueIsNil(fact[1].skipConv)
|
||||
of mNot, mOr, mAnd: assert(false, "impliesIsNil")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesIsNil")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesGe(fact, x, c: PNode): TImplication =
|
||||
assert isLocation(x)
|
||||
@@ -594,32 +659,57 @@ proc impliesGe(fact, x, c: PNode): TImplication =
|
||||
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
|
||||
if leValue(c, fact[2]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x < 4; question N <= x? --> false iff N <= 4
|
||||
if leValue(fact[2], c): result = impNo
|
||||
else: result = impUnknown
|
||||
# fact: x < 4; question 2 <= x? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c.pred, fact[1]): result = impYes
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impNo
|
||||
# fact: x <= 4; question x >= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impYes
|
||||
of mNot, mOr, mAnd: assert(false, "impliesGe")
|
||||
else: discard
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesGe")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesLe(fact, x, c: PNode): TImplication =
|
||||
if not isLocation(x):
|
||||
@@ -634,35 +724,59 @@ proc impliesLe(fact, x, c: PNode): TImplication =
|
||||
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(fact[1], c): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
|
||||
if leValue(fact[2], c.pred): result = impYes
|
||||
else:
|
||||
result = impUnknown
|
||||
# fact: x < 4; question x <= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impNo
|
||||
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impYes
|
||||
else: result = impUnknown
|
||||
# fact: x <= 4; question x <= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1].pred): result = impNo
|
||||
else:result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
of mNot, mOr, mAnd: assert(false, "impliesLe")
|
||||
else: discard
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesLe")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesLt(fact, x, c: PNode): TImplication =
|
||||
# x < 3 same as x <= 2:
|
||||
@@ -674,6 +788,8 @@ proc impliesLt(fact, x, c: PNode): TImplication =
|
||||
let q = x.pred
|
||||
if q != x:
|
||||
result = impliesLe(fact, q, c)
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc `~`(x: TImplication): TImplication =
|
||||
case x
|
||||
@@ -725,6 +841,7 @@ proc factImplies(fact, prop: PNode): TImplication =
|
||||
|
||||
proc doesImply*(facts: TModel, prop: PNode): TImplication =
|
||||
assert prop.kind in nkCallKinds
|
||||
result = impUnknown
|
||||
for f in facts.s:
|
||||
# facts can be invalidated, in which case they are 'nil':
|
||||
if not f.isNil:
|
||||
@@ -900,6 +1017,7 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
|
||||
|
||||
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
|
||||
# now check for inferrable facts: a <= b and b <= c implies a <= c
|
||||
result = impUnknown
|
||||
for i in 0..m.s.high:
|
||||
let fact = m.s[i]
|
||||
if fact != nil and fact.getMagic in someLe:
|
||||
@@ -981,7 +1099,7 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
|
||||
|
||||
proc settype(n: PNode): PType =
|
||||
result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
|
||||
var idgen: IdGenerator
|
||||
var idgen: IdGenerator = nil
|
||||
addSonSkipIntLit(result, n.typ, idgen)
|
||||
|
||||
proc buildOf(it, loc: PNode; o: Operators): PNode =
|
||||
@@ -1047,12 +1165,8 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
|
||||
if check[1].kind == nkCurly:
|
||||
result = copyTree(check)
|
||||
if access.kind == nkDotExpr:
|
||||
# change the access to the discriminator field access
|
||||
var a = copyTree(access)
|
||||
# set field name to discriminator field name
|
||||
a[1] = check[2]
|
||||
# set discriminator field type: important for `neg`
|
||||
a.typ = check[2].typ
|
||||
result[2] = a
|
||||
# 'access.kind != nkDotExpr' can happen for object constructors
|
||||
# which we don't check yet
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
# This include implements the high level optimization pass.
|
||||
# included from sem.nim
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
proc hlo(c: PContext, n: PNode): PNode
|
||||
|
||||
proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
@@ -17,9 +20,11 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
# we need to ensure that the resulting AST is semchecked. However, it's
|
||||
# awful to semcheck before macro invocation, so we don't and treat
|
||||
# templates and macros as immediate in this context.
|
||||
var rule: string
|
||||
if c.config.hasHint(hintPattern):
|
||||
rule = renderTree(n, {renderNoComments})
|
||||
var rule: string =
|
||||
if c.config.hasHint(hintPattern):
|
||||
renderTree(n, {renderNoComments})
|
||||
else:
|
||||
""
|
||||
let s = n[0].sym
|
||||
case s.kind
|
||||
of skMacro:
|
||||
@@ -70,7 +75,7 @@ proc hlo(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
|
||||
n[0].kind == nkSym and
|
||||
{sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}:
|
||||
{sfGlobal, sfPure} <= n[0].sym.flags:
|
||||
# do not optimize 'var g {.global} = re(...)' again!
|
||||
return n
|
||||
result = applyPatterns(c, n)
|
||||
|
||||
@@ -101,7 +101,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
|
||||
var f2 = rodfiles.open(asymFile.string)
|
||||
f2.loadHeader()
|
||||
f2.loadSection aliveSymsSection
|
||||
var oldData: seq[int32]
|
||||
var oldData: seq[int32] = @[]
|
||||
f2.loadSeq(oldData)
|
||||
f2.close
|
||||
if f2.err == ok and oldData == s:
|
||||
|
||||
@@ -40,10 +40,14 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
|
||||
if ({sfExportc, sfCompilerProc} * flags != {}) or
|
||||
(symPtr.kind == skMethod):
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
# XXX: This used to be a condition to:
|
||||
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
if sfCompilerProc in flags:
|
||||
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
|
||||
else:
|
||||
result = false
|
||||
|
||||
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
|
||||
paddingAtEnd: t.paddingAtEnd)
|
||||
storeNode(p, t, n)
|
||||
p.typeInst = t.typeInst.storeType(c, m)
|
||||
for kid in items t.sons:
|
||||
for kid in items t:
|
||||
p.types.add kid.storeType(c, m)
|
||||
c.addMissing t.sym
|
||||
p.sym = t.sym.safeItemId(c, m)
|
||||
@@ -421,7 +421,7 @@ proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pac
|
||||
## add a remote symbol reference to the tree
|
||||
let info = n.info.toPackedInfo(c, m)
|
||||
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info, flags: n.flags)
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
|
||||
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
|
||||
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
|
||||
@@ -768,8 +768,6 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
|
||||
of nkSym:
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
|
||||
if result.typ == nil:
|
||||
result.typ = result.sym.typ
|
||||
of directIntLit:
|
||||
result.intVal = tree.nodes[n.int].operand
|
||||
of externIntLit:
|
||||
@@ -784,8 +782,6 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
assert n2.kind == nkInt32Lit
|
||||
transitionNoneToSym(result)
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
|
||||
if result.typ == nil:
|
||||
result.typ = result.sym.typ
|
||||
else:
|
||||
for n0 in sonsReadonly(tree, n):
|
||||
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
|
||||
@@ -817,6 +813,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
|
||||
|
||||
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
tree: PackedTree; n: NodePos): PNode =
|
||||
result = nil
|
||||
var i = 0
|
||||
for n0 in sonsReadonly(tree, n):
|
||||
if i == bodyPos:
|
||||
@@ -920,7 +917,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
result.attachedOps[op] = loadSym(c, g, si, item)
|
||||
result.typeInst = loadType(c, g, si, t.typeInst)
|
||||
for son in items t.types:
|
||||
result.sons.add loadType(c, g, si, son)
|
||||
result.addSon loadType(c, g, si, son)
|
||||
loadAstBody(t, n)
|
||||
when false:
|
||||
for gen, id in items t.methods:
|
||||
@@ -1151,6 +1148,8 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, int(module), it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
|
||||
@@ -1168,11 +1167,15 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, int(module), it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, it.module, it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: FileIndex;
|
||||
@@ -1205,7 +1208,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
|
||||
# ------------------------- .rod file viewer ---------------------------------
|
||||
|
||||
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
|
||||
var m: PackedModule
|
||||
var m: PackedModule = PackedModule()
|
||||
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
|
||||
if err != ok:
|
||||
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
|
||||
|
||||
@@ -34,7 +34,11 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
|
||||
if current.file == trackPos.file and current.line == trackPos.line:
|
||||
let col = trackPos.col
|
||||
if col >= current.col and col < current.col+tokenLen:
|
||||
return true
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
|
||||
result = s.name != LitId(0) and
|
||||
|
||||
@@ -305,6 +305,7 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
|
||||
result = (NodePos a, NodePos b, NodePos c)
|
||||
|
||||
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
|
||||
result = default(NodePos)
|
||||
if tree.nodes[n.int].kind > nkNilLit:
|
||||
var count = 0
|
||||
for child in sonsReadonly(tree, n):
|
||||
|
||||
@@ -215,7 +215,7 @@ proc storeHeader*(f: var RodFile) =
|
||||
proc loadHeader*(f: var RodFile) =
|
||||
## Loads the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
var thisCookie: array[cookie.len, byte]
|
||||
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
|
||||
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
|
||||
setError f, ioFailure
|
||||
elif thisCookie != cookie:
|
||||
@@ -231,13 +231,14 @@ proc storeSection*(f: var RodFile; s: RodSection) =
|
||||
proc loadSection*(f: var RodFile; expected: RodSection) =
|
||||
## read the bytes value of s, sets and error if the section is incorrect.
|
||||
if f.err != ok: return
|
||||
var s: RodSection
|
||||
var s: RodSection = default(RodSection)
|
||||
loadPrim(f, s)
|
||||
if expected != s and f.err == ok:
|
||||
setError f, wrongSection
|
||||
|
||||
proc create*(filename: string): RodFile =
|
||||
## create the file and open it for writing
|
||||
result = default(RodFile)
|
||||
if not open(result.f, filename, fmWrite):
|
||||
setError result, cannotOpen
|
||||
|
||||
@@ -245,5 +246,6 @@ proc close*(f: var RodFile) = close(f.f)
|
||||
|
||||
proc open*(filename: string): RodFile =
|
||||
## open the file for reading
|
||||
result = default(RodFile)
|
||||
if not open(result.f, filename, fmRead):
|
||||
setError result, cannotOpen
|
||||
|
||||
@@ -113,6 +113,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
|
||||
|
||||
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
|
||||
template bail = globalError(c.config, n.info, "invalid pragma")
|
||||
result = (nil, @[])
|
||||
if n.kind == nkPragmaExpr:
|
||||
if n.len == 2 and n[1].kind == nkPragma:
|
||||
result[0] = n[0]
|
||||
@@ -141,7 +142,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) =
|
||||
# for an enumeration we have to add all identifiers
|
||||
if multiImport:
|
||||
# for a overloadable syms add all overloaded routines
|
||||
var it: ModuleIter = default(ModuleIter)
|
||||
var it: ModuleIter
|
||||
var e = initModuleIter(it, c.graph, fromMod, s.name)
|
||||
while e != nil:
|
||||
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
|
||||
@@ -304,17 +305,11 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
|
||||
var prefix = ""
|
||||
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
|
||||
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
|
||||
|
||||
proc suggestMod(n: PNode; s: PSym) =
|
||||
if n.kind == nkImportAs:
|
||||
suggestMod(n[0], realModule)
|
||||
elif n.kind == nkInfix:
|
||||
suggestMod(n[2], s)
|
||||
else:
|
||||
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
|
||||
suggestMod(n, result)
|
||||
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
|
||||
importStmtResult.add newSymNode(result, n.info)
|
||||
#newStrNode(toFullPath(c.config, f), n.info)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc afterImport(c: PContext, m: PSym) =
|
||||
# fixes bug #17510, for re-exported symbols
|
||||
@@ -352,11 +347,9 @@ proc evalImport*(c: PContext, n: PNode): PNode =
|
||||
imp[lastPos] = x[1]
|
||||
impAs[1] = imp
|
||||
impAs[2] = x[2]
|
||||
impAs.info = x[2].info
|
||||
impMod(c, impAs, result)
|
||||
else:
|
||||
imp[lastPos] = x
|
||||
imp.info = x.info
|
||||
impMod(c, imp, result)
|
||||
else:
|
||||
impMod(c, it, result)
|
||||
|
||||
@@ -161,8 +161,7 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
|
||||
result = false
|
||||
|
||||
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
|
||||
# bug #23354; an object type could have a non-trival assignements when it is passed to a sink parameter
|
||||
if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true
|
||||
if not hasDestructor(c, n.typ): return true
|
||||
|
||||
let m = skipConvDfa(n)
|
||||
result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or
|
||||
@@ -296,7 +295,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
|
||||
proc isCriticalLink(dest: PNode): bool {.inline.} =
|
||||
#[
|
||||
Lins's idea that only "critical" links can introduce a cycle. This is
|
||||
critical for the performance guarantees that we strive for: If you
|
||||
critical for the performance gurantees that we strive for: If you
|
||||
traverse a data structure, no tracing will be performed at all.
|
||||
ORC is about this promise: The GC only touches the memory that the
|
||||
mutator touches too.
|
||||
@@ -313,10 +312,9 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
|
||||
]#
|
||||
result = dest.kind != nkSym
|
||||
|
||||
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
|
||||
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
|
||||
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
|
||||
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
|
||||
if c.graph.config.selectedGC == gcOrc:
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(c.graph, t):
|
||||
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
|
||||
|
||||
@@ -409,10 +407,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
# generate: (let tmp = v; reset(v); tmp)
|
||||
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
|
||||
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) or
|
||||
(n.typ.kind == tyPtr and n.sym.typ.kind == tyRef)
|
||||
# bug #23505; transformed by `transf`: addr (deref ref) -> ptr
|
||||
# we know it's really a pointer; so here we assign it directly
|
||||
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
|
||||
result = copyTree(n)
|
||||
else:
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
@@ -439,28 +434,28 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
proc isCapturedVar(n: PNode): bool =
|
||||
let root = getRoot(n)
|
||||
if root != nil: result = root.name.s[0] == ':'
|
||||
else: result = false
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
|
||||
let tmp = c.getTemp(s, nTyp, n.info)
|
||||
if hasDestructor(c, nTyp):
|
||||
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let tmp = c.getTemp(s, n.typ, n.info)
|
||||
if hasDestructor(c, n.typ):
|
||||
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, typ, attachedDup)
|
||||
if op != nil and tfHasOwned notin typ.flags:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup")
|
||||
c.checkForErrorPragma(n.typ, n, "=dup")
|
||||
else:
|
||||
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
|
||||
if copyOp != nil and sfError in copyOp.flags and
|
||||
sfOverridden notin op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup", inferredFromCopy = true)
|
||||
c.checkForErrorPragma(n.typ, n, "=dup", inferredFromCopy = true)
|
||||
|
||||
let src = p(n, c, s, normal)
|
||||
var newCall = newTreeIT(nkCall, src.info, src.typ,
|
||||
newSymNode(op),
|
||||
src)
|
||||
c.finishCopy(newCall, n, {}, isFromSink = true)
|
||||
c.finishCopy(newCall, n, isFromSink = true)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
newCall
|
||||
@@ -469,9 +464,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, {}, isFromSink = true)
|
||||
c.finishCopy(m, n, isFromSink = true)
|
||||
result.add m
|
||||
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
|
||||
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
|
||||
message(c.graph.config, n.info, hintPerformance,
|
||||
("passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||
"if possible, rearrange your program's control flow to prevent it") % $n)
|
||||
@@ -480,8 +475,8 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
|
||||
else:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsManagedMemory(nTyp))
|
||||
if nTyp.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
assert(not containsManagedMemory(n.typ))
|
||||
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
|
||||
result.add newTree(nkAsgn, tmp, p(n, c, s, normal))
|
||||
# Since we know somebody will take over the produced copy, there is
|
||||
@@ -497,7 +492,7 @@ proc containsConstSeq(n: PNode): bool =
|
||||
return true
|
||||
result = false
|
||||
case n.kind
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast:
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = containsConstSeq(n[1])
|
||||
of nkObjConstr, nkClosure:
|
||||
for i in 1..<n.len:
|
||||
@@ -595,9 +590,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
|
||||
# tricky because you would have to intercept moveOrCopy at a certain point
|
||||
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
|
||||
tmp.sym.flags = tmpFlags
|
||||
let cpy = if hasDestructor(c, ret.typ) and
|
||||
ret.typ.kind notin {tyOpenArray, tyVarargs}:
|
||||
# bug #23247 we don't own the data, so it's harmful to destroy it
|
||||
let cpy = if hasDestructor(c, ret.typ):
|
||||
s.parent[].final.add c.genDestroy(tmp)
|
||||
moveOrCopy(tmp, ret, c, s, {IsDecl})
|
||||
else:
|
||||
@@ -743,7 +736,9 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
|
||||
result[^1] = maybeVoid(n[^1], s)
|
||||
dec c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||
|
||||
else: assert(false)
|
||||
else:
|
||||
result = nil
|
||||
assert(false)
|
||||
|
||||
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
@@ -755,7 +750,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
let tmp = c.getTemp(s, n[0].typ, n.info)
|
||||
var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
|
||||
m.add p(n[0], c, s, normal)
|
||||
c.finishCopy(m, n[0], {}, isFromSink = false)
|
||||
c.finishCopy(m, n[0], isFromSink = false)
|
||||
result = newTree(nkStmtList, c.genWasMoved(tmp), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
@@ -770,18 +765,6 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
result.add copyNode(n[0])
|
||||
s.needsTry = true
|
||||
|
||||
template isCustomDestructor(c: Con, t: PType): bool =
|
||||
hasDestructor(c, t) and
|
||||
getAttachedOp(c.graph, t, attachedDestructor) != nil and
|
||||
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags
|
||||
|
||||
proc hasCustomDestructor(c: Con, t: PType): bool =
|
||||
result = isCustomDestructor(c, t)
|
||||
var obj = t
|
||||
while obj.len > 0 and obj[0] != nil:
|
||||
obj = skipTypes(obj[0], abstractPtrs)
|
||||
result = result or isCustomDestructor(c, obj)
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
|
||||
@@ -795,7 +778,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result = passCopyToSink(n, c, s)
|
||||
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
|
||||
nkCallKinds + nkLiterals:
|
||||
result = p(n, c, s, consumed)
|
||||
if n.kind in nkCallKinds and n[0].kind == nkSym:
|
||||
if n[0].sym.magic == mEnsureMove:
|
||||
inc c.inEnsureMove
|
||||
result = p(n[1], c, s, sinkArg)
|
||||
dec c.inEnsureMove
|
||||
else:
|
||||
result = p(n, c, s, consumed)
|
||||
else:
|
||||
result = p(n, c, s, consumed)
|
||||
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
|
||||
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
@@ -815,9 +806,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
elif n.kind in {nkObjDownConv, nkObjUpConv}:
|
||||
result = copyTree(n)
|
||||
result[0] = p(n[0], c, s, sinkArg)
|
||||
elif n.kind == nkCast and n.typ.skipTypes(abstractInst).kind in {tyString, tySequence}:
|
||||
result = copyTree(n)
|
||||
result[1] = p(n[1], c, s, sinkArg)
|
||||
elif n.typ == nil:
|
||||
# 'raise X' can be part of a 'case' expression. Deal with it here:
|
||||
result = p(n, c, s, normal)
|
||||
@@ -867,9 +855,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result[i][1] = p(n[i][1], c, s, m)
|
||||
else:
|
||||
result[i] = p(n[i], c, s, m)
|
||||
if mode == normal and (isRefConstr or hasCustomDestructor(c, t)):
|
||||
if mode == normal and isRefConstr:
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
|
||||
inc c.inEnsureMove
|
||||
result = p(n[1], c, s, sinkArg)
|
||||
dec c.inEnsureMove
|
||||
return
|
||||
|
||||
let inSpawn = c.inSpawn
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
|
||||
c.inSpawn.inc
|
||||
@@ -886,19 +880,13 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
isDangerous = true
|
||||
|
||||
result = shallowCopy(n)
|
||||
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
|
||||
inc c.inEnsureMove
|
||||
result[1] = p(n[1], c, s, sinkArg)
|
||||
dec c.inEnsureMove
|
||||
else:
|
||||
for i in 1..<n.len:
|
||||
if i < L and isCompileTimeOnly(parameters[i]):
|
||||
result[i] = n[i]
|
||||
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
|
||||
result[i] = p(n[i], c, s, sinkArg)
|
||||
else:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
for i in 1..<n.len:
|
||||
if i < L and isCompileTimeOnly(parameters[i]):
|
||||
result[i] = n[i]
|
||||
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
|
||||
result[i] = p(n[i], c, s, sinkArg)
|
||||
else:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
|
||||
when false:
|
||||
if isDangerous:
|
||||
@@ -913,10 +901,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result[0] = p(n[0], c, s, normal)
|
||||
if canRaise(n[0]): s.needsTry = true
|
||||
if mode == normal:
|
||||
if result.typ != nil and result.typ.kind notin {tyOpenArray, tyVarargs}:
|
||||
# Returns of openarray types shouldn't be destroyed
|
||||
# bug #19435; # bug #23247
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
of nkDiscardStmt: # Small optimization
|
||||
result = shallowCopy(n)
|
||||
if n[0].kind != nkEmpty:
|
||||
@@ -1064,6 +1049,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
of nkGotoState, nkState, nkAsmStmt:
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
|
||||
|
||||
proc sameLocation*(a, b: PNode): bool =
|
||||
@@ -1156,7 +1142,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, flags, isFromSink = false)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
of nkBracket:
|
||||
# array constructor
|
||||
if ri.len > 0 and isDangerousSeq(ri.typ):
|
||||
@@ -1164,7 +1150,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, flags, isFromSink = false)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
else:
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
|
||||
@@ -1175,7 +1161,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
|
||||
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
|
||||
not ({sfGlobal, sfPure} <= ri.sym.flags):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
@@ -1184,7 +1171,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, flags, isFromSink = false)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
|
||||
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||
@@ -1204,7 +1191,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, flags, isFromSink = false)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
|
||||
when false:
|
||||
proc computeUninit(c: var Con) =
|
||||
|
||||
@@ -10,7 +10,7 @@ Platforms: """
|
||||
macosx: i386;amd64;powerpc64;arm64
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
|
||||
netbsd: i386;amd64;arm64
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64;arm;arm64
|
||||
dragonfly: i386;amd64
|
||||
crossos: amd64
|
||||
|
||||
@@ -171,6 +171,7 @@ proc addToHex*(result: var string; arg: Int128) =
|
||||
i -= 1
|
||||
|
||||
proc toHex*(arg: Int128): string =
|
||||
result = ""
|
||||
result.addToHex(arg)
|
||||
|
||||
proc inc*(a: var Int128, y: uint32 = 1) =
|
||||
@@ -330,8 +331,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
|
||||
if b < 0:
|
||||
result = -result
|
||||
|
||||
proc `*=`*(a: var Int128, b: int32): Int128 =
|
||||
result = result * b
|
||||
proc `*=`(a: var Int128, b: int32) =
|
||||
a = a * b
|
||||
|
||||
proc makeInt128(high, low: uint64): Int128 =
|
||||
result.udata[0] = cast[uint32](low)
|
||||
@@ -360,6 +361,7 @@ proc `*=`*(a: var Int128, b: Int128) =
|
||||
import bitops
|
||||
|
||||
proc fastLog2*(a: Int128): int =
|
||||
result = 0
|
||||
if a.udata[3] != 0:
|
||||
return 96 + fastLog2(a.udata[3])
|
||||
if a.udata[2] != 0:
|
||||
|
||||
@@ -21,6 +21,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
|
||||
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
result = false
|
||||
for i in 0..<n.len:
|
||||
result = canAliasN(arg, n[i], marker)
|
||||
if result: return
|
||||
@@ -36,7 +37,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
|
||||
else: discard
|
||||
of nkSym:
|
||||
result = canAlias(arg, n.sym.typ, marker)
|
||||
else: discard
|
||||
else: result = false
|
||||
|
||||
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
|
||||
if containsOrIncl(marker, ret.id):
|
||||
@@ -56,6 +57,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
|
||||
else:
|
||||
result = true
|
||||
of tyTuple:
|
||||
result = false
|
||||
for i in 0..<ret.len:
|
||||
result = canAlias(arg, ret[i], marker)
|
||||
if result: break
|
||||
@@ -184,10 +186,12 @@ proc checkIsolate*(n: PNode): bool =
|
||||
return false
|
||||
result = true
|
||||
of nkIfStmt, nkIfExpr:
|
||||
result = false
|
||||
for it in n:
|
||||
result = checkIsolate(it.lastSon)
|
||||
if not result: break
|
||||
of nkCaseStmt:
|
||||
result = false
|
||||
for i in 1..<n.len:
|
||||
result = checkIsolate(n[i].lastSon)
|
||||
if not result: break
|
||||
@@ -197,6 +201,7 @@ proc checkIsolate*(n: PNode): bool =
|
||||
result = checkIsolate(n[i].lastSon)
|
||||
if not result: break
|
||||
of nkBracket, nkTupleConstr, nkPar:
|
||||
result = false
|
||||
for it in n:
|
||||
result = checkIsolate(it)
|
||||
if not result: break
|
||||
|
||||
@@ -32,7 +32,7 @@ import
|
||||
ast, trees, magicsys, options,
|
||||
nversion, msgs, idents, types,
|
||||
ropes, ccgutils, wordrecg, renderer,
|
||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos,
|
||||
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
|
||||
|
||||
import pipelineutils
|
||||
@@ -43,6 +43,7 @@ import strutils except addf
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, syncio]
|
||||
|
||||
import std/formatfloat
|
||||
|
||||
type
|
||||
TJSGen = object of PPassContext
|
||||
@@ -137,17 +138,15 @@ template nested(p, body) =
|
||||
dec p.extraIndent
|
||||
|
||||
proc newGlobals(): PGlobals =
|
||||
new(result)
|
||||
result.forwarded = @[]
|
||||
result.generatedSyms = initIntSet()
|
||||
result.typeInfoGenerated = initIntSet()
|
||||
result = PGlobals(forwarded: @[],
|
||||
generatedSyms: initIntSet(),
|
||||
typeInfoGenerated: initIntSet()
|
||||
)
|
||||
|
||||
proc initCompRes(r: var TCompRes) =
|
||||
r.address = ""
|
||||
r.res = ""
|
||||
r.tmpLoc = ""
|
||||
r.typ = etyNone
|
||||
r.kind = resNone
|
||||
proc initCompRes(): TCompRes =
|
||||
result = TCompRes(address: "", res: "",
|
||||
tmpLoc: "", typ: etyNone, kind: resNone
|
||||
)
|
||||
|
||||
proc rdLoc(a: TCompRes): Rope {.inline.} =
|
||||
if a.typ != etyBaseIndex:
|
||||
@@ -219,7 +218,8 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||
else: result = etyNone
|
||||
of tyProc: result = etyProc
|
||||
of tyCstring: result = etyString
|
||||
of tyConcept, tyIterable: doAssert false
|
||||
of tyConcept, tyIterable:
|
||||
raiseAssert "unreachable"
|
||||
|
||||
proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
||||
result = mapType(typ)
|
||||
@@ -348,8 +348,7 @@ proc isSimpleExpr(p: PProc; n: PNode): bool =
|
||||
if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
|
||||
result = isSimpleExpr(p, n.lastSon)
|
||||
else:
|
||||
if n.isAtom:
|
||||
result = true
|
||||
result = n.isAtom
|
||||
|
||||
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||
inc(p.unique)
|
||||
@@ -359,7 +358,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||
|
||||
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
assert r.kind == resNone
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
|
||||
gen(p, a, x)
|
||||
gen(p, b, y)
|
||||
@@ -386,7 +385,7 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
|
||||
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
assert r.kind == resNone
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
|
||||
gen(p, a, x)
|
||||
gen(p, b, y)
|
||||
@@ -474,6 +473,7 @@ const # magic checked op; magic unchecked op;
|
||||
proc needsTemp(p: PProc; n: PNode): bool =
|
||||
# check if n contains a call to determine
|
||||
# if a temp should be made to prevent multiple evals
|
||||
result = false
|
||||
if n.kind in nkCallKinds + {nkTupleConstr, nkObjConstr, nkBracket, nkCurly}:
|
||||
return true
|
||||
for c in n:
|
||||
@@ -509,8 +509,8 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
|
||||
elif x.tmpLoc != "" and n.kind == nkBracketExpr:
|
||||
# genArrayAddr
|
||||
var
|
||||
address, index: TCompRes
|
||||
first: Int128
|
||||
address, index: TCompRes = default(TCompRes)
|
||||
first: Int128 = Zero
|
||||
gen(p, n[0], address)
|
||||
gen(p, n[1], index)
|
||||
let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
|
||||
@@ -542,7 +542,7 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
|
||||
# $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
|
||||
# if $3 or $4 are present they will be substituted with temps for
|
||||
# lhs and rhs respectively
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
useMagic(p, magic)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
@@ -572,7 +572,7 @@ proc signedTrimmer(size: BiggestInt): string =
|
||||
|
||||
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
||||
reassign: static[bool] = false) =
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
let size = n[1].typ.skipTypes(abstractRange).size
|
||||
@@ -611,8 +611,8 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
|
||||
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
var
|
||||
x, y: TCompRes
|
||||
xLoc, yLoc: Rope
|
||||
x, y: TCompRes = default(TCompRes)
|
||||
xLoc, yLoc: Rope = ""
|
||||
let i = ord(optOverflowCheck notin p.options)
|
||||
useMagic(p, jsMagics[op][i])
|
||||
if n.len > 2:
|
||||
@@ -676,8 +676,38 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
applyFormat("modInt64($1, $2)", "$1 % $2")
|
||||
else:
|
||||
applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
|
||||
of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
|
||||
of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
|
||||
of mSucc:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
case typ.kind
|
||||
of tyUInt..tyUInt32:
|
||||
binaryUintExpr(p, n, r, "+")
|
||||
of tyUInt64:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asUintN(64, $1 + BigInt($2))")
|
||||
else: binaryUintExpr(p, n, r, "+")
|
||||
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if optOverflowCheck notin p.options:
|
||||
applyFormat("BigInt.asIntN(64, $1 + BigInt($2))")
|
||||
else: binaryExpr(p, n, r, "addInt64", "addInt64($1, BigInt($2))")
|
||||
else:
|
||||
if optOverflowCheck notin p.options: applyFormat("$1 + $2")
|
||||
else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
|
||||
of mPred:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
case typ.kind
|
||||
of tyUInt..tyUInt32:
|
||||
binaryUintExpr(p, n, r, "-")
|
||||
of tyUInt64:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asUintN(64, $1 - BigInt($2))")
|
||||
else: binaryUintExpr(p, n, r, "-")
|
||||
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if optOverflowCheck notin p.options:
|
||||
applyFormat("BigInt.asIntN(64, $1 - BigInt($2))")
|
||||
else: binaryExpr(p, n, r, "subInt64", "subInt64($1, BigInt($2))")
|
||||
else:
|
||||
if optOverflowCheck notin p.options: applyFormat("$1 - $2")
|
||||
else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
|
||||
of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
|
||||
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
|
||||
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
|
||||
@@ -803,7 +833,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
if mapType(n[1].typ) != etyBaseIndex:
|
||||
arithAux(p, n, r, op)
|
||||
else:
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
|
||||
@@ -836,7 +866,7 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||
p.previousFileName = currentFileName
|
||||
|
||||
proc genWhileStmt(p: PProc, n: PNode) =
|
||||
var cond: TCompRes
|
||||
var cond: TCompRes = default(TCompRes)
|
||||
internalAssert p.config, isEmptyType(n.typ)
|
||||
genLineDir(p, n)
|
||||
inc(p.unique)
|
||||
@@ -896,7 +926,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
p.body.add("++excHandler;\L")
|
||||
var tmpFramePtr = rope"F"
|
||||
lineF(p, "try {$n", [])
|
||||
var a: TCompRes = default(TCompRes)
|
||||
var a: TCompRes
|
||||
gen(p, n[0], a)
|
||||
moveInto(p, a, r)
|
||||
var generalCatchBranchExists = false
|
||||
@@ -931,6 +961,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
elif it.kind == nkType:
|
||||
throwObj = it
|
||||
else:
|
||||
throwObj = nil
|
||||
internalError(p.config, n.info, "genTryStmt")
|
||||
|
||||
if orExpr != "": orExpr.add("||")
|
||||
@@ -971,7 +1002,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
if n[0].kind != nkEmpty:
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
gen(p, n[0], a)
|
||||
let typ = skipTypes(n[0].typ, abstractPtrs)
|
||||
genLineDir(p, n)
|
||||
@@ -985,7 +1016,7 @@ proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
|
||||
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
a, b, cond, stmt: TCompRes
|
||||
a, b, cond, stmt: TCompRes = default(TCompRes)
|
||||
genLineDir(p, n)
|
||||
gen(p, n[0], cond)
|
||||
let typeKind = skipTypes(n[0].typ, abstractVar).kind
|
||||
@@ -1119,7 +1150,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||
if false:
|
||||
discard
|
||||
else:
|
||||
var r: TCompRes
|
||||
var r = default(TCompRes)
|
||||
gen(p, it, r)
|
||||
|
||||
if it.typ.kind == tyPointer:
|
||||
@@ -1135,13 +1166,13 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||
|
||||
p.body.add(r.rdLoc)
|
||||
else:
|
||||
var r: TCompRes
|
||||
var r: TCompRes = default(TCompRes)
|
||||
gen(p, it, r)
|
||||
p.body.add(r.rdLoc)
|
||||
p.body.add "\L"
|
||||
|
||||
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var cond, stmt: TCompRes
|
||||
var cond, stmt: TCompRes = default(TCompRes)
|
||||
var toClose = 0
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
@@ -1178,6 +1209,7 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
||||
result.add("_Idx")
|
||||
|
||||
proc countJsParams(typ: PType): int =
|
||||
result = 0
|
||||
for i in 1..<typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
var param = typ.n[i].sym
|
||||
@@ -1198,10 +1230,10 @@ proc needsNoCopy(p: PProc; y: PNode): bool =
|
||||
return y.kind in nodeKindsNeedNoCopy or
|
||||
((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
|
||||
(skipTypes(y.typ, abstractInst).kind in
|
||||
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
|
||||
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
|
||||
|
||||
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
var a, b: TCompRes
|
||||
var a, b: TCompRes = default(TCompRes)
|
||||
var xtyp = mapType(p, x.typ)
|
||||
|
||||
# disable `[]=` for cstring
|
||||
@@ -1280,7 +1312,7 @@ proc genFastAsgn(p: PProc, n: PNode) =
|
||||
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
|
||||
|
||||
proc genSwap(p: PProc, n: PNode) =
|
||||
var a, b: TCompRes
|
||||
var a, b: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], a)
|
||||
gen(p, n[2], b)
|
||||
var tmp = p.getTemp(false)
|
||||
@@ -1298,10 +1330,12 @@ proc getFieldPosition(p: PProc; f: PNode): int =
|
||||
case f.kind
|
||||
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
|
||||
of nkSym: result = f.sym.position
|
||||
else: internalError(p.config, f.info, "genFieldPosition")
|
||||
else:
|
||||
result = 0
|
||||
internalError(p.config, f.info, "genFieldPosition")
|
||||
|
||||
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.typ = etyBaseIndex
|
||||
let b = if n.kind == nkHiddenAddr: n[0] else: n
|
||||
gen(p, b[0], a)
|
||||
@@ -1365,10 +1399,10 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
|
||||
internalAssert p.config, disc.kind == skField
|
||||
if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
|
||||
|
||||
var setx: TCompRes
|
||||
var setx: TCompRes = default(TCompRes)
|
||||
gen(p, checkExpr[1], setx)
|
||||
|
||||
var obj: TCompRes
|
||||
var obj: TCompRes = default(TCompRes)
|
||||
gen(p, accessExpr[0], obj)
|
||||
# Avoid evaluating the LHS twice (one to read the discriminant and one to read
|
||||
# the field)
|
||||
@@ -1394,8 +1428,8 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
|
||||
|
||||
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
a, b: TCompRes
|
||||
first: Int128
|
||||
a, b: TCompRes = default(TCompRes)
|
||||
first: Int128 = Zero
|
||||
r.typ = etyBaseIndex
|
||||
let m = if n.kind == nkHiddenAddr: n[0] else: n
|
||||
gen(p, m[0], a)
|
||||
@@ -1519,8 +1553,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
||||
of nkObjDownConv:
|
||||
gen(p, n[0], r)
|
||||
of nkHiddenDeref, nkDerefExpr:
|
||||
of nkHiddenDeref:
|
||||
gen(p, n[0], r)
|
||||
of nkDerefExpr:
|
||||
var x = n[0]
|
||||
if n.kind == nkHiddenAddr:
|
||||
x = n[0][0]
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
x.typ = n.typ
|
||||
gen(p, x, r)
|
||||
of nkHiddenAddr:
|
||||
gen(p, n[0], r)
|
||||
of nkConv:
|
||||
@@ -1635,7 +1676,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if t == etyObject or it.typ.kind == tyLent:
|
||||
gen(p, it, r)
|
||||
else:
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
gen(p, it, a)
|
||||
r.kind = a.kind
|
||||
r.typ = mapType(p, n.typ)
|
||||
@@ -1652,7 +1693,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||
internalError(p.config, n.info, "genDeref")
|
||||
|
||||
proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
gen(p, n, a)
|
||||
if a.typ == etyBaseIndex:
|
||||
r.res.add(a.address)
|
||||
@@ -1662,7 +1703,7 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res.add(a.res)
|
||||
|
||||
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
gen(p, n, a)
|
||||
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
|
||||
a.typ == etyBaseIndex:
|
||||
@@ -1786,7 +1827,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.address = ""
|
||||
r.typ = etyNone
|
||||
r.res.add(".")
|
||||
var op: TCompRes
|
||||
var op: TCompRes = default(TCompRes)
|
||||
gen(p, n[0], op)
|
||||
r.res.add(op.res)
|
||||
genArgs(p, n, r, 2)
|
||||
@@ -1934,7 +1975,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result.add("}")
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyObject:
|
||||
var initList: Rope
|
||||
var initList: Rope = ""
|
||||
createObjInitList(p, t, initIntSet(), initList)
|
||||
result = ("({$1})") % [initList]
|
||||
if indirect: result = "[$1]" % [result]
|
||||
@@ -1945,7 +1986,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result = putToSeq("null", indirect)
|
||||
of tySequence, tyString:
|
||||
result = putToSeq("[]", indirect)
|
||||
of tyCstring, tyProc, tyOpenArray:
|
||||
of tyCstring, tyProc:
|
||||
result = putToSeq("null", indirect)
|
||||
of tyStatic:
|
||||
if t.n != nil:
|
||||
@@ -1961,7 +2002,7 @@ template returnType: untyped = ""
|
||||
|
||||
proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
var
|
||||
a: TCompRes
|
||||
a: TCompRes = default(TCompRes)
|
||||
s: Rope
|
||||
varCode: string
|
||||
varName = mangleName(p.module, v)
|
||||
@@ -2062,7 +2103,7 @@ proc genConstant(p: PProc, c: PSym) =
|
||||
p.body = oldBody
|
||||
|
||||
proc genNew(p: PProc, n: PNode) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], a)
|
||||
var t = skipTypes(n[1].typ, abstractVar)[0]
|
||||
if mapType(t) == etyObject:
|
||||
@@ -2073,7 +2114,7 @@ proc genNew(p: PProc, n: PNode) =
|
||||
lineF(p, "$1 = [[$2], 0];$n", [a.rdLoc, createVar(p, t, false)])
|
||||
|
||||
proc genNewSeq(p: PProc, n: PNode) =
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
let t = skipTypes(n[1].typ, abstractVar)[0]
|
||||
@@ -2091,7 +2132,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else: internalError(p.config, n.info, "genOrd")
|
||||
|
||||
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
|
||||
gen(p, n[1], a)
|
||||
r.kind = resExpr
|
||||
@@ -2116,7 +2157,7 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
|
||||
useMagic(p, magic)
|
||||
r.res.add(magic & "(")
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
|
||||
gen(p, n[1], a)
|
||||
if magic == "reprAny":
|
||||
@@ -2163,7 +2204,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
|
||||
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
let t = skipTypes(n[2].typ,
|
||||
abstractVarRange+{tyRef, tyPtr, tyLent, tyTypeDesc, tyOwned})
|
||||
gen(p, n[1], x)
|
||||
@@ -2179,7 +2220,7 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
|
||||
proc genReset(p: PProc, n: PNode) =
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
useMagic(p, "genericReset")
|
||||
gen(p, n[1], x)
|
||||
if x.typ == etyBaseIndex:
|
||||
@@ -2190,7 +2231,7 @@ proc genReset(p: PProc, n: PNode) =
|
||||
genTypeInfo(p, n[1].typ), tmp])
|
||||
|
||||
proc genMove(p: PProc; n: PNode; r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.kind = resVal
|
||||
r.res = p.getTemp()
|
||||
gen(p, n[1], a)
|
||||
@@ -2199,14 +2240,14 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
|
||||
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||
|
||||
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.kind = resVal
|
||||
r.res = p.getTemp()
|
||||
gen(p, n[1], a)
|
||||
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
|
||||
|
||||
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.res = rope("[")
|
||||
r.kind = resExpr
|
||||
for i in 0 ..< n.len:
|
||||
@@ -2237,7 +2278,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
binaryExpr(p, n, r, "addChar",
|
||||
"addChar($1, $2);")
|
||||
of mAppendStrStr:
|
||||
var lhs, rhs: TCompRes
|
||||
var lhs, rhs: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], lhs)
|
||||
gen(p, n[2], rhs)
|
||||
|
||||
@@ -2250,7 +2291,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
|
||||
r.kind = resExpr
|
||||
of mAppendSeqElem:
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
if mapType(n[2].typ) == etyBaseIndex:
|
||||
@@ -2278,7 +2319,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if mapType(n[1].typ) != etyBaseIndex:
|
||||
unaryExpr(p, n, r, "", "($1 == null)")
|
||||
else:
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
r.res = "($# == null && $# === 0)" % [x.address, x.res]
|
||||
of mEnumToStr: genRepr(p, n, r)
|
||||
@@ -2289,7 +2330,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if n[1].kind == nkBracket:
|
||||
genJSArrayConstr(p, n[1], r)
|
||||
else:
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
useMagic(p, "nimCopy")
|
||||
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
|
||||
@@ -2298,7 +2339,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mDestroy, mTrace: discard "ignore calls to the default destructor"
|
||||
of mOrd: genOrd(p, n, r)
|
||||
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
|
||||
let (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
@@ -2307,7 +2348,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = "($1).length" % [x.rdLoc]
|
||||
r.kind = resExpr
|
||||
of mHigh:
|
||||
var x: TCompRes
|
||||
var x: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
|
||||
let (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
@@ -2339,7 +2380,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of tyUInt64:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true)
|
||||
else: binaryUintExpr(p, n, r, "+", true)
|
||||
else: binaryUintExpr(p, n, r, "-", true)
|
||||
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if optOverflowCheck notin p.options:
|
||||
binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true)
|
||||
@@ -2352,7 +2393,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
|
||||
else {$3.length = $4; }""")
|
||||
of mSetLengthSeq:
|
||||
var x, y: TCompRes
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
let t = skipTypes(n[1].typ, abstractVar)[0]
|
||||
@@ -2391,7 +2432,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
genCall(p, n, r)
|
||||
of mSlice:
|
||||
# arr.slice([begin[, end]]): 'end' is exclusive
|
||||
var x, y, z: TCompRes
|
||||
var x, y, z: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
gen(p, n[3], z)
|
||||
@@ -2409,7 +2450,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
||||
proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
a, b: TCompRes
|
||||
a, b: TCompRes = default(TCompRes)
|
||||
useMagic(p, "setConstr")
|
||||
r.res = rope("setConstr(")
|
||||
r.kind = resExpr
|
||||
@@ -2446,7 +2487,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# generate typed array
|
||||
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
|
||||
# TODO use `set` or loop to initialize typed array which improves performances in some situations
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.res = "new $1([" % [rope(jsTyp)]
|
||||
r.kind = resExpr
|
||||
for i in 0 ..< n.len:
|
||||
@@ -2458,7 +2499,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
genJSArrayConstr(p, n, r)
|
||||
|
||||
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.res = rope("{")
|
||||
r.kind = resExpr
|
||||
for i in 0..<n.len:
|
||||
@@ -2477,9 +2518,9 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res.add("}")
|
||||
|
||||
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
var a: TCompRes = default(TCompRes)
|
||||
r.kind = resExpr
|
||||
var initList : Rope
|
||||
var initList : Rope = ""
|
||||
var fieldIDs = initIntSet()
|
||||
let nTyp = n.typ.skipTypes(abstractInst)
|
||||
for i in 1..<n.len:
|
||||
@@ -2553,16 +2594,23 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n[0], r) # XXX
|
||||
|
||||
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
|
||||
var a, b: TCompRes
|
||||
var a, b: TCompRes = default(TCompRes)
|
||||
gen(p, n[0], r)
|
||||
let src = skipTypes(n[0].typ, abstractVarRange)
|
||||
let dest = skipTypes(n.typ, abstractVarRange)
|
||||
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number($1)" % [r.res]
|
||||
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "XXX maybe emit masking instructions here"
|
||||
if optRangeCheck notin p.options:
|
||||
return
|
||||
elif dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures:
|
||||
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "BigInt.asUintN($1, $2)" % [$(dest.size * 8), r.res]
|
||||
else:
|
||||
r.res = "BigInt.asUintN($1, BigInt($2))" % [$(dest.size * 8), r.res]
|
||||
if not (dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions):
|
||||
r.res = "Number($1)" % [r.res]
|
||||
else:
|
||||
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
# we do a range check anyway, so it's ok if the number gets rounded
|
||||
r.res = "Number($1)" % [r.res]
|
||||
gen(p, n[1], a)
|
||||
gen(p, n[2], b)
|
||||
useMagic(p, "chckRange")
|
||||
@@ -2639,9 +2687,10 @@ proc optionalLine(p: Rope): Rope =
|
||||
|
||||
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
## Generate a JS procedure ('function').
|
||||
result = ""
|
||||
var
|
||||
resultSym: PSym
|
||||
a: TCompRes
|
||||
a: TCompRes = default(TCompRes)
|
||||
#if gVerbosity >= 3:
|
||||
# echo "BEGIN generating code for: " & prc.name.s
|
||||
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
|
||||
@@ -2721,7 +2770,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
# echo "END generated code for: " & prc.name.s
|
||||
|
||||
proc genStmt(p: PProc, n: PNode) =
|
||||
var r: TCompRes
|
||||
var r: TCompRes = default(TCompRes)
|
||||
gen(p, n, r)
|
||||
if r.res != "": lineF(p, "$#;$n", [r.res])
|
||||
|
||||
@@ -2852,7 +2901,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = rope"Infinity"
|
||||
of fcNegInf:
|
||||
r.res = rope"-Infinity"
|
||||
else: r.res = rope(f.toStrMaxPrecision)
|
||||
else:
|
||||
if n.typ.skipTypes(abstractVarRange).kind == tyFloat32:
|
||||
r.res.addFloatRoundtrip(f.float32)
|
||||
else:
|
||||
r.res.addFloatRoundtrip(f)
|
||||
r.kind = resExpr
|
||||
of nkCallKinds:
|
||||
if isEmptyType(n.typ):
|
||||
@@ -2953,13 +3006,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
||||
proc newModule(g: ModuleGraph; module: PSym): BModule =
|
||||
## Create a new JS backend module node.
|
||||
new(result)
|
||||
result.module = module
|
||||
result.sigConflicts = initCountTable[SigHash]()
|
||||
if g.backend == nil:
|
||||
g.backend = newGlobals()
|
||||
result.graph = g
|
||||
result.config = g.config
|
||||
result = BModule(module: module, sigConflicts: initCountTable[SigHash](),
|
||||
graph: g, config: g.config
|
||||
)
|
||||
if sfSystemModule in module.flags:
|
||||
PGlobals(g.backend).inSystem = true
|
||||
|
||||
|
||||
@@ -187,6 +187,8 @@ proc getEnvParam*(routine: PSym): PSym =
|
||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||
result = hidden.sym
|
||||
assert sfFromGeneric in result.flags
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc interestingVar(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
|
||||
@@ -199,6 +201,8 @@ proc illegalCapture(s: PSym): bool {.inline.} =
|
||||
proc isInnerProc(s: PSym): bool =
|
||||
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
|
||||
result = s.skipGenericOwner.kind in routineKinds
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
|
||||
@@ -258,7 +262,8 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
|
||||
let iter = n.sym
|
||||
assert iter.isIterator
|
||||
|
||||
result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
let hp = getHiddenParam(g, iter)
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
@@ -311,17 +316,14 @@ type
|
||||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo: bool
|
||||
inTypeOf: bool
|
||||
graph: ModuleGraph
|
||||
idgen: IdGenerator
|
||||
|
||||
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
|
||||
result.processed = initIntSet()
|
||||
result.capturedVars = initIntSet()
|
||||
result.ownerToType = initTable[int, PType]()
|
||||
result.processed.incl(fn.id)
|
||||
result.graph = g
|
||||
result.idgen = idgen
|
||||
result = DetectionPass(processed: toIntSet([fn.id]),
|
||||
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
|
||||
graph: g, idgen: idgen
|
||||
)
|
||||
|
||||
discard """
|
||||
proc outer =
|
||||
@@ -415,9 +417,6 @@ Consider:
|
||||
|
||||
"""
|
||||
|
||||
proc isTypeOf(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
|
||||
|
||||
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
||||
var cp = getEnvParam(fn)
|
||||
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
|
||||
@@ -456,8 +455,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
c.somethingToDo = true
|
||||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.contains(s.id):
|
||||
if not c.inTypeOf: c.capturedVars.incl(s.id)
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
|
||||
@@ -483,12 +481,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
addClosureParam(c, owner, n.info)
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
if interestingVar(s):
|
||||
if not c.capturedVars.contains(s.id):
|
||||
if not c.inTypeOf: c.capturedVars.incl(s.id)
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
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})
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# create required upFields:
|
||||
var w = owner.skipGenericOwner
|
||||
if isInnerProc(w) or owner.isIterator:
|
||||
@@ -520,14 +516,9 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
detectCapturedVars(n[namePos], owner, c)
|
||||
of nkReturnStmt:
|
||||
detectCapturedVars(n[0], owner, c)
|
||||
of nkIdentDefs:
|
||||
detectCapturedVars(n[^1], owner, c)
|
||||
else:
|
||||
if n.isCallExpr and n[0].isTypeOf:
|
||||
c.inTypeOf = true
|
||||
for i in 0..<n.len:
|
||||
detectCapturedVars(n[i], owner, c)
|
||||
c.inTypeOf = false
|
||||
|
||||
type
|
||||
LiftingPass = object
|
||||
@@ -537,9 +528,8 @@ type
|
||||
unownedEnvVars: Table[int, PNode] # only required for --newruntime
|
||||
|
||||
proc initLiftingPass(fn: PSym): LiftingPass =
|
||||
result.processed = initIntSet()
|
||||
result.processed.incl(fn.id)
|
||||
result.envVars = initTable[int, PNode]()
|
||||
result = LiftingPass(processed: toIntSet([fn.id]),
|
||||
envVars: initTable[int, PNode]())
|
||||
|
||||
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
let s = n.sym
|
||||
@@ -726,6 +716,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
# direct dependency, so use the outer's env variable:
|
||||
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
|
||||
else:
|
||||
result = nil
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
let wanted = getHiddenParam(d.graph, s).typ
|
||||
# ugh: call through some other inner proc;
|
||||
@@ -807,8 +798,6 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
of nkTypeOfExpr:
|
||||
result = n
|
||||
else:
|
||||
if n.isCallExpr and n[0].isTypeOf:
|
||||
return
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
# special case 'when nimVm' due to bug #3636:
|
||||
@@ -953,7 +942,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
|
||||
result = newNodeI(nkStmtList, body.info)
|
||||
|
||||
# static binding?
|
||||
var env: PSym
|
||||
var env: PSym = nil
|
||||
let op = call[0]
|
||||
if op.kind == nkSym and op.sym.isIterator:
|
||||
# createClosure()
|
||||
@@ -988,15 +977,12 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
|
||||
# gather vars in a tuple:
|
||||
var v2 = newNodeI(nkLetSection, body.info)
|
||||
var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
|
||||
if body.len == 3 and body[0].kind == nkVarTuple:
|
||||
vpart = body[0] # fixes for (i,j) in walk() # bug #15924
|
||||
else:
|
||||
for i in 0..<body.len-2:
|
||||
if body[i].kind == nkSym:
|
||||
body[i].sym.transitionToLet()
|
||||
vpart.add body[i]
|
||||
for i in 0..<body.len-2:
|
||||
if body[i].kind == nkSym:
|
||||
body[i].sym.transitionToLet()
|
||||
vpart.add body[i]
|
||||
|
||||
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
|
||||
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
|
||||
if not env.isNil:
|
||||
call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info)
|
||||
vpart.add call
|
||||
|
||||
@@ -148,9 +148,11 @@ proc isNimIdentifier*(s: string): bool =
|
||||
var i = 1
|
||||
while i < sLen:
|
||||
if s[i] == '_': inc(i)
|
||||
if i < sLen and s[i] notin SymChars: return
|
||||
if i < sLen and s[i] notin SymChars: return false
|
||||
inc(i)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc `$`*(tok: Token): string =
|
||||
case tok.tokType
|
||||
@@ -537,8 +539,8 @@ proc getNumber(L: var Lexer, result: var Token) =
|
||||
of floatTypes:
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
of tkUInt64Lit, tkUIntLit:
|
||||
var iNumber: uint64
|
||||
var len: int
|
||||
var iNumber: uint64 = uint64(0)
|
||||
var len: int = 0
|
||||
try:
|
||||
len = parseBiggestUInt(result.literal, iNumber)
|
||||
except ValueError:
|
||||
@@ -547,8 +549,8 @@ proc getNumber(L: var Lexer, result: var Token) =
|
||||
raise newException(ValueError, "invalid integer: " & result.literal)
|
||||
result.iNumber = cast[int64](iNumber)
|
||||
else:
|
||||
var iNumber: int64
|
||||
var len: int
|
||||
var iNumber: int64 = int64(0)
|
||||
var len: int = 0
|
||||
try:
|
||||
len = parseBiggestInt(result.literal, iNumber)
|
||||
except ValueError:
|
||||
@@ -1007,6 +1009,7 @@ proc getPrecedence*(tok: Token): int =
|
||||
else: return -10
|
||||
|
||||
proc newlineFollows*(L: Lexer): bool =
|
||||
result = false
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -1394,8 +1397,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
|
||||
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
|
||||
cache: IdentCache; config: ConfigRef): int =
|
||||
var lex: Lexer
|
||||
var tok: Token
|
||||
result = 0
|
||||
var lex: Lexer = default(Lexer)
|
||||
var tok: Token = default(Token)
|
||||
initToken(tok)
|
||||
openLexer(lex, fileIdx, inputstream, cache, config)
|
||||
var prevToken = tkEof
|
||||
|
||||
@@ -156,18 +156,17 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
result.add(newSymNode(op))
|
||||
result.add genAddr(c, x)
|
||||
|
||||
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
|
||||
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
if c.filterDiscriminator != nil: return
|
||||
let f = n.sym
|
||||
let b = if c.kind == attachedTrace: y else: y.dotField(f)
|
||||
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
|
||||
c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
if enforceWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
|
||||
fillBody(c, f.typ, body, x.dotField(f), b)
|
||||
of nkNilLit: discard
|
||||
of nkRecCase:
|
||||
@@ -206,7 +205,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
branch[^1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
|
||||
enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
|
||||
enforceDefaultOp = localEnforceDefaultOp)
|
||||
if branch[^1].len == 0: inc emptyBranches
|
||||
caseStmt.add(branch)
|
||||
if emptyBranches != n.len-1:
|
||||
@@ -217,23 +216,13 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
|
||||
c.filterDiscriminator = oldfilterDiscriminator
|
||||
of nkRecList:
|
||||
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
|
||||
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
|
||||
else:
|
||||
illFormedAstLocal(n, c.g.config)
|
||||
|
||||
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
if t.len > 0 and t[0] != nil:
|
||||
let obj = newNodeIT(nkHiddenSubConv, c.info, t[0])
|
||||
obj.add newNodeI(nkEmpty, c.info)
|
||||
obj.add x
|
||||
var src = y
|
||||
|
||||
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
|
||||
src = newNodeIT(nkHiddenSubConv, c.info, t[0])
|
||||
src.add newNodeI(nkEmpty, c.info)
|
||||
src.add y
|
||||
|
||||
fillBody(c, skipTypes(t[0], abstractPtrs), body, obj, src)
|
||||
fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y)
|
||||
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
|
||||
|
||||
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
@@ -290,7 +279,6 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
c.kind = attachedDestructor
|
||||
fillBodyObjTImpl(c, t, body, blob, y)
|
||||
c.kind = prevKind
|
||||
|
||||
else:
|
||||
fillBodyObjTImpl(c, t, body, x, y)
|
||||
|
||||
@@ -314,7 +302,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result.add newSymNode(op)
|
||||
if sfNeverRaises notin op.flags:
|
||||
c.canRaise = true
|
||||
if op.typ.sons[1].kind == tyVar:
|
||||
if op.typ[1].kind == tyVar:
|
||||
result.add genAddr(c, x)
|
||||
else:
|
||||
result.add x
|
||||
@@ -379,6 +367,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
elif tfHasAsgn in t.flags:
|
||||
var op: PSym
|
||||
if sameType(t, c.asgnForType):
|
||||
@@ -408,6 +398,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
assert op.ast[genericParamsPos].kind == nkEmpty
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
|
||||
let t = orig.skipTypes(abstractInst - {tyDistinct})
|
||||
@@ -447,6 +439,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add destructorCall(c, op, x)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
#result = addDestructorCall(c, t, body, x)
|
||||
of attachedAsgn, attachedSink, attachedTrace:
|
||||
var op = getAttachedOp(c.g, t, c.kind)
|
||||
@@ -467,6 +461,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add newDeepCopyCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of attachedWasMoved:
|
||||
var op = getAttachedOp(c.g, t, attachedWasMoved)
|
||||
@@ -481,6 +477,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add genWasMovedCall(c, op, x)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of attachedDup:
|
||||
var op = getAttachedOp(c.g, t, attachedDup)
|
||||
@@ -495,6 +493,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add newDupCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
@@ -554,14 +554,6 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
else:
|
||||
body.sons.setLen counterIdx
|
||||
|
||||
proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
var cond = callCodegenProc(c.g, "sameSeqPayload", c.info,
|
||||
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
|
||||
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
|
||||
)
|
||||
cond.typ = getSysType(c.g, c.info, tyBool)
|
||||
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
|
||||
|
||||
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedDup:
|
||||
@@ -569,13 +561,10 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
# we generate:
|
||||
# if x.p == y.p:
|
||||
# return
|
||||
# setLen(dest, y.len)
|
||||
# var i = 0
|
||||
# while i < y.len: dest[i] = y[i]; inc(i)
|
||||
# This is usually more efficient than a destroy/create pair.
|
||||
checkSelfAssignment(c, t, body, x, y)
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedSink:
|
||||
@@ -1035,7 +1024,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of tyOrdinal, tyRange, tyInferred,
|
||||
tyGenericInst, tyAlias, tySink:
|
||||
fillBody(c, lastSon(t), body, x, y)
|
||||
of tyConcept, tyIterable: doAssert false
|
||||
of tyConcept, tyIterable: raiseAssert "unreachable"
|
||||
|
||||
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
|
||||
kind: TTypeAttachedOp; info: TLineInfo;
|
||||
@@ -1082,7 +1071,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
if kind == attachedDup:
|
||||
return symDupPrototype(g, typ, owner, kind, info, idgen)
|
||||
|
||||
@@ -1091,8 +1080,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
|
||||
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
|
||||
idgen, result, info)
|
||||
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
|
||||
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or (typ.kind in {tyRef, tyString, tySequence})):
|
||||
|
||||
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
dest.typ = typ
|
||||
else:
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
@@ -1178,22 +1167,14 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
# 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
|
||||
result.ast[pragmasPos] = newNodeI(nkPragma, info)
|
||||
result.ast[pragmasPos].add newTree(nkExprColonExpr,
|
||||
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
|
||||
|
||||
if kind == attachedDestructor:
|
||||
incl result.options, optQuirky
|
||||
if not a.canRaise: incl result.flags, sfNeverRaises
|
||||
completePartialOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
|
||||
proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
|
||||
# discrimantor assignments needs pointers to destroy fields; alas, we cannot use non-var destructor here
|
||||
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen, isDiscriminant = true)
|
||||
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen)
|
||||
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen,
|
||||
fn: result)
|
||||
a.asgnForType = typ
|
||||
@@ -1245,7 +1226,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
|
||||
else:
|
||||
localError(g.config, info, "unresolved generic parameter")
|
||||
|
||||
proc isTrival*(s: PSym): bool {.inline.} =
|
||||
proc isTrival(s: PSym): bool {.inline.} =
|
||||
s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
|
||||
|
||||
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
|
||||
@@ -1280,7 +1261,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
# bug #15122: We need to produce all prototypes before entering the
|
||||
# mind boggling recursion. Hacks like these imply we should rewrite
|
||||
# this module.
|
||||
var generics: array[attachedWasMoved..attachedTrace, bool]
|
||||
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
|
||||
for k in attachedWasMoved..lastAttached:
|
||||
generics[k] = getAttachedOp(g, canon, k) != nil
|
||||
if not generics[k]:
|
||||
|
||||
@@ -49,6 +49,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
|
||||
liftLocals(it, i, c)
|
||||
|
||||
proc lookupParam(params, dest: PNode): PSym =
|
||||
result = nil
|
||||
if dest.kind != nkIdent: return nil
|
||||
for i in 1..<params.len:
|
||||
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains the ``TMsgKind`` enum as well as the
|
||||
## ``TLineInfo`` object.
|
||||
## This module contains the `TMsgKind` enum as well as the
|
||||
## `TLineInfo` object.
|
||||
|
||||
import ropes, tables, pathutils, hashes
|
||||
|
||||
@@ -91,7 +91,6 @@ type
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnImplicitDefaultValue = "ImplicitDefaultValue",
|
||||
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
@@ -105,10 +104,10 @@ type
|
||||
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
|
||||
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
|
||||
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
|
||||
hintAmbiguousEnum = "AmbiguousEnum",
|
||||
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
|
||||
hintMsgOrigin = "MsgOrigin", # since 1.3.5
|
||||
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
|
||||
hintUnknownHint = "UnknownHint"
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
@@ -186,7 +185,7 @@ const
|
||||
warnAnyEnumConv: "$1",
|
||||
warnHoleEnumConv: "$1",
|
||||
warnCstringConv: "$1",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnCastSizes: "$1", # deadcode
|
||||
warnAboveMaxSizeSet: "$1",
|
||||
@@ -195,7 +194,6 @@ const
|
||||
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
|
||||
warnBareExcept: "$1",
|
||||
warnImplicitDefaultValue: "$1",
|
||||
warnIgnoredSymbolInjection: "$1",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
@@ -227,12 +225,12 @@ const
|
||||
hintGCStats: "$1",
|
||||
hintGlobalVar: "global variable declared here",
|
||||
hintExpandMacro: "expanded macro: $1",
|
||||
hintAmbiguousEnum: "$1",
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1",
|
||||
hintExtendedContext: "$1",
|
||||
hintMsgOrigin: "$1",
|
||||
hintDeclaredLoc: "$1",
|
||||
hintUnknownHint: "unknown hint: $1"
|
||||
]
|
||||
|
||||
const
|
||||
@@ -250,6 +248,7 @@ type
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result = default(array[0..3, TNoteKinds])
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
|
||||
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
@@ -312,7 +311,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||
proc hash*(i: TLineInfo): Hash =
|
||||
hash (i.line.int, i.col.int, i.fileIndex.int)
|
||||
|
||||
proc raiseRecoverableError*(msg: string) {.noinline.} =
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
const
|
||||
@@ -343,9 +342,8 @@ type
|
||||
|
||||
|
||||
proc initMsgConfig*(): MsgConfig =
|
||||
result.msgContext = @[]
|
||||
result.lastError = unknownLineInfo
|
||||
result.filenameToIndexTbl = initTable[string, FileIndex]()
|
||||
result.fileInfos = @[]
|
||||
result.errorOutputs = {eStdOut, eStdErr}
|
||||
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
|
||||
filenameToIndexTbl: initTable[string, FileIndex](),
|
||||
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
|
||||
)
|
||||
result.filenameToIndexTbl["???"] = FileIndex(-1)
|
||||
|
||||
@@ -12,17 +12,19 @@
|
||||
import std/strutils
|
||||
from std/sugar import dup
|
||||
|
||||
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages, modulegraphs
|
||||
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages
|
||||
export packages
|
||||
|
||||
const
|
||||
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
|
||||
proc identLen*(line: string, start: int): int =
|
||||
result = 0
|
||||
while start+result < line.len and line[start+result] in Letters:
|
||||
inc result
|
||||
|
||||
proc `=~`(s: string, a: openArray[string]): bool =
|
||||
result = false
|
||||
for x in a:
|
||||
if s.startsWith(x): return true
|
||||
|
||||
@@ -95,7 +97,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
|
||||
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.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) 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
|
||||
@@ -136,7 +138,7 @@ 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.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) 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
|
||||
@@ -152,5 +154,5 @@ template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragma
|
||||
## Note: This only applies to builtin pragmas, not user pragmas.
|
||||
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.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)): # ignore foreign packages
|
||||
(sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
|
||||
checkPragmaUseImpl(ctx.config, info, w, pragmaName)
|
||||
|
||||
@@ -40,33 +40,22 @@ type
|
||||
|
||||
PLLStream* = ref TLLStream
|
||||
|
||||
proc llStreamOpen*(data: string): PLLStream =
|
||||
new(result)
|
||||
result.s = data
|
||||
result.kind = llsString
|
||||
proc llStreamOpen*(data: sink string): PLLStream =
|
||||
PLLStream(kind: llsString, s: data)
|
||||
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
PLLStream(kind: llsFile, f: f)
|
||||
|
||||
proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
result = PLLStream(kind: llsFile)
|
||||
if not open(result.f, filename.string, mode): result = nil
|
||||
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsNone
|
||||
PLLStream(kind: llsNone)
|
||||
|
||||
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int
|
||||
proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsStdIn
|
||||
result.s = ""
|
||||
result.lineOffset = -1
|
||||
result.repl = r
|
||||
result.onPrompt = onPrompt
|
||||
PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt)
|
||||
|
||||
proc llStreamClose*(s: PLLStream) =
|
||||
case s.kind
|
||||
@@ -89,6 +78,8 @@ proc endsWith*(x: string, s: set[char]): bool =
|
||||
while i >= 0 and x[i] == ' ': dec(i)
|
||||
if i >= 0 and x[i] in s:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
const
|
||||
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
|
||||
@@ -104,6 +95,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
||||
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
|
||||
|
||||
proc countTriples(s: string): int =
|
||||
result = 0
|
||||
var i = 0
|
||||
while i+2 < s.len:
|
||||
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
|
||||
|
||||
@@ -48,7 +48,7 @@ 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, nkOpenSym:
|
||||
of nkSymChoices:
|
||||
if x[0].kind == nkSym:
|
||||
id.add(x[0].sym.name.s)
|
||||
else:
|
||||
@@ -61,8 +61,6 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
|
||||
result = n[0].sym.name
|
||||
else:
|
||||
handleError(n, origin)
|
||||
of nkOpenSym:
|
||||
result = considerQuotedIdent(c, n[0], origin)
|
||||
else:
|
||||
handleError(n, origin)
|
||||
|
||||
@@ -74,7 +72,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
|
||||
|
||||
proc openScope*(c: PContext): PScope {.discardable.} =
|
||||
result = PScope(parent: c.currentScope,
|
||||
symbols: newStrTable(),
|
||||
symbols: initStrTable(),
|
||||
depthLevel: c.scopeDepth + 1)
|
||||
c.currentScope = result
|
||||
|
||||
@@ -137,7 +135,7 @@ proc nextIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule;
|
||||
return result
|
||||
|
||||
iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent; g: ModuleGraph): PSym =
|
||||
var ti: ModuleIter = default(ModuleIter)
|
||||
var ti: ModuleIter
|
||||
var candidate = initIdentIter(ti, marked, im, name, g)
|
||||
while candidate != nil:
|
||||
yield candidate
|
||||
@@ -150,7 +148,7 @@ iterator importedItems*(c: PContext; name: PIdent): PSym =
|
||||
yield s
|
||||
|
||||
proc allPureEnumFields(c: PContext; name: PIdent): seq[PSym] =
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
var ti: TIdentIter
|
||||
result = @[]
|
||||
var res = initIdentIter(ti, c.pureEnumFields, name)
|
||||
while res != nil:
|
||||
@@ -222,7 +220,7 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
|
||||
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
|
||||
result = @[]
|
||||
for scope in allScopes(c.currentScope):
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
var ti: TIdentIter
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter:
|
||||
@@ -240,7 +238,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
|
||||
result = @[]
|
||||
block outer:
|
||||
for scope in allScopes(c.currentScope):
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
var ti: TIdentIter
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter:
|
||||
@@ -256,63 +254,8 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
|
||||
if s.kind in filter:
|
||||
result.add s
|
||||
|
||||
proc cmpScopes*(ctx: PContext, s: PSym): int =
|
||||
# Do not return a negative number
|
||||
if s.originatingModule == ctx.module:
|
||||
result = 2
|
||||
var owner = s
|
||||
while true:
|
||||
owner = owner.skipGenericOwner
|
||||
if owner.kind == skModule: break
|
||||
inc result
|
||||
else:
|
||||
result = 1
|
||||
|
||||
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
|
||||
result = false
|
||||
block outer:
|
||||
for scope in allScopes(c.currentScope):
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
var scopeHasCandidate = false
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter:
|
||||
if scopeHasCandidate:
|
||||
# 2 candidates in same scope, ambiguous
|
||||
return true
|
||||
else:
|
||||
scopeHasCandidate = true
|
||||
sym = candidate
|
||||
candidate = nextIdentIter(ti, scope.symbols)
|
||||
if scopeHasCandidate:
|
||||
# scope had a candidate but wasn't ambiguous
|
||||
return false
|
||||
|
||||
var importsHaveCandidate = false
|
||||
var marked = initIntSet()
|
||||
for im in c.imports.mitems:
|
||||
for s in symbols(im, marked, s, c.graph):
|
||||
if s.kind in filter:
|
||||
if importsHaveCandidate:
|
||||
# 2 candidates among imports, ambiguous
|
||||
return true
|
||||
else:
|
||||
importsHaveCandidate = true
|
||||
sym = s
|
||||
if importsHaveCandidate:
|
||||
# imports had a candidate but wasn't ambiguous
|
||||
return false
|
||||
|
||||
proc errorSym*(c: PContext, ident: PIdent, info: TLineInfo): PSym =
|
||||
## creates an error symbol to avoid cascading errors (for IDE support)
|
||||
result = newSym(skError, ident, c.idgen, getCurrOwner(c), info, {})
|
||||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's from the top level scope to prevent cascading errors:
|
||||
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
|
||||
c.moduleScope.addSym(result)
|
||||
|
||||
proc errorSym*(c: PContext, n: PNode): PSym =
|
||||
## creates an error symbol to avoid cascading errors (for IDE support)
|
||||
var m = n
|
||||
# ensure that 'considerQuotedIdent' can't fail:
|
||||
if m.kind == nkDotExpr: m = m[1]
|
||||
@@ -320,7 +263,12 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
||||
considerQuotedIdent(c, m)
|
||||
else:
|
||||
getIdent(c.cache, "err:" & renderTree(m))
|
||||
result = errorSym(c, ident, n.info)
|
||||
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
|
||||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's from the top level scope to prevent cascading errors:
|
||||
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
|
||||
c.moduleScope.addSym(result)
|
||||
|
||||
type
|
||||
TOverloadIterMode* = enum
|
||||
@@ -347,10 +295,10 @@ proc getSymRepr*(conf: ConfigRef; s: PSym, getDeclarationPath = true): string =
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
|
||||
# check if all symbols have been used and defined:
|
||||
var it: TTabIter = default(TTabIter)
|
||||
var it: TTabIter
|
||||
var s = initTabIter(it, scope.symbols)
|
||||
var missingImpls = 0
|
||||
var unusedSyms: seq[tuple[sym: PSym, key: string]]
|
||||
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
|
||||
while s != nil:
|
||||
if sfForward in s.flags and s.kind notin {skType, skModule}:
|
||||
# too many 'implementation of X' errors are annoying
|
||||
@@ -456,7 +404,7 @@ proc openShadowScope*(c: PContext) =
|
||||
## opens a shadow scope, just like any other scope except the depth is the
|
||||
## same as the parent -- see `isShadowScope`.
|
||||
c.currentScope = PScope(parent: c.currentScope,
|
||||
symbols: newStrTable(),
|
||||
symbols: initStrTable(),
|
||||
depthLevel: c.scopeDepth)
|
||||
|
||||
proc closeShadowScope*(c: PContext) =
|
||||
@@ -502,7 +450,7 @@ proc mustFixSpelling(c: PContext): bool {.inline.} =
|
||||
result = c.config.spellSuggestMax != 0 and c.compilesContextId == 0
|
||||
# don't slowdown inside compiles()
|
||||
|
||||
proc fixSpelling(c: PContext, ident: PIdent, result: var string) =
|
||||
proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
|
||||
## when we cannot find the identifier, suggest nearby spellings
|
||||
var list = initHeapQueue[SpellCandidate]()
|
||||
let name0 = ident.s.nimIdentNormalize
|
||||
@@ -510,7 +458,7 @@ proc fixSpelling(c: PContext, ident: PIdent, result: var string) =
|
||||
for (sym, depth, isLocal) in allSyms(c):
|
||||
let depth = -depth - 1
|
||||
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
|
||||
var msg: string
|
||||
var msg: string = ""
|
||||
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
|
||||
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
|
||||
|
||||
@@ -540,6 +488,7 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
|
||||
var err = "ambiguous identifier: '" & s.name.s & "'"
|
||||
var i = 0
|
||||
var ignoredModules = 0
|
||||
result = nil
|
||||
for candidate in importedItems(c, s.name):
|
||||
if i == 0: err.add " -- use one of the following:\n"
|
||||
else: err.add "\n"
|
||||
@@ -557,10 +506,10 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
|
||||
amb = false
|
||||
|
||||
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
|
||||
var amb: bool = false
|
||||
var amb: bool
|
||||
discard errorUseQualifier(c, info, s, amb)
|
||||
|
||||
proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
|
||||
proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
|
||||
var err = "ambiguous identifier: '" & candidates[0].name.s & "'"
|
||||
var i = 0
|
||||
for candidate in candidates:
|
||||
@@ -583,11 +532,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
|
||||
if name == "_":
|
||||
err = "the special identifier '_' is ignored in declarations and cannot be used"
|
||||
else:
|
||||
err = "undeclared identifier: '" & name & "'"
|
||||
if "`gensym" in name:
|
||||
err.add "; if declared in a template, this identifier may be inconsistently marked inject or gensym"
|
||||
if extra.len != 0:
|
||||
err.add extra
|
||||
err = "undeclared identifier: '" & name & "'" & extra
|
||||
if c.recursiveDep.len > 0:
|
||||
err.add "\nThis might be caused by a recursive module dependency:\n"
|
||||
err.add c.recursiveDep
|
||||
@@ -595,11 +540,11 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
|
||||
c.recursiveDep = ""
|
||||
localError(c.config, info, errGenerated, err)
|
||||
|
||||
proc errorUndeclaredIdentifierHint*(c: PContext; ident: PIdent; info: TLineInfo): PSym =
|
||||
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
|
||||
var extra = ""
|
||||
if c.mustFixSpelling: fixSpelling(c, ident, extra)
|
||||
errorUndeclaredIdentifier(c, info, ident.s, extra)
|
||||
result = errorSym(c, ident, info)
|
||||
if c.mustFixSpelling: fixSpelling(c, n, ident, extra)
|
||||
errorUndeclaredIdentifier(c, n.info, ident.s, extra)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
# Looks up a symbol. Generates an error in case of nil.
|
||||
@@ -607,16 +552,16 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
result = searchInScopes(c, n.ident, amb)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n.ident, n.info)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
of nkAccQuoted:
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
result = searchInScopes(c, ident, amb)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, ident, n.info)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
|
||||
else:
|
||||
internalError(c.config, n.info, "lookUp")
|
||||
return nil
|
||||
return
|
||||
if amb:
|
||||
#contains(c.ambiguousSymbols, result.id):
|
||||
result = errorUseQualifier(c, n.info, result, amb)
|
||||
@@ -627,29 +572,16 @@ type
|
||||
TLookupFlag* = enum
|
||||
checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields
|
||||
|
||||
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
|
||||
|
||||
proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] =
|
||||
result = searchInScopesFilterBy(c, ident, filter)
|
||||
if result.len == 0:
|
||||
result.add allPureEnumFields(c, ident)
|
||||
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var amb = false
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
if checkModule in flags:
|
||||
result = searchInScopes(c, ident, amb)
|
||||
if result == nil:
|
||||
let candidates = allPureEnumFields(c, ident)
|
||||
if candidates.len > 0:
|
||||
result = candidates[0]
|
||||
amb = candidates.len > 1
|
||||
if amb and checkAmbiguity in flags:
|
||||
errorUseQualifier(c, n.info, candidates)
|
||||
else:
|
||||
let candidates = lookUpCandidates(c, ident, allExceptModule)
|
||||
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
|
||||
if candidates.len > 0:
|
||||
result = candidates[0]
|
||||
amb = candidates.len > 1
|
||||
@@ -657,15 +589,21 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
errorUseQualifier(c, n.info, candidates)
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
let candidates = allPureEnumFields(c, ident)
|
||||
if candidates.len > 0:
|
||||
result = candidates[0]
|
||||
amb = candidates.len > 1
|
||||
if amb and checkAmbiguity in flags:
|
||||
errorUseQualifier(c, n.info, candidates)
|
||||
|
||||
if result == nil and checkUndeclared in flags:
|
||||
result = errorUndeclaredIdentifierHint(c, ident, n.info)
|
||||
result = errorUndeclaredIdentifierHint(c, n, ident)
|
||||
elif checkAmbiguity in flags and result != nil and amb:
|
||||
result = errorUseQualifier(c, n.info, result, amb)
|
||||
c.isAmbiguous = amb
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
of nkOpenSym:
|
||||
result = qualifiedLookUp(c, n[0], flags)
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule})
|
||||
@@ -680,17 +618,17 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
|
||||
var amb: bool = false
|
||||
var amb: bool
|
||||
result = errorUseQualifier(c, n.info, m, amb)
|
||||
else:
|
||||
result = someSym(c.graph, m, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
result = errorUndeclaredIdentifierHint(c, ident, n[1].info)
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], ident)
|
||||
elif n[1].kind == nkSym:
|
||||
result = n[1].sym
|
||||
if result.owner != nil and result.owner != m and checkUndeclared in flags:
|
||||
# dotExpr in templates can end up here
|
||||
result = errorUndeclaredIdentifierHint(c, result.name, n[1].info)
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
|
||||
elif checkUndeclared in flags and
|
||||
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
|
||||
localError(c.config, n[1].info, "identifier expected, but got: " &
|
||||
@@ -702,14 +640,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if n.kind == nkOpenSym:
|
||||
# maybe the logic in semexprs should be mirrored here instead
|
||||
# for now it only seems this is called for `pickSym` in `getTypeIdent`
|
||||
return initOverloadIter(o, c, n[0])
|
||||
o.importIdx = -1
|
||||
o.marked = initIntSet()
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
result = nil
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
var scope = c.currentScope
|
||||
o.mode = oimNoQualifier
|
||||
@@ -733,6 +668,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = n.sym
|
||||
o.mode = oimDone
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
o.mode = oimOtherModule
|
||||
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
|
||||
if o.m != nil and o.m.kind == skModule:
|
||||
@@ -762,7 +698,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.symChoiceIndex = 1
|
||||
o.marked = initIntSet()
|
||||
incl(o.marked, result.id)
|
||||
else: discard
|
||||
else: result = nil
|
||||
when false:
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
@@ -777,6 +713,7 @@ proc lastOverloadScope*(o: TOverloadIter): int =
|
||||
else: result = -1
|
||||
|
||||
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = nil
|
||||
assert o.currentScope == nil
|
||||
var idx = o.importIdx+1
|
||||
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
|
||||
@@ -789,6 +726,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
|
||||
inc idx
|
||||
|
||||
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
|
||||
result = nil
|
||||
assert o.currentScope == nil
|
||||
while o.importIdx < c.imports.len:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
|
||||
@@ -851,6 +789,8 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
break
|
||||
if result != nil:
|
||||
incl o.marked, result.id
|
||||
else:
|
||||
result = nil
|
||||
of oimSymChoiceLocalLookup:
|
||||
if o.currentScope != nil:
|
||||
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
|
||||
@@ -874,13 +814,16 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if result == nil:
|
||||
inc o.importIdx
|
||||
result = symChoiceExtension(o, c, n)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
when false:
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
|
||||
flags: TSymFlags = {}): PSym =
|
||||
var o: TOverloadIter
|
||||
result = nil
|
||||
var o: TOverloadIter = default(TOverloadIter)
|
||||
var a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind in kinds and flags <= a.flags:
|
||||
|
||||
@@ -122,6 +122,25 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
|
||||
proc newTryFinally*(body, final: PNode): PNode =
|
||||
result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
|
||||
|
||||
proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
|
||||
let value = n.lastSon
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options)
|
||||
var v = newNodeI(nkLetSection, value.info)
|
||||
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = newNodeI(nkTupleClassTy, value.info)
|
||||
vpart[2] = value
|
||||
v.add vpart
|
||||
result.add(v)
|
||||
|
||||
let lhs = n[0]
|
||||
for i in 0..<lhs.len:
|
||||
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
|
||||
|
||||
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
|
||||
|
||||
@@ -30,6 +30,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
|
||||
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
|
||||
result = nil
|
||||
let id = getIdent(g.cache, name)
|
||||
for r in systemModuleSyms(g, id):
|
||||
if r.magic == m:
|
||||
@@ -80,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
|
||||
|
||||
proc resetSysTypes*(g: ModuleGraph) =
|
||||
g.systemModule = nil
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.exposed = initStrTable()
|
||||
for i in low(g.sysTypes)..high(g.sysTypes):
|
||||
g.sysTypes[i] = nil
|
||||
|
||||
@@ -99,7 +100,7 @@ proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
|
||||
|
||||
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
|
||||
let s = son.skipIntLit(id)
|
||||
father.sons.add(s)
|
||||
father.add(s)
|
||||
propagateToOwner(father, s)
|
||||
|
||||
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
@@ -123,7 +124,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
|
||||
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
|
||||
strTableGet(g.exposed, getIdent(g.cache, name))
|
||||
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
|
||||
|
||||
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
case t.kind
|
||||
@@ -145,6 +146,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
of tyProc:
|
||||
result = getSysMagic(g, info, "==", mEqProc)
|
||||
else:
|
||||
result = nil
|
||||
globalError(g.config, info,
|
||||
"can't find magic equals operator for type kind " & $t.kind)
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
|
||||
for it in conf.toCompile: cfiles.add(it.cname.string)
|
||||
let fileset = cfiles.toCountTable()
|
||||
# read old cfiles list
|
||||
var fl: File
|
||||
var fl: File = default(File)
|
||||
var prevset = initCountTable[string]()
|
||||
if open(fl, fname.string, fmRead):
|
||||
for line in fl.lines: prevset.inc(line)
|
||||
@@ -115,7 +115,7 @@ when not defined(leanCompiler):
|
||||
setPipeLinePass(graph, Docgen2JsonPass)
|
||||
of HtmlExt:
|
||||
setPipeLinePass(graph, Docgen2Pass)
|
||||
else: doAssert false, $ext
|
||||
else: raiseAssert $ext
|
||||
compilePipelineProject(graph)
|
||||
|
||||
proc commandCompileToC(graph: ModuleGraph) =
|
||||
@@ -151,7 +151,7 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
extccomp.callCCompiler(conf)
|
||||
# for now we do not support writing out a .json file with the build instructions when HCR is on
|
||||
if not conf.hcrOn:
|
||||
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
|
||||
extccomp.writeJsonBuildInstructions(conf)
|
||||
if optGenScript in graph.config.globalOptions:
|
||||
writeDepsFile(graph)
|
||||
if optGenCDeps in graph.config.globalOptions:
|
||||
@@ -195,7 +195,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
L: Lexer = default(Lexer)
|
||||
L: Lexer
|
||||
tok: Token = default(Token)
|
||||
initToken(tok)
|
||||
openLexer(L, f, stream, cache, config)
|
||||
@@ -267,7 +267,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
# and it has added this define implictly, so we must undo that here.
|
||||
# A better solution might be to fix system.nim
|
||||
undefSymbol(conf.symbols, "useNimRtl")
|
||||
of backendInvalid: doAssert false
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
proc compileToBackend() =
|
||||
customizeForBackend(conf.backend)
|
||||
@@ -277,7 +277,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of backendCpp: commandCompileToC(graph)
|
||||
of backendObjc: commandCompileToC(graph)
|
||||
of backendJs: commandCompileToJS(graph)
|
||||
of backendInvalid: doAssert false
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
template docLikeCmd(body) =
|
||||
when defined(leanCompiler):
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
## represents a complete Nim project. Single modules can either be kept in RAM
|
||||
## or stored in a rod-file.
|
||||
|
||||
import std/[intsets, tables, hashes, strtabs]
|
||||
import intsets, tables, hashes
|
||||
import ../dist/checksums/src/checksums/md5
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
|
||||
import ic / [packed_ast, ic]
|
||||
@@ -57,7 +57,6 @@ type
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
isDecl*: bool
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
@@ -129,8 +128,6 @@ type
|
||||
idgen*: IdGenerator
|
||||
operators*: Operators
|
||||
|
||||
cachedFiles*: StringTableRef
|
||||
|
||||
TPassContext* = object of RootObj # the pass's context
|
||||
idgen*: IdGenerator
|
||||
PPassContext* = ref TPassContext
|
||||
@@ -145,7 +142,7 @@ type
|
||||
isFrontend: bool]
|
||||
|
||||
proc resetForBackend*(g: ModuleGraph) =
|
||||
initStrTable(g.compilerprocs)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.typeInstCache.clear()
|
||||
g.procInstCache.clear()
|
||||
for a in mitems(g.attachedOps):
|
||||
@@ -199,8 +196,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
|
||||
g.ifaces[m.position].interfHidden
|
||||
|
||||
proc initStrTables*(g: ModuleGraph, m: PSym) =
|
||||
initStrTable(semtab(g, m))
|
||||
initStrTable(semtabAll(g, m))
|
||||
semtab(g, m) = initStrTable()
|
||||
semtabAll(g, m) = initStrTable()
|
||||
|
||||
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
|
||||
strTableAdd(semtab(g, m), s)
|
||||
@@ -251,7 +248,7 @@ proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
|
||||
iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
|
||||
let importHidden = optImportHidden in m.options
|
||||
if isCachedModule(g, m):
|
||||
var rodIt: RodIter = default(RodIter)
|
||||
var rodIt: RodIter
|
||||
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
|
||||
while r != nil:
|
||||
yield r
|
||||
@@ -272,7 +269,7 @@ proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
|
||||
result = someSym(g, g.systemModule, name)
|
||||
|
||||
iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
|
||||
var mi: ModuleIter = default(ModuleIter)
|
||||
var mi: ModuleIter
|
||||
var r = initModuleIter(mi, g, g.systemModule, name)
|
||||
while r != nil:
|
||||
yield r
|
||||
@@ -371,6 +368,7 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
|
||||
setAttachedOp(g, module, dest, k, op)
|
||||
|
||||
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
result = nil
|
||||
if g.config.symbolFiles == disabledSf: return nil
|
||||
|
||||
# slow, linear search, but the results are cached:
|
||||
@@ -461,7 +459,7 @@ 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)
|
||||
initStrTable(result.packageSyms)
|
||||
result.packageSyms = initStrTable()
|
||||
result.deps = initIntSet()
|
||||
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
|
||||
result.ifaces = @[]
|
||||
@@ -471,9 +469,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
|
||||
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
|
||||
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
|
||||
result.methods = @[]
|
||||
initStrTable(result.compilerprocs)
|
||||
initStrTable(result.exposed)
|
||||
initStrTable(result.packageTypes)
|
||||
result.compilerprocs = initStrTable()
|
||||
result.exposed = initStrTable()
|
||||
result.packageTypes = initStrTable()
|
||||
result.emptyNode = newNode(nkEmpty)
|
||||
result.cacheSeqs = initTable[string, PNode]()
|
||||
result.cacheCounters = initTable[string, BiggestInt]()
|
||||
@@ -482,7 +480,6 @@ proc initModuleGraphFields(result: ModuleGraph) =
|
||||
result.symBodyHashes = initTable[int, SigHash]()
|
||||
result.operators = initOperators(result)
|
||||
result.emittedTypeInfo = initTable[string, FileIndex]()
|
||||
result.cachedFiles = newStringTable()
|
||||
|
||||
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result = ModuleGraph()
|
||||
@@ -491,7 +488,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
initModuleGraphFields(result)
|
||||
|
||||
proc resetAllModules*(g: ModuleGraph) =
|
||||
initStrTable(g.packageSyms)
|
||||
g.packageSyms = initStrTable()
|
||||
g.deps = initIntSet()
|
||||
g.ifaces = @[]
|
||||
g.importStack = @[]
|
||||
@@ -499,11 +496,12 @@ proc resetAllModules*(g: ModuleGraph) =
|
||||
g.usageSym = nil
|
||||
g.owners = @[]
|
||||
g.methods = @[]
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.exposed = initStrTable()
|
||||
initModuleGraphFields(g)
|
||||
|
||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
result = nil
|
||||
if fileIdx.int32 >= 0:
|
||||
if isCachedModule(g, fileIdx.int32):
|
||||
result = g.packed[fileIdx.int32].module
|
||||
@@ -609,6 +607,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
|
||||
proc needsCompilation*(g: ModuleGraph): bool =
|
||||
# every module that *depends* on this file is also dirty:
|
||||
result = false
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil:
|
||||
@@ -616,6 +615,7 @@ proc needsCompilation*(g: ModuleGraph): bool =
|
||||
return true
|
||||
|
||||
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
|
||||
result = false
|
||||
let module = g.getModule(fileIdx)
|
||||
if module != nil and g.isDirty(module):
|
||||
return true
|
||||
@@ -637,6 +637,8 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
|
||||
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc configComplete*(g: ModuleGraph) =
|
||||
rememberStartupConfig(g.startupPackedConfig, g.config)
|
||||
|
||||
@@ -36,18 +36,11 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
localError(n.info, "only '/' supported with $package notation")
|
||||
result = ""
|
||||
else:
|
||||
if n0.kind in nkIdentKinds:
|
||||
let ident = n0.getPIdent
|
||||
if ident != nil and ident.s[0] == '/':
|
||||
let modname = getModuleName(conf, n[2])
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = getModuleName(conf, n1)
|
||||
result.add renderTree(n0, {renderNoComments}).replace(" ")
|
||||
result.add modname
|
||||
else:
|
||||
result = ""
|
||||
else:
|
||||
result = ""
|
||||
let modname = getModuleName(conf, n[2])
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = getModuleName(conf, n1)
|
||||
result.add renderTree(n0, {renderNoComments}).replace(" ")
|
||||
result.add modname
|
||||
of nkPrefix:
|
||||
when false:
|
||||
if n[0].kind == nkIdent and n[0].ident.s == "$":
|
||||
|
||||
@@ -14,9 +14,6 @@ import
|
||||
idents, lexer, syntaxes, modulegraphs,
|
||||
lineinfos, pathutils
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
import std/strtabs
|
||||
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
magicsys.resetSysTypes(g)
|
||||
|
||||
@@ -45,8 +42,6 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
|
||||
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
|
||||
graph.addDep(s, fileIdx)
|
||||
graph.addIncludeDep(s.position.FileIndex, fileIdx)
|
||||
let path = toFullPath(graph.config, fileIdx)
|
||||
graph.cachedFiles[path] = $secureHashFile(path)
|
||||
|
||||
proc wantMainModule*(conf: ConfigRef) =
|
||||
if conf.projectFull.isEmpty:
|
||||
|
||||
@@ -125,14 +125,14 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
|
||||
conf.m.filenameToIndexTbl[canon2] = result
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
|
||||
var dummy: bool = false
|
||||
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 = false
|
||||
var dummy: bool
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
@@ -294,9 +294,11 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
|
||||
result = info.col
|
||||
|
||||
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
|
||||
result = ""
|
||||
result.toLocation(info.filename, info.line, info.column + ColOffset)
|
||||
|
||||
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
|
||||
result = ""
|
||||
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
|
||||
|
||||
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
|
||||
@@ -408,7 +410,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
|
||||
type TErrorHandling* = enum doNothing, doAbort, doRaise
|
||||
|
||||
proc log*(s: string) =
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
|
||||
f.writeLine(s)
|
||||
close(f)
|
||||
@@ -429,8 +431,7 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
|
||||
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
|
||||
if msg in fatalMsgs:
|
||||
if conf.cmd == cmdIdeTools: log(s)
|
||||
if conf.cmd != cmdIdeTools or msg != errFatal:
|
||||
quit(conf, msg)
|
||||
quit(conf, msg)
|
||||
if msg >= errMin and msg <= errMax or
|
||||
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
|
||||
inc(conf.errorCounter)
|
||||
@@ -438,11 +439,7 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
|
||||
if conf.errorCounter >= conf.errorMax:
|
||||
# only really quit when we're not in the new 'nim check --def' mode:
|
||||
if conf.ideCmd == ideNone:
|
||||
when defined(nimsuggest):
|
||||
#we need to inform the user that something went wrong when initializing NimSuggest
|
||||
raiseRecoverableError(s)
|
||||
else:
|
||||
quit(conf, msg)
|
||||
quit(conf, msg)
|
||||
elif eh == doAbort and conf.cmd != cmdIdeTools:
|
||||
quit(conf, msg)
|
||||
elif eh == doRaise:
|
||||
@@ -507,6 +504,8 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
|
||||
result = "\n" & indent & $sourceLine(conf, info)
|
||||
if info.col >= 0:
|
||||
result.add "\n" & indent & spaces(info.col) & '^'
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let title = case msg
|
||||
@@ -558,10 +557,9 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
ignoreMsg = not conf.hasHint(msg)
|
||||
if not ignoreMsg and msg in conf.warningAsErrors:
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
else:
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
color = HintColor
|
||||
inc(conf.hintCounter)
|
||||
|
||||
let s = if isRaw: arg else: getMessageStr(msg, arg)
|
||||
@@ -649,16 +647,13 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
|
||||
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
|
||||
liMessage(conf, info, msg, m, doNothing, instLoc())
|
||||
|
||||
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
|
||||
if fi.int32 < 0:
|
||||
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
if i.fileIndex.int32 < 0:
|
||||
result = makeCString "???"
|
||||
elif optExcessiveStackTrace in conf.globalOptions:
|
||||
result = conf.m.fileInfos[fi.int32].quotedFullName
|
||||
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
|
||||
else:
|
||||
result = conf.m.fileInfos[fi.int32].quotedName
|
||||
|
||||
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
quotedFilename(conf, i.fileIndex)
|
||||
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
|
||||
|
||||
template listMsg(title, r) =
|
||||
msgWriteln(conf, title, {msgNoUnitSep})
|
||||
|
||||
@@ -309,6 +309,7 @@ proc symbol(n: PNode): Symbol =
|
||||
# echo "symbol ", n, " ", n.kind, " ", result.int
|
||||
|
||||
func `$`(map: NilMap): string =
|
||||
result = ""
|
||||
var now = map
|
||||
var stack: seq[NilMap] = @[]
|
||||
while not now.isNil:
|
||||
@@ -416,7 +417,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
|
||||
if targetSetIndex != noSetIndex:
|
||||
var targetSet = map.sets[targetSetIndex]
|
||||
if targetSet.len > 1:
|
||||
var other: ExprIndex
|
||||
var other: ExprIndex = default(ExprIndex)
|
||||
|
||||
for element in targetSet:
|
||||
if element.ExprIndex != targetIndex:
|
||||
@@ -561,7 +562,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
|
||||
if n.info in ctx.warningLocations:
|
||||
return
|
||||
ctx.warningLocations.incl(n.info)
|
||||
var a: seq[History]
|
||||
var a: seq[History] = @[]
|
||||
if n.kind == nkSym:
|
||||
a = history(map, ctx.index(n))
|
||||
var res = ""
|
||||
@@ -765,7 +766,7 @@ proc checkIf(n, ctx, map): Check =
|
||||
# the state of the conditions: negating conditions before the current one
|
||||
var layerHistory = newNilMap(mapIf)
|
||||
# the state after branch effects
|
||||
var afterLayer: NilMap
|
||||
var afterLayer: NilMap = nil
|
||||
# the result nilability for expressions
|
||||
var nilability = Safe
|
||||
|
||||
@@ -862,9 +863,10 @@ proc checkInfix(n, ctx, map): Check =
|
||||
## a or b : map is an union of a and b's
|
||||
## a == b : use checkCondition
|
||||
## else: no change, just check args
|
||||
result = default(Check)
|
||||
if n[0].kind == nkSym:
|
||||
var mapL: NilMap
|
||||
var mapR: NilMap
|
||||
var mapL: NilMap = nil
|
||||
var mapR: NilMap = nil
|
||||
if n[0].sym.magic notin {mAnd, mEqRef}:
|
||||
mapL = checkCondition(n[1], ctx, map, false, false)
|
||||
mapR = checkCondition(n[2], ctx, map, false, false)
|
||||
@@ -947,7 +949,7 @@ proc checkCase(n, ctx, map): Check =
|
||||
let base = n[0]
|
||||
result.map = map.copyMap()
|
||||
result.nilability = Safe
|
||||
var a: PNode
|
||||
var a: PNode = nil
|
||||
for child in n:
|
||||
case child.kind:
|
||||
of nkOfBranch:
|
||||
@@ -1222,7 +1224,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
|
||||
# TODO deeper nested elements?
|
||||
# A(field: B()) #
|
||||
# field: Safe ->
|
||||
var elements: seq[(PNode, Nilability)]
|
||||
var elements: seq[(PNode, Nilability)] = @[]
|
||||
for i, child in n:
|
||||
result = check(child, ctx, result.map)
|
||||
if i > 0:
|
||||
@@ -1333,7 +1335,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
|
||||
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
|
||||
var cache = newIdentCache()
|
||||
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
|
||||
var emptySet: IntSet # set[ExprIndex]
|
||||
var emptySet: IntSet = initIntSet() # set[ExprIndex]
|
||||
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
|
||||
for i, arg in s.typ.n.sons:
|
||||
if i > 0:
|
||||
|
||||
@@ -9,7 +9,6 @@ define:nimPreviewSlimSystem
|
||||
define:nimPreviewCstringConversion
|
||||
define:nimPreviewProcConversion
|
||||
define:nimPreviewRangeDefault
|
||||
define:nimPreviewNonVarDestructor
|
||||
threads:off
|
||||
|
||||
#import:"$projectpath/testability"
|
||||
@@ -44,3 +43,11 @@ define:useStdoutAsStdmsg
|
||||
@if nimHasWarnBareExcept:
|
||||
warningAserror[BareExcept]:on
|
||||
@end
|
||||
|
||||
|
||||
@if nimUseStrictDefs:
|
||||
experimental:strictDefs
|
||||
warningAsError[Uninit]:on
|
||||
warningAsError[ProveInit]:on
|
||||
@end
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ proc getNimRunExe(conf: ConfigRef): string =
|
||||
if conf.isDefined("mingw"):
|
||||
if conf.isDefined("i386"): result = "wine"
|
||||
elif conf.isDefined("amd64"): result = "wine64"
|
||||
else: result = ""
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
let self = NimProg(
|
||||
@@ -137,7 +140,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
|
||||
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
|
||||
cmdPrefix.add " --unhandled-rejections=strict"
|
||||
else: doAssert false, $conf.backend
|
||||
else: raiseAssert $conf.backend
|
||||
if cmdPrefix.len > 0: cmdPrefix.add " "
|
||||
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
|
||||
# `The parameter is incorrect`
|
||||
|
||||
@@ -37,11 +37,16 @@ proc isSpecial(ver: Version): bool =
|
||||
|
||||
proc isValidVersion(v: string): bool =
|
||||
if v.len > 0:
|
||||
if v[0] in {'#'} + Digits: return true
|
||||
if v[0] in {'#'} + Digits:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc `<`*(ver: Version, ver2: Version): bool =
|
||||
## This is synced from Nimble's version module.
|
||||
|
||||
result = false
|
||||
# Handling for special versions such as "#head" or "#branch".
|
||||
if ver.isSpecial or ver2.isSpecial:
|
||||
if ver2.isSpecial and ($ver2).normalize == "#head":
|
||||
@@ -145,7 +150,7 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
|
||||
conf.lazyPaths.insert(AbsoluteDir path, 0)
|
||||
|
||||
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
|
||||
var packages: PackageInfo
|
||||
var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]()
|
||||
var pos = dir.len-1
|
||||
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
||||
for k,p in os.walkDir(dir):
|
||||
|
||||
@@ -214,7 +214,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
|
||||
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
config: ConfigRef): bool =
|
||||
var
|
||||
L: Lexer
|
||||
L: Lexer = default(Lexer)
|
||||
tok: Token
|
||||
stream: PLLStream
|
||||
stream = llStreamOpen(filename, fmRead)
|
||||
@@ -228,6 +228,8 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
|
||||
closeLexer(L)
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
|
||||
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
|
||||
@@ -250,7 +252,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
|
||||
|
||||
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
|
||||
let p = path # eval once
|
||||
var s: PLLStream
|
||||
var s: PLLStream = nil
|
||||
if isMain and optWasNimscript in conf.globalOptions:
|
||||
if conf.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)
|
||||
|
||||
@@ -40,7 +40,7 @@ proc selectUniqueSymbol*(i: Interpreter; name: string;
|
||||
assert i != nil
|
||||
assert i.mainModule != nil, "no main module selected"
|
||||
let n = getIdent(i.graph.cache, name)
|
||||
var it: ModuleIter = default(ModuleIter)
|
||||
var it: ModuleIter
|
||||
var s = initModuleIter(it, i.graph, i.mainModule, n)
|
||||
result = nil
|
||||
while s != nil:
|
||||
|
||||
@@ -62,7 +62,9 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
|
||||
var first, j: Int128
|
||||
result = @[]
|
||||
var first: Int128 = Zero
|
||||
var j: Int128 = Zero
|
||||
first = firstOrd(conf, s.typ[0])
|
||||
bitSetInit(result, int(getSize(conf, s.typ)))
|
||||
for i in 0..<s.len:
|
||||
|
||||
@@ -280,7 +280,7 @@ proc optimize*(n: PNode): PNode =
|
||||
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
|
||||
]#
|
||||
var c: Con = Con()
|
||||
var b: BasicBlock = default(BasicBlock)
|
||||
var b: BasicBlock
|
||||
analyse(c, b, n)
|
||||
if c.somethingTodo:
|
||||
result = shallowCopy(n)
|
||||
|
||||
@@ -195,7 +195,7 @@ type
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
dotOperators,
|
||||
@@ -209,7 +209,7 @@ type
|
||||
codeReordering,
|
||||
compiletimeFFI,
|
||||
## This requires building nim with `-d:nimHasLibFFI`
|
||||
## which itself requires `nimble install libffi`, see #10150
|
||||
## which itself requires `koch installdeps libffi`, see #10150
|
||||
## Note: this feature can't be localized with {.push.}
|
||||
vmopsDanger,
|
||||
strictFuncs,
|
||||
@@ -221,9 +221,8 @@ type
|
||||
flexibleOptionalParams,
|
||||
strictDefs,
|
||||
strictCaseObjects,
|
||||
openSym, # remove nfDisabledOpenSym when this is default
|
||||
# alternative to above:
|
||||
genericsOpenSym
|
||||
inferGenericTypes
|
||||
noforwardDecl
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -283,24 +282,9 @@ type
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
inlayHintInfo*: SuggestInlayHint
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
SuggestInlayHintKind* = enum
|
||||
sihkType = "Type",
|
||||
sihkParameter = "Parameter"
|
||||
|
||||
SuggestInlayHint* = ref object
|
||||
kind*: SuggestInlayHintKind
|
||||
line*: int # Starts at 1
|
||||
column*: int # Starts at 0
|
||||
label*: string
|
||||
paddingLeft*: bool
|
||||
paddingRight*: bool
|
||||
allowInsert*: bool
|
||||
tooltip*: string
|
||||
|
||||
ProfileInfo* = object
|
||||
time*: float
|
||||
count*: int
|
||||
@@ -435,11 +419,10 @@ type
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
clientProcessId*: int
|
||||
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
result = default(NimVer)
|
||||
if a.len > 0:
|
||||
let b = a.split(".")
|
||||
assert b.len == 3, a
|
||||
@@ -676,12 +659,12 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
of "nimrawsetjmp":
|
||||
result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
|
||||
osDragonfly, osMacosx}
|
||||
else: discard
|
||||
else: result = false
|
||||
|
||||
template quitOrRaise*(conf: ConfigRef, msg = "") =
|
||||
# xxx in future work, consider whether to also intercept `msgQuit` calls
|
||||
if conf.isDefined("nimDebug"):
|
||||
doAssert false, msg
|
||||
raiseAssert msg
|
||||
else:
|
||||
quit(msg) # quits with QuitFailure
|
||||
|
||||
@@ -902,6 +885,7 @@ const
|
||||
stdPrefix = "std/"
|
||||
|
||||
proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile =
|
||||
result = RelativeFile("")
|
||||
let f = $f
|
||||
if isTitle:
|
||||
for dir in stdlibDirs:
|
||||
@@ -937,6 +921,7 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi
|
||||
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
|
||||
else:
|
||||
if m.startsWith(stdPrefix):
|
||||
result = AbsoluteFile("")
|
||||
let stripped = m.substr(stdPrefix.len)
|
||||
for candidate in stdlibDirs:
|
||||
let path = (conf.libpath.string / candidate / stripped)
|
||||
@@ -1077,7 +1062,6 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
of ideInlayHints: "inlayHints"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
|
||||
@@ -17,6 +17,7 @@ iterator myParentDirs(p: string): string =
|
||||
|
||||
proc getNimbleFile*(conf: ConfigRef; path: string): string =
|
||||
## returns absolute path to nimble file, e.g.: /pathto/cligen.nimble
|
||||
result = ""
|
||||
var parents = 0
|
||||
block packageSearch:
|
||||
for d in myParentDirs(path):
|
||||
|
||||
@@ -51,11 +51,3 @@ func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
|
||||
## See Also:
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
conf.mainPackageId == sym.getPackageId
|
||||
|
||||
func belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
|
||||
## Return whether the symbol belongs to the project's package.
|
||||
## Returns `false` if `sym` is nil.
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
sym != nil and conf.mainPackageId == sym.getPackageId
|
||||
|
||||
@@ -184,6 +184,7 @@ type
|
||||
arStrange # it is a strange beast like 'typedesc[var T]'
|
||||
|
||||
proc exprRoot*(n: PNode; allowCalls = true): PSym =
|
||||
result = nil
|
||||
var it = n
|
||||
while true:
|
||||
case it.kind
|
||||
@@ -280,15 +281,8 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isAssignable(owner, n[0])
|
||||
of nkCallKinds:
|
||||
let m = getMagic(n)
|
||||
if m == mSlice:
|
||||
# builtin slice keeps l-value-ness
|
||||
# except for pointers because slice dereferences
|
||||
if n[1].typ.kind == tyPtr:
|
||||
result = arLValue
|
||||
else:
|
||||
result = isAssignable(owner, n[1])
|
||||
elif m == mArrGet:
|
||||
# builtin slice keeps lvalue-ness:
|
||||
if getMagic(n) in {mArrGet, mSlice}:
|
||||
result = isAssignable(owner, n[1])
|
||||
elif n.typ != nil:
|
||||
case n.typ.kind
|
||||
|
||||
@@ -1177,6 +1177,7 @@ proc optPragmas(p: var Parser): PNode =
|
||||
|
||||
proc parseDoBlock(p: var Parser; info: TLineInfo): PNode =
|
||||
#| doBlock = 'do' paramListArrow pragma? colcom stmt
|
||||
result = nil
|
||||
var params = parseParamList(p, retColon=false)
|
||||
let pragmas = optPragmas(p)
|
||||
colcom(p, result)
|
||||
@@ -1430,7 +1431,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkConcept:
|
||||
result = p.emptyNode
|
||||
result = nil
|
||||
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
|
||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc)
|
||||
of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc)
|
||||
@@ -2286,7 +2287,7 @@ proc parseTypeDef(p: var Parser): PNode =
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode =
|
||||
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' (':' optInd typeDescExpr)?
|
||||
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')'
|
||||
#| varTuple = varTupleLhs '=' optInd expr
|
||||
result = newNodeP(nkVarTuple, p)
|
||||
getTok(p) # skip '('
|
||||
@@ -2303,14 +2304,9 @@ proc parseVarTuple(p: var Parser): PNode =
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
result.add(p.emptyNode) # no type desc
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
if p.tok.tokType == tkColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(parseTypeDesc(p, fullExpr = true))
|
||||
else:
|
||||
result.add(p.emptyNode) # no type desc
|
||||
setEndInfo()
|
||||
|
||||
proc parseVariable(p: var Parser): PNode =
|
||||
@@ -2517,6 +2513,22 @@ proc parseStmt(p: var Parser): PNode =
|
||||
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.
|
||||
result = newNodeP(nkStmtList, p)
|
||||
while p.tok.tokType != tkEof:
|
||||
p.hasProgress = false
|
||||
var a = complexOrSimpleStmt(p)
|
||||
if a.kind != nkEmpty and p.hasProgress:
|
||||
result.add(a)
|
||||
else:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
# bugfix: consume a token here to prevent an endless loop:
|
||||
getTok(p)
|
||||
if p.tok.indent != 0:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
setEndInfo()
|
||||
|
||||
proc checkFirstLineIndentation*(p: var Parser) =
|
||||
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
@@ -2551,16 +2563,6 @@ proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
break
|
||||
setEndInfo()
|
||||
|
||||
proc parseAll*(p: var Parser): PNode =
|
||||
## Parses the rest of the input stream held by the parser into a PNode.
|
||||
result = newNodeP(nkStmtList, p)
|
||||
while true:
|
||||
let nextStmt = p.parseTopLevelStmt()
|
||||
if nextStmt.kind == nkEmpty:
|
||||
break
|
||||
result &= nextStmt
|
||||
setEndInfo()
|
||||
|
||||
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
|
||||
filename: string = ""; line: int = 0;
|
||||
errorHandler: ErrorHandler = nil): PNode =
|
||||
|
||||
@@ -29,6 +29,8 @@ type
|
||||
proc getLazy(c: PPatternContext, sym: PSym): PNode =
|
||||
if c.mappingIsFull:
|
||||
result = c.mapping[sym.position]
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
|
||||
if not c.mappingIsFull:
|
||||
@@ -65,14 +67,21 @@ proc sameTrees*(a, b: PNode): bool =
|
||||
for i in 0..<a.len:
|
||||
if not sameTrees(a[i], b[i]): return
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc inSymChoice(sc, x: PNode): bool =
|
||||
if sc.kind == nkClosedSymChoice:
|
||||
result = false
|
||||
for i in 0..<sc.len:
|
||||
if sc[i].sym == x.sym: return true
|
||||
elif sc.kind == nkOpenSymChoice:
|
||||
# same name suffices for open sym choices!
|
||||
result = sc[0].sym.name.id == x.sym.name.id
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||
# check param constraints first here as this is quite optimized:
|
||||
@@ -88,6 +97,7 @@ proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} =
|
||||
result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner
|
||||
|
||||
proc matchChoice(c: PPatternContext, p, n: PNode): bool =
|
||||
result = false
|
||||
for i in 1..<p.len:
|
||||
if matches(c, p[i], n): return true
|
||||
|
||||
@@ -99,6 +109,8 @@ proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
|
||||
elif n.kind == nkArgList or checkTypes(c, param, n):
|
||||
putLazy(c, param, n)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc gather(c: PPatternContext, param: PSym, n: PNode) =
|
||||
var pp = getLazy(c, param)
|
||||
@@ -132,6 +144,10 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
||||
var arglist = newNodeI(nkArgList, n.info)
|
||||
if matchStarAux(c, p, n, arglist, rpn):
|
||||
result = bindOrCheck(c, p[2].sym, arglist)
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
let n = skipHidden(n)
|
||||
@@ -147,6 +163,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
# try both:
|
||||
if p.kind == nkSym: result = p.sym == n.sym
|
||||
elif matches(c, p, n.sym.astdef): result = true
|
||||
else: result = false
|
||||
elif p.kind == nkPattern:
|
||||
# pattern operators: | *
|
||||
let opr = p[0].ident.s
|
||||
@@ -155,7 +172,9 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
of "*": result = matchNested(c, p, n, rpn=false)
|
||||
of "**": result = matchNested(c, p, n, rpn=true)
|
||||
of "~": result = not matches(c, p[1], n)
|
||||
else: doAssert(false, "invalid pattern")
|
||||
else:
|
||||
result = false
|
||||
doAssert(false, "invalid pattern")
|
||||
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
|
||||
# a.add(b)
|
||||
elif p.kind == nkCurlyExpr:
|
||||
@@ -163,10 +182,14 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
if matches(c, p[0], n):
|
||||
gather(c, p[1][1].sym, n)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
assert isPatternParam(c, p[1])
|
||||
if matches(c, p[0], n):
|
||||
result = bindOrCheck(c, p[1].sym, n)
|
||||
else:
|
||||
result = false
|
||||
elif sameKinds(p, n):
|
||||
case p.kind
|
||||
of nkSym: result = p.sym == n.sym
|
||||
@@ -179,6 +202,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
else:
|
||||
# special rule for p(X) ~ f(...); this also works for stuff like
|
||||
# partial case statements, etc! - Not really ... :-/
|
||||
result = false
|
||||
let v = lastSon(p)
|
||||
if isPatternParam(c, v) and v.sym.typ.kind == tyVarargs:
|
||||
var arglist: PNode
|
||||
@@ -207,6 +231,8 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
for i in 0..<p.len:
|
||||
if not matches(c, p[i], n[i]): return
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
||||
proc matchRange(c: PPatternContext, p, n: PNode, i: int): bool =
|
||||
@@ -219,6 +245,7 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
||||
result = true
|
||||
|
||||
if p.kind == nkStmtList and n.kind == p.kind and p.len < n.len:
|
||||
result = nil
|
||||
let n = flattenStmts(n)
|
||||
# no need to flatten 'p' here as that has already been done
|
||||
for i in 0..n.len - p.len:
|
||||
@@ -231,8 +258,11 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
||||
break
|
||||
elif matches(c, p, n):
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc aliasAnalysisRequested(params: PNode): bool =
|
||||
result = false
|
||||
if params.len >= 2:
|
||||
for i in 1..<params.len:
|
||||
let param = params[i].sym
|
||||
@@ -258,9 +288,11 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
result.add(newSymNode(s, n.info))
|
||||
let params = s.typ.n
|
||||
let requiresAA = aliasAnalysisRequested(params)
|
||||
var args: PNode
|
||||
if requiresAA:
|
||||
args = newNodeI(nkArgList, n.info)
|
||||
var args: PNode =
|
||||
if requiresAA:
|
||||
newNodeI(nkArgList, n.info)
|
||||
else:
|
||||
nil
|
||||
for i in 1..<params.len:
|
||||
let param = params[i].sym
|
||||
let x = getLazy(ctx, param)
|
||||
|
||||
@@ -5,12 +5,10 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
|
||||
|
||||
import pipelineutils
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import jsgen, docgen2
|
||||
|
||||
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
|
||||
import std/[syncio, objectdollar, assertions, tables, strutils]
|
||||
import renderer
|
||||
import ic/replayer
|
||||
|
||||
@@ -27,6 +25,8 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processJSCodeGen(bModule, semNode)
|
||||
else:
|
||||
result = nil
|
||||
of GenDependPass:
|
||||
result = addDotDependency(bModule, semNode)
|
||||
of SemPass:
|
||||
@@ -34,13 +34,17 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
of Docgen2Pass, Docgen2TexPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processNode(bModule, semNode)
|
||||
else:
|
||||
result = nil
|
||||
of Docgen2JsonPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processNodeJson(bModule, semNode)
|
||||
else:
|
||||
result = nil
|
||||
of EvalPass, InterpreterPass:
|
||||
result = interpreterCode(bModule, semNode)
|
||||
of NonePass:
|
||||
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
|
||||
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator,
|
||||
@@ -77,9 +81,9 @@ proc prePass(c: PContext; n: PNode) =
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
try:
|
||||
let feature = parseEnum[Feature](name.strVal)
|
||||
if feature == codeReordering:
|
||||
c.features.incl feature
|
||||
c.module.flags.incl sfReorder
|
||||
# if feature == codeReordering:
|
||||
c.features.incl feature
|
||||
c.module.flags.incl sfReorder
|
||||
except ValueError:
|
||||
discard
|
||||
else:
|
||||
@@ -91,7 +95,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
stream: PLLStream): bool =
|
||||
if graph.stopCompile(): return true
|
||||
var
|
||||
p: Parser = default(Parser)
|
||||
p: Parser
|
||||
s: PLLStream
|
||||
fileIdx = module.fileIdx
|
||||
|
||||
@@ -128,8 +132,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
of SemPass:
|
||||
nil
|
||||
of NonePass:
|
||||
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
|
||||
nil
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
if stream == nil:
|
||||
let filename = toFullPathConsiderDirty(graph.config, fileIdx)
|
||||
@@ -203,7 +206,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
when not defined(leanCompiler):
|
||||
discard closeJson(graph, bModule, finalNode)
|
||||
of NonePass:
|
||||
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
|
||||
# We only write rod files here if no C-like backend is active.
|
||||
@@ -219,18 +222,15 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
var s: PLLStream = nil
|
||||
if sfMainModule in flags:
|
||||
if graph.config.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processPipelineModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
var cachedModules: seq[FileIndex]
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let path = toFullPath(graph.config, fileIdx)
|
||||
let filename = AbsoluteFile path
|
||||
if fileExists(filename): # it could be a stdinfile
|
||||
graph.cachedFiles[path] = $secureHashFile(path)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
|
||||
@@ -277,6 +277,7 @@ proc nameToOS*(name: string): TSystemOS =
|
||||
result = osNone
|
||||
|
||||
proc listOSnames*(): seq[string] =
|
||||
result = @[]
|
||||
for i in succ(osNone)..high(TSystemOS):
|
||||
result.add OS[i].name
|
||||
|
||||
@@ -287,6 +288,7 @@ proc nameToCPU*(name: string): TSystemCPU =
|
||||
result = cpuNone
|
||||
|
||||
proc listCPUnames*(): seq[string] =
|
||||
result = @[]
|
||||
for i in succ(cpuNone)..high(TSystemCPU):
|
||||
result.add CPU[i].name
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ const
|
||||
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe,
|
||||
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
|
||||
wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky}
|
||||
wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky, wMember}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
@@ -94,6 +94,7 @@ const
|
||||
enumFieldPragmas* = {wDeprecated}
|
||||
|
||||
proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
|
||||
result = nil
|
||||
let p = procAst[pragmasPos]
|
||||
if p.kind == nkEmpty: return nil
|
||||
for it in p:
|
||||
@@ -139,9 +140,9 @@ proc pragmaEnsures(c: PContext, n: PNode) =
|
||||
else:
|
||||
openScope(c)
|
||||
let o = getCurrOwner(c)
|
||||
if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil:
|
||||
if o.kind in routineKinds and o.typ != nil and o.typ[0] != nil:
|
||||
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
|
||||
s.typ = o.typ.sons[0]
|
||||
s.typ = o.typ[0]
|
||||
incl(s.flags, sfUsed)
|
||||
addDecl(c, s)
|
||||
n[1] = c.semExpr(c, n[1])
|
||||
@@ -231,6 +232,7 @@ proc expectStrLit(c: PContext, n: PNode): string =
|
||||
result = getStrLitNode(c, n).strVal
|
||||
|
||||
proc expectIntLit(c: PContext, n: PNode): int =
|
||||
result = 0
|
||||
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
||||
localError(c.config, n.info, errIntLiteralExpected)
|
||||
else:
|
||||
@@ -243,10 +245,10 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
|
||||
if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
|
||||
else: result = defaultStr
|
||||
|
||||
proc processVirtual(c: PContext, n: PNode, s: PSym) =
|
||||
proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) =
|
||||
s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1"))
|
||||
s.constraint.strVal = s.constraint.strVal % s.name.s
|
||||
s.flags.incl {sfVirtual, sfInfixCall, sfExportc, sfMangleCpp}
|
||||
s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
|
||||
|
||||
s.typ.callConv = ccNoConvention
|
||||
incl c.config.globalOptions, optMixedMode
|
||||
@@ -276,6 +278,7 @@ proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
|
||||
TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall))
|
||||
|
||||
proc isTurnedOn(c: PContext, n: PNode): bool =
|
||||
result = false
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
let x = c.semConstBoolExpr(c, n[1])
|
||||
n[1] = x
|
||||
@@ -330,7 +333,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
# {.dynlib: myGetProcAddr(...).}
|
||||
result = c.semExpr(c, n[1])
|
||||
if result.kind == nkSym and result.sym.kind == skConst:
|
||||
result = c.semConstExpr(c, result) # fold const
|
||||
result = result.sym.astdef # look it up
|
||||
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
|
||||
localError(c.config, n.info, errStringLiteralExpected)
|
||||
result = newEmptyStrNode(c, n)
|
||||
@@ -468,18 +471,6 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
|
||||
# calling conventions (boring...):
|
||||
localError(c.config, n.info, "option expected")
|
||||
|
||||
proc checkPushedPragma(c: PContext, n: PNode) =
|
||||
let keyDeep = n.kind in nkPragmaCallKinds and n.len > 1
|
||||
var key = if keyDeep: n[0] else: n
|
||||
if key.kind in nkIdentKinds:
|
||||
let ident = considerQuotedIdent(c, key)
|
||||
var userPragma = strTableGet(c.userPragmas, ident)
|
||||
if userPragma == nil:
|
||||
let k = whichKeyword(ident)
|
||||
# TODO: might as well make a list which is not accepted by `push`: emit, cast etc.
|
||||
if k == wEmit:
|
||||
localError(c.config, n.info, "an 'emit' pragma cannot be pushed")
|
||||
|
||||
proc processPush(c: PContext, n: PNode, start: int) =
|
||||
if n[start-1].kind in nkPragmaCallKinds:
|
||||
localError(c.config, n.info, "'push' cannot have arguments")
|
||||
@@ -487,7 +478,6 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||
for i in start..<n.len:
|
||||
if not tryProcessOption(c, n[i], c.config.options):
|
||||
# simply store it somewhere:
|
||||
checkPushedPragma(c, n[i])
|
||||
if x.otherPragmas.isNil:
|
||||
x.otherPragmas = newNodeI(nkPragma, n.info)
|
||||
x.otherPragmas.add n[i]
|
||||
@@ -837,6 +827,7 @@ proc processEffectsOf(c: PContext, n: PNode; owner: PSym) =
|
||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
validPragmas: TSpecialWords,
|
||||
comesFromPush, isStatement: bool): bool =
|
||||
result = false
|
||||
var it = n[i]
|
||||
let keyDeep = it.kind in nkPragmaCallKinds and it.len > 1
|
||||
var key = if keyDeep: it[0] else: it
|
||||
@@ -862,7 +853,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
|
||||
# number of pragmas increase/decrease with user pragma expansion
|
||||
inc c.instCounter
|
||||
defer: dec c.instCounter
|
||||
if c.instCounter > 100:
|
||||
globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
|
||||
|
||||
@@ -872,6 +862,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
|
||||
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
|
||||
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
|
||||
dec c.instCounter
|
||||
else:
|
||||
let k = whichKeyword(ident)
|
||||
if k in validPragmas:
|
||||
@@ -1125,20 +1116,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
|
||||
of wDefine: processDefine(c, it, sym)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile:
|
||||
let m = sym.getModule()
|
||||
incl(m.flags, sfUsed)
|
||||
processCompile(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processLink(c, it)
|
||||
of wPassl:
|
||||
let m = sym.getModule()
|
||||
incl(m.flags, sfUsed)
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addLinkOption(c.config, s)
|
||||
recordPragma(c, it, "passl", s)
|
||||
of wPassc:
|
||||
let m = sym.getModule()
|
||||
incl(m.flags, sfUsed)
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addCompileOption(c.config, s)
|
||||
recordPragma(c, it, "passc", s)
|
||||
@@ -1295,16 +1279,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
pragmaProposition(c, it)
|
||||
of wEnsures:
|
||||
pragmaEnsures(c, it)
|
||||
of wEnforceNoRaises:
|
||||
of wEnforceNoRaises, wQuirky:
|
||||
sym.flags.incl sfNeverRaises
|
||||
of wQuirky:
|
||||
sym.flags.incl sfNeverRaises
|
||||
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
|
||||
sym.options.incl optQuirky
|
||||
of wSystemRaisesDefect:
|
||||
sym.flags.incl sfSystemRaisesDefect
|
||||
of wVirtual:
|
||||
processVirtual(c, it, sym)
|
||||
processVirtual(c, it, sym, sfVirtual)
|
||||
of wMember:
|
||||
processVirtual(c, it, sym, sfMember)
|
||||
|
||||
else: invalidPragma(c, it)
|
||||
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
||||
|
||||
@@ -31,10 +31,10 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
const flags = {ExactGenericParams, ExactTypeDescValues,
|
||||
ExactConstraints, IgnoreCC}
|
||||
var it: TIdentIter = default(TIdentIter)
|
||||
var it: TIdentIter
|
||||
result = initIdentIter(it, scope.symbols, fn.name)
|
||||
while result != nil:
|
||||
if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
|
||||
if result.kind == fn.kind and result.typ != nil: #and sameType(result.typ, fn.typ, flags):
|
||||
case equalParams(result.typ.n, fn.typ.n)
|
||||
of paramsEqual:
|
||||
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
||||
@@ -74,7 +74,7 @@ when false:
|
||||
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searches for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter = default(TIdentIter)
|
||||
var it: TIdentIter
|
||||
for scope in walkScopes(startScope):
|
||||
result = initIdentIter(it, scope.symbols, fn.Name)
|
||||
while result != nil:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{.used.}
|
||||
|
||||
import
|
||||
lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg
|
||||
lexer, options, idents, strutils, ast, msgs, lineinfos
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions, formatfloat]
|
||||
@@ -76,6 +76,8 @@ proc isKeyword*(i: PIdent): bool =
|
||||
if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
|
||||
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isExported(n: PNode): bool =
|
||||
## Checks if an ident is exported.
|
||||
@@ -143,19 +145,13 @@ const
|
||||
MaxLineLen = 80
|
||||
LineCommentColumn = 30
|
||||
|
||||
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
|
||||
g.comStack = @[]
|
||||
g.tokens = @[]
|
||||
g.indent = 0
|
||||
g.lineLen = 0
|
||||
g.pos = 0
|
||||
g.idx = 0
|
||||
g.buf = ""
|
||||
g.flags = renderFlags
|
||||
g.pendingNL = -1
|
||||
g.pendingWhitespace = -1
|
||||
g.inside = {}
|
||||
g.config = config
|
||||
proc initSrcGen(renderFlags: TRenderFlags; config: ConfigRef): TSrcGen =
|
||||
result = TSrcGen(comStack: @[], tokens: @[], indent: 0,
|
||||
lineLen: 0, pos: 0, idx: 0, buf: "",
|
||||
flags: renderFlags, pendingNL: -1,
|
||||
pendingWhitespace: -1, inside: {},
|
||||
config: config
|
||||
)
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
|
||||
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
|
||||
@@ -274,6 +270,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||
optNL(g)
|
||||
|
||||
proc maxLineLength(s: string): int =
|
||||
result = 0
|
||||
if s.len == 0: return 0
|
||||
var i = 0
|
||||
let hi = s.len - 1
|
||||
@@ -371,6 +368,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
||||
tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
|
||||
result = lastSon(result)
|
||||
|
||||
result = ""
|
||||
let typ = n.typ.skip
|
||||
if typ != nil and typ.kind in {tyBool, tyEnum}:
|
||||
if sfPure in typ.sym.flags:
|
||||
@@ -488,6 +486,7 @@ proc referencesUsing(n: PNode): bool =
|
||||
|
||||
proc lsub(g: TSrcGen; n: PNode): int =
|
||||
# computes the length of a tree
|
||||
result = 0
|
||||
if isNil(n): return 0
|
||||
if shouldRenderComment(g, n): return MaxLineLen + 1
|
||||
case n.kind
|
||||
@@ -515,7 +514,6 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
if n.len > 0: result += lsub(g, n[0])
|
||||
of nkOpenSym: result = lsub(g, n[0])
|
||||
of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
|
||||
of nkTupleClassTy: result = len("tuple")
|
||||
of nkDotExpr: result = lsons(g, n) + 1
|
||||
@@ -557,16 +555,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkIfExpr:
|
||||
result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
|
||||
len("if_:_")
|
||||
of nkElifExpr, nkElifBranch:
|
||||
if isEmptyType(n[1].typ):
|
||||
result = lsons(g, n) + len("elif_:_")
|
||||
else:
|
||||
result = lsons(g, n) + len("_elif_:_")
|
||||
of nkElseExpr, nkElse:
|
||||
if isEmptyType(n[0].typ):
|
||||
result = lsub(g, n[0]) + len("else:_")
|
||||
else:
|
||||
result = lsub(g, n[0]) + len("_else:_") # type descriptions
|
||||
of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
|
||||
of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
|
||||
of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
|
||||
of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
|
||||
of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
|
||||
@@ -609,6 +599,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkCommentStmt: result = n.comment.len
|
||||
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
|
||||
of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
|
||||
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
|
||||
of nkElse: result = lsub(g, n[0]) + len("else:_")
|
||||
of nkFinally: result = lsub(g, n[0]) + len("finally:_")
|
||||
of nkGenericParams: result = lcomma(g, n) + 2
|
||||
of nkFormalParams:
|
||||
@@ -632,14 +624,12 @@ type
|
||||
const
|
||||
emptyContext: TContext = (spacing: 0, flags: {})
|
||||
|
||||
proc initContext(c: var TContext) =
|
||||
c.spacing = 0
|
||||
c.flags = {}
|
||||
proc initContext(): TContext =
|
||||
result = (spacing: 0, flags: {})
|
||||
|
||||
proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false)
|
||||
proc gsub(g: var TSrcGen, n: PNode, fromStmtList = false) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
var c: TContext = initContext()
|
||||
gsub(g, n, c, fromStmtList = fromStmtList)
|
||||
|
||||
proc hasCom(n: PNode): bool =
|
||||
@@ -769,9 +759,8 @@ proc gcond(g: var TSrcGen, n: PNode) =
|
||||
put(g, tkParRi, ")")
|
||||
|
||||
proc gif(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
gcond(g, n[0][0])
|
||||
initContext(c)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(g, n) or (lsub(g, n[0][1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
@@ -782,20 +771,18 @@ proc gif(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n[i], c)
|
||||
|
||||
proc gwhile(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
putWithSpace(g, tkWhile, "while")
|
||||
gcond(g, n[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n[1], c)
|
||||
|
||||
proc gpattern(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
put(g, tkCurlyLe, "{")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
@@ -803,20 +790,18 @@ proc gpattern(g: var TSrcGen, n: PNode) =
|
||||
put(g, tkCurlyRi, "}")
|
||||
|
||||
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
gsub(g, n[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n[1], c)
|
||||
|
||||
proc gtry(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
put(g, tkTry, "try")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
@@ -824,9 +809,8 @@ proc gtry(g: var TSrcGen, n: PNode) =
|
||||
gsons(g, n, c, 1)
|
||||
|
||||
proc gfor(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
putWithSpace(g, tkFor, "for")
|
||||
initContext(c)
|
||||
if longMode(g, n) or
|
||||
(lsub(g, n[^1]) + lsub(g, n[^2]) + 6 + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
@@ -839,8 +823,7 @@ proc gfor(g: var TSrcGen, n: PNode) =
|
||||
gstmts(g, n[^1], c)
|
||||
|
||||
proc gcase(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
var c: TContext = initContext()
|
||||
if n.len == 0: return
|
||||
var last = if n[^1].kind == nkElse: -2 else: -1
|
||||
if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
|
||||
@@ -850,17 +833,17 @@ proc gcase(g: var TSrcGen, n: PNode) =
|
||||
optNL(g)
|
||||
gsons(g, n, c, 1, last)
|
||||
if last == - 2:
|
||||
initContext(c)
|
||||
c = initContext()
|
||||
if longMode(g, n[^1]): incl(c.flags, rfLongMode)
|
||||
gsub(g, n[^1], c)
|
||||
|
||||
proc genSymSuffix(result: var string, s: PSym) {.inline.} =
|
||||
if sfGenSym in s.flags and s.name.id != ord(wUnderscore):
|
||||
if sfGenSym in s.flags:
|
||||
result.add '_'
|
||||
result.addInt s.id
|
||||
|
||||
proc gproc(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
if n[namePos].kind == nkSym:
|
||||
let s = n[namePos].sym
|
||||
var ret = renderDefinitionName(s)
|
||||
@@ -881,13 +864,13 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
if renderNoPragmas notin g.flags:
|
||||
gsub(g, n[pragmasPos])
|
||||
if renderNoBody notin g.flags:
|
||||
if n.len > bodyPos and n[bodyPos].kind != nkEmpty:
|
||||
if n[bodyPos].kind != nkEmpty:
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
indentNL(g)
|
||||
gcoms(g)
|
||||
dedent(g)
|
||||
initContext(c)
|
||||
c = initContext()
|
||||
gstmts(g, n[bodyPos], c)
|
||||
putNL(g)
|
||||
else:
|
||||
@@ -896,8 +879,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
dedent(g)
|
||||
|
||||
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
var c: TContext = initContext()
|
||||
putWithSpace(g, tkConcept, "concept")
|
||||
gsons(g, n[0], c) # arglist
|
||||
gsub(g, n[1]) # pragmas
|
||||
@@ -916,8 +898,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
|
||||
if n.len == 0:
|
||||
return
|
||||
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
var c: TContext = initContext()
|
||||
|
||||
if n[0].kind != nkEmpty:
|
||||
putWithSpace(g, tkBlock, "block")
|
||||
@@ -937,10 +918,9 @@ proc gblock(g: var TSrcGen, n: PNode) =
|
||||
gstmts(g, n[1], c)
|
||||
|
||||
proc gstaticStmt(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var c: TContext = initContext()
|
||||
putWithSpace(g, tkStatic, "static")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
@@ -978,9 +958,7 @@ proc gident(g: var TSrcGen, n: PNode) =
|
||||
s.addInt localId
|
||||
if sfCursor in n.sym.flags:
|
||||
s.add "_cursor"
|
||||
elif n.kind == nkSym and (renderIds in g.flags or
|
||||
(sfGenSym in n.sym.flags and n.sym.name.id != ord(wUnderscore)) or
|
||||
n.sym.kind == skTemp):
|
||||
elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
|
||||
s.add '_'
|
||||
s.addInt n.sym.id
|
||||
when defined(debugMagics):
|
||||
@@ -1014,6 +992,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
|
||||
case n.kind
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
if n.len > 0: result = bracketKind(g, n[0])
|
||||
else: result = bkNone
|
||||
of nkSym:
|
||||
result = case n.sym.name.s
|
||||
of "[]": bkBracket
|
||||
@@ -1022,11 +1001,13 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
|
||||
of "{}=": bkCurlyAsgn
|
||||
else: bkNone
|
||||
else: result = bkNone
|
||||
else:
|
||||
result = bkNone
|
||||
|
||||
proc skipHiddenNodes(n: PNode): PNode =
|
||||
result = n
|
||||
while result != nil:
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkOpenSym} and result.len > 1:
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
|
||||
result = result[1]
|
||||
elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
|
||||
result.len > 0:
|
||||
@@ -1094,11 +1075,13 @@ proc isCustomLit(n: PNode): bool =
|
||||
if n.len == 2 and n[0].kind == nkRStrLit:
|
||||
let ident = n[1].getPIdent
|
||||
result = ident != nil and ident.s.startsWith('\'')
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
if isNil(n): return
|
||||
var
|
||||
a: TContext
|
||||
a: TContext = default(TContext)
|
||||
if shouldRenderComment(g, n): pushCom(g, n)
|
||||
case n.kind # atoms:
|
||||
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
|
||||
@@ -1286,7 +1269,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
|
||||
else:
|
||||
gsub(g, n, 0)
|
||||
of nkOpenSym: gsub(g, n, 0)
|
||||
of nkPar, nkClosure:
|
||||
put(g, tkParLe, "(")
|
||||
gcomma(g, n, c)
|
||||
@@ -1316,11 +1298,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
put(g, tkCustomLit, n[0].strVal)
|
||||
gsub(g, n, 1)
|
||||
else:
|
||||
for i in 0..<n.len-1:
|
||||
gsub(g, n, i)
|
||||
gsub(g, n, 0)
|
||||
put(g, tkDot, ".")
|
||||
if n.len > 1:
|
||||
accentedName(g, n[^1])
|
||||
assert n.len == 2, $n.len
|
||||
accentedName(g, n[1])
|
||||
of nkBind:
|
||||
putWithSpace(g, tkBind, "bind")
|
||||
gsub(g, n, 0)
|
||||
@@ -1448,6 +1429,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
if n.kind in {nkIdent, nkSym}:
|
||||
let tmp = n.getPIdent.s
|
||||
result = tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'}
|
||||
else:
|
||||
result = false
|
||||
var useSpace = false
|
||||
if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]:
|
||||
if not n[1].isAlpha: # handle `=destroy`, `'big'
|
||||
@@ -1465,30 +1448,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if n.len > 0: gsub(g, n[0], 1)
|
||||
gsons(g, n, emptyContext, 1)
|
||||
of nkElifExpr, nkElifBranch:
|
||||
if isEmptyType(n[1].typ):
|
||||
optNL(g)
|
||||
putWithSpace(g, tkElif, "elif")
|
||||
gsub(g, n, 0)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gcoms(g)
|
||||
gstmts(g, n[1], c)
|
||||
else:
|
||||
putWithSpace(g, tkElif, " elif")
|
||||
gcond(g, n[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, 1)
|
||||
of nkElseExpr, nkElse:
|
||||
if isEmptyType(n[0].typ):
|
||||
optNL(g)
|
||||
put(g, tkElse, "else")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gcoms(g)
|
||||
gstmts(g, n[0], c)
|
||||
else:
|
||||
put(g, tkElse, " else")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, 0)
|
||||
of nkElifExpr:
|
||||
putWithSpace(g, tkElif, " elif")
|
||||
gcond(g, n[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, 1)
|
||||
of nkElseExpr:
|
||||
put(g, tkElse, " else")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, 0)
|
||||
of nkTypeOfExpr:
|
||||
put(g, tkType, "typeof")
|
||||
put(g, tkParLe, "(")
|
||||
@@ -1550,16 +1518,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
gsub(g, n[0])
|
||||
gsub(g, n[1])
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
gsub(g, n[2])
|
||||
dedent(g)
|
||||
else:
|
||||
put(g, tkObject, "object")
|
||||
of nkRecList:
|
||||
indentNL(g)
|
||||
for i in 0..<n.len:
|
||||
optNL(g)
|
||||
gsub(g, n[i], c)
|
||||
gcoms(g)
|
||||
dedent(g)
|
||||
putNL(g)
|
||||
of nkOfInherit:
|
||||
putWithSpace(g, tkOf, "of")
|
||||
gsub(g, n, 0)
|
||||
@@ -1644,7 +1613,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
of nkTypeSection:
|
||||
gsection(g, n, emptyContext, tkType, "type")
|
||||
of nkConstSection:
|
||||
initContext(a)
|
||||
a = initContext()
|
||||
incl(a.flags, rfInConstExpr)
|
||||
gsection(g, n, a, tkConst, "const")
|
||||
of nkVarSection, nkLetSection, nkUsingStmt:
|
||||
@@ -1750,6 +1719,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
of nkMixinStmt:
|
||||
putWithSpace(g, tkMixin, "mixin")
|
||||
gcomma(g, n, c)
|
||||
of nkElifBranch:
|
||||
optNL(g)
|
||||
putWithSpace(g, tkElif, "elif")
|
||||
gsub(g, n, 0)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gcoms(g)
|
||||
gstmts(g, n[1], c)
|
||||
of nkElse:
|
||||
optNL(g)
|
||||
put(g, tkElse, "else")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gcoms(g)
|
||||
gstmts(g, n[0], c)
|
||||
of nkFinally, nkDefer:
|
||||
optNL(g)
|
||||
if n.kind == nkFinally:
|
||||
@@ -1799,13 +1781,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
gsub(g, n, 0)
|
||||
put(g, tkParRi, ")")
|
||||
of nkGotoState:
|
||||
var c: TContext
|
||||
initContext c
|
||||
var c: TContext = initContext()
|
||||
putWithSpace g, tkSymbol, "goto"
|
||||
gsons(g, n, c)
|
||||
of nkState:
|
||||
var c: TContext
|
||||
initContext c
|
||||
var c: TContext = initContext()
|
||||
putWithSpace g, tkSymbol, "state"
|
||||
gsub(g, n[0], c)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
@@ -1829,8 +1809,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
|
||||
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||
if n == nil: return "<nil tree>"
|
||||
var g: TSrcGen
|
||||
initSrcGen(g, renderFlags, newPartialConfigRef())
|
||||
var g: TSrcGen = initSrcGen(renderFlags, newPartialConfigRef())
|
||||
# do not indent the initial statement list so that
|
||||
# writeFile("file.nim", repr n)
|
||||
# produces working Nim code:
|
||||
@@ -1847,9 +1826,8 @@ proc renderModule*(n: PNode, outfile: string,
|
||||
fid = FileIndex(-1);
|
||||
conf: ConfigRef = nil) =
|
||||
var
|
||||
f: File
|
||||
g: TSrcGen
|
||||
initSrcGen(g, renderFlags, conf)
|
||||
f: File = default(File)
|
||||
g: TSrcGen = initSrcGen(renderFlags, conf)
|
||||
g.fid = fid
|
||||
for i in 0..<n.len:
|
||||
gsub(g, n[i])
|
||||
@@ -1865,9 +1843,9 @@ proc renderModule*(n: PNode, outfile: string,
|
||||
else:
|
||||
rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
|
||||
|
||||
proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
|
||||
initSrcGen(r, renderFlags, newPartialConfigRef())
|
||||
gsub(r, n)
|
||||
proc initTokRender*(n: PNode, renderFlags: TRenderFlags = {}): TSrcGen =
|
||||
result = initSrcGen(renderFlags, newPartialConfigRef())
|
||||
gsub(result, n)
|
||||
|
||||
proc getNextTok*(r: var TSrcGen, kind: var TokType, literal: var string) =
|
||||
if r.idx < r.tokens.len:
|
||||
|
||||
@@ -40,6 +40,7 @@ type LineData = object
|
||||
|
||||
proc tripleStrLitStartsAtNextLine(conf: ConfigRef, n: PNode): bool =
|
||||
# enabling TLineInfo.offsetA,offsetB would probably make this easier
|
||||
result = false
|
||||
const tripleQuote = "\"\"\""
|
||||
let src = sourceLine(conf, n.info)
|
||||
let col = n.info.col
|
||||
|
||||
@@ -25,17 +25,11 @@ when defined(nimDebugReorder):
|
||||
var idNames = newTable[int, string]()
|
||||
|
||||
proc newDepN(id: int, pnode: PNode): DepN =
|
||||
new(result)
|
||||
result.id = id
|
||||
result.pnode = pnode
|
||||
result.idx = -1
|
||||
result.lowLink = -1
|
||||
result.onStack = false
|
||||
result.kids = @[]
|
||||
result.hAQ = -1
|
||||
result.hIS = -1
|
||||
result.hB = -1
|
||||
result.hCmd = -1
|
||||
result = DepN(id: id, pnode: pnode, idx: -1,
|
||||
lowLink: -1, onStack: false,
|
||||
kids: @[], hAQ: -1, hIS: -1,
|
||||
hB: -1, hCmd: -1
|
||||
)
|
||||
when defined(nimDebugReorder):
|
||||
result.expls = @[]
|
||||
|
||||
@@ -114,7 +108,8 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
|
||||
# XXX: for callables, this technically adds the return type dep before args
|
||||
for i in 0..<n.safeLen: deps(n[i])
|
||||
|
||||
proc hasIncludes(n:PNode): bool =
|
||||
proc hasIncludes(n: PNode): bool =
|
||||
result = false
|
||||
for a in n:
|
||||
if a.kind == nkIncludeStmt:
|
||||
return true
|
||||
@@ -234,8 +229,9 @@ proc hasImportStmt(n: PNode): bool =
|
||||
# i it contains one
|
||||
case n.kind
|
||||
of nkImportStmt, nkFromStmt, nkImportExceptStmt:
|
||||
return true
|
||||
result = true
|
||||
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
|
||||
result = false
|
||||
for a in n:
|
||||
if a.hasImportStmt:
|
||||
return true
|
||||
@@ -268,6 +264,7 @@ proc hasCommand(n: DepN): bool =
|
||||
result = bool(n.hCmd)
|
||||
|
||||
proc hasAccQuoted(n: PNode): bool =
|
||||
result = false
|
||||
if n.kind == nkAccQuoted:
|
||||
return true
|
||||
for a in n:
|
||||
@@ -283,6 +280,7 @@ proc hasAccQuotedDef(n: PNode): bool =
|
||||
of extendedProcDefs:
|
||||
result = n[0].hasAccQuoted
|
||||
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
|
||||
result = false
|
||||
for a in n:
|
||||
if hasAccQuotedDef(a):
|
||||
return true
|
||||
@@ -303,6 +301,7 @@ proc hasBody(n: PNode): bool =
|
||||
of extendedProcDefs:
|
||||
result = n[^1].kind == nkStmtList
|
||||
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
|
||||
result = false
|
||||
for a in n:
|
||||
if a.hasBody:
|
||||
return true
|
||||
@@ -315,18 +314,11 @@ proc hasBody(n: DepN): bool =
|
||||
result = bool(n.hB)
|
||||
|
||||
proc intersects(s1, s2: IntSet): bool =
|
||||
result = false
|
||||
for a in s1:
|
||||
if s2.contains(a):
|
||||
return true
|
||||
|
||||
proc hasPushOrPopPragma(n: DepN): bool =
|
||||
# Checks if the tree node has some pragmas that do not
|
||||
# play well with reordering, like the push/pop pragma
|
||||
# no crossing for push/pop barrier
|
||||
let a = n.pnode
|
||||
result = a.kind == nkPragma and a[0].kind == nkIdent and
|
||||
(a[0].ident.s == "push" or a[0].ident.s == "pop")
|
||||
|
||||
proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
|
||||
# Build a dependency graph
|
||||
result = newSeqOfCap[DepN](deps.len)
|
||||
@@ -368,13 +360,6 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
|
||||
for dep in deps[i][0]:
|
||||
if dep in declares:
|
||||
ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it"
|
||||
elif hasPushOrPopPragma(nj):
|
||||
# Every node that comes after a push/pop pragma must
|
||||
# depend on it; vice versa
|
||||
if j < i:
|
||||
ni.kids.add nj
|
||||
else:
|
||||
nj.kids.add ni
|
||||
else:
|
||||
for d in declares:
|
||||
if uses.contains(d):
|
||||
@@ -409,13 +394,24 @@ proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
|
||||
## Tarjan's algorithm. Performs a topological sort
|
||||
## and detects strongly connected components.
|
||||
result = @[]
|
||||
var s: seq[DepN] = @[]
|
||||
var s: seq[DepN]
|
||||
var idx = 0
|
||||
for v in g.mitems:
|
||||
if v.idx < 0:
|
||||
strongConnect(v, idx, s, result)
|
||||
|
||||
proc hasForbiddenPragma(n: PNode): bool =
|
||||
# Checks if the tree node has some pragmas that do not
|
||||
# play well with reordering, like the push/pop pragma
|
||||
result = false
|
||||
for a in n:
|
||||
if a.kind == nkPragma and a[0].kind == nkIdent and
|
||||
a[0].ident.s == "push":
|
||||
return true
|
||||
|
||||
proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
|
||||
if n.hasForbiddenPragma:
|
||||
return n
|
||||
var includedFiles = initIntSet()
|
||||
let mpath = toFullPath(graph.config, module.fileIdx)
|
||||
let n = expandIncludes(graph, module, n, mpath,
|
||||
|
||||
@@ -61,6 +61,7 @@ proc toStrMaxPrecision*(f: BiggestFloat | float32): string =
|
||||
of fcNegInf:
|
||||
result = "-INF"
|
||||
else:
|
||||
result = ""
|
||||
result.addFloatRoundtrip(f)
|
||||
result.add literalPostfix
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ proc writeRope*(f: File, r: Rope) =
|
||||
write(f, r)
|
||||
|
||||
proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, filename.string, fmWrite):
|
||||
writeRope(f, head)
|
||||
close(f)
|
||||
@@ -76,7 +76,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
else:
|
||||
result.add(args[j-1])
|
||||
of '{':
|
||||
@@ -88,10 +88,10 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
num = j
|
||||
if frmt[i] == '}': inc(i)
|
||||
else:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
|
||||
if j > high(args) + 1:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
else:
|
||||
result.add(args[j-1])
|
||||
of 'n':
|
||||
@@ -101,7 +101,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
result.add("\n")
|
||||
inc(i)
|
||||
else:
|
||||
doAssert false, "invalid format string: " & frmt
|
||||
raiseAssert "invalid format string: " & frmt
|
||||
else:
|
||||
result.add(frmt[i])
|
||||
inc(i)
|
||||
@@ -119,7 +119,7 @@ const
|
||||
proc equalsFile*(s: Rope, f: File): bool =
|
||||
## returns true if the contents of the file `f` equal `r`.
|
||||
var
|
||||
buf: array[bufSize, char]
|
||||
buf: array[bufSize, char] = default(array[bufSize, char])
|
||||
bpos = buf.len
|
||||
blen = buf.len
|
||||
btotal = 0
|
||||
@@ -151,7 +151,7 @@ proc equalsFile*(s: Rope, f: File): bool =
|
||||
proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
|
||||
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
||||
## exist, false is returned.
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
result = open(f, filename.string)
|
||||
if result:
|
||||
result = equalsFile(r, f)
|
||||
|
||||
@@ -240,7 +240,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
of gcAtomicArc:
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
else:
|
||||
doAssert false, "unreachable"
|
||||
raiseAssert "unreachable"
|
||||
|
||||
# ensure we load 'system.nim' again for the real non-config stuff!
|
||||
resetSystemArtifacts(graph)
|
||||
|
||||
127
compiler/sem.nim
127
compiler/sem.nim
@@ -26,10 +26,7 @@ when not defined(leanCompiler):
|
||||
import spawn
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[
|
||||
formatfloat,
|
||||
assertions,
|
||||
]
|
||||
import std/formatfloat
|
||||
|
||||
# implementation
|
||||
|
||||
@@ -88,11 +85,6 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
changeType(c, x, formal, check=true)
|
||||
result = arg
|
||||
result = skipHiddenSubConv(result, c.graph, c.idgen)
|
||||
# mark inserted converter as used:
|
||||
var a = result
|
||||
if a.kind == nkHiddenDeref: a = a[0]
|
||||
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
|
||||
markUsed(c, a.info, a[0].sym)
|
||||
|
||||
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
@@ -104,6 +96,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
result.typ = formal
|
||||
elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum:
|
||||
# Pick the right 'sym' from the sym choice by looking at 'formal' type:
|
||||
result = nil
|
||||
for ch in arg:
|
||||
if sameType(ch.typ, formal):
|
||||
return getConstExpr(c.module, ch, c.idgen, c.graph)
|
||||
@@ -157,7 +150,7 @@ proc commonType*(c: PContext; x, y: PType): PType =
|
||||
let idx = ord(b.kind == tyArray)
|
||||
if a[idx].kind == tyEmpty: return y
|
||||
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
|
||||
var nt: PType
|
||||
var nt: PType = nil
|
||||
for i in 0..<a.len:
|
||||
let aEmpty = isEmptyContainer(a[i])
|
||||
let bEmpty = isEmptyContainer(b[i])
|
||||
@@ -213,19 +206,13 @@ proc commonType*(c: PContext; x, y: PType): PType =
|
||||
result = newType(k, nextTypeId(c.idgen), r.owner)
|
||||
result.addSonSkipIntLit(r, c.idgen)
|
||||
|
||||
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
|
||||
proc shouldCheckCaseCovered(caseTyp: PType): bool =
|
||||
result = false
|
||||
case caseTyp.kind
|
||||
of shouldChckCovered:
|
||||
result = true
|
||||
of tyRange:
|
||||
if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
|
||||
result = true
|
||||
else:
|
||||
discard
|
||||
|
||||
proc endsInNoReturn(n: PNode): bool
|
||||
proc endsInNoReturn(n: PNode): bool =
|
||||
# check if expr ends in raise exception or call of noreturn proc
|
||||
var it = n
|
||||
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||
it = it.lastSon
|
||||
result = it.kind in nkLastBlockStmts or
|
||||
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
|
||||
proc commonType*(c: PContext; x: PType, y: PNode): PType =
|
||||
# ignore exception raising branches in case/if expressions
|
||||
@@ -257,8 +244,6 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
result.owner = getCurrOwner(c)
|
||||
else:
|
||||
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
|
||||
if find(result.name.s, '`') >= 0:
|
||||
result.flags.incl sfWasGenSym
|
||||
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
|
||||
# incl(result.flags, sfGlobal)
|
||||
when defined(nimsuggest):
|
||||
@@ -268,7 +253,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym
|
||||
# identifier with visibility
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags, fromTopLevel = false): PSym
|
||||
allowed: TSymFlags): PSym
|
||||
|
||||
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
|
||||
flags: TTypeAllowedFlags = {}) =
|
||||
@@ -321,6 +306,7 @@ when false:
|
||||
result = isOpImpl(c, n)
|
||||
|
||||
proc hasCycle(n: PNode): bool =
|
||||
result = false
|
||||
incl n.flags, nfNone
|
||||
for i in 0..<n.safeLen:
|
||||
if nfNone in n[i].flags or hasCycle(n[i]):
|
||||
@@ -485,15 +471,9 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
# e.g. template foo(T: typedesc): seq[T]
|
||||
# We will instantiate the return type here, because
|
||||
# we now know the supplied arguments
|
||||
var paramTypes = newIdTable()
|
||||
var paramTypes = initIdTable()
|
||||
for param, value in genericParamsInMacroCall(s, call):
|
||||
var givenType = value.typ
|
||||
# the sym nodes used for the supplied generic arguments for
|
||||
# templates and macros leave type nil so regular sem can handle it
|
||||
# in this case, get the type directly from the sym
|
||||
if givenType == nil and value.kind == nkSym and value.sym.typ != nil:
|
||||
givenType = value.sym.typ
|
||||
idTablePut(paramTypes, param.typ, givenType)
|
||||
idTablePut(paramTypes, param.typ, value.typ)
|
||||
|
||||
retType = generateTypeInstance(c, paramTypes,
|
||||
macroResult.info, retType)
|
||||
@@ -501,7 +481,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
if retType.kind == tyVoid:
|
||||
result = semStmt(c, result, flags)
|
||||
else:
|
||||
result = semExpr(c, result, flags)
|
||||
result = semExpr(c, result, flags, expectedType)
|
||||
result = fitNode(c, retType, result, result.info)
|
||||
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
|
||||
dec(c.config.evalTemplateCounter)
|
||||
@@ -570,6 +550,7 @@ proc setGenericParamsMisc(c: PContext; n: PNode) =
|
||||
n[miscPos][1] = orig
|
||||
|
||||
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
||||
result = false
|
||||
for i in 0 ..< branch.len-1:
|
||||
if branch[i].kind == nkRange:
|
||||
if overlap(branch[i], matched): return true
|
||||
@@ -577,6 +558,7 @@ proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
||||
return true
|
||||
|
||||
proc pickCaseBranchIndex(caseExpr, matched: PNode): int =
|
||||
result = 0
|
||||
let endsWithElse = caseExpr[^1].kind == nkElse
|
||||
for i in 1..<caseExpr.len - endsWithElse.int:
|
||||
if caseExpr[i].caseBranchMatchesExpr(matched):
|
||||
@@ -591,6 +573,7 @@ proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode
|
||||
const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink}
|
||||
|
||||
proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, checkDefault: bool): seq[PNode] =
|
||||
result = @[]
|
||||
case recNode.kind
|
||||
of nkRecList:
|
||||
for field in recNode:
|
||||
@@ -620,9 +603,10 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch
|
||||
asgnExpr.typ = recNode.typ
|
||||
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||
else:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
|
||||
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] =
|
||||
result = @[]
|
||||
case recNode.kind
|
||||
of nkRecList:
|
||||
for field in recNode:
|
||||
@@ -655,7 +639,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
|
||||
asgnExpr.flags.incl nfSkipFieldChecking
|
||||
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||
else:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
|
||||
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode =
|
||||
let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
|
||||
@@ -666,6 +650,8 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
asgnExpr.typ = aTyp
|
||||
asgnExpr.sons.add child
|
||||
result = semExpr(c, asgnExpr)
|
||||
else:
|
||||
result = nil
|
||||
elif aTypSkip.kind == tyArray:
|
||||
let child = defaultNodeField(c, a, aTypSkip[1], checkDefault)
|
||||
|
||||
@@ -677,6 +663,8 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
node
|
||||
))
|
||||
result.typ = aTyp
|
||||
else:
|
||||
result = nil
|
||||
elif aTypSkip.kind == tyTuple:
|
||||
var hasDefault = false
|
||||
if aTypSkip.n != nil:
|
||||
@@ -686,6 +674,12 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
result.typ = aTyp
|
||||
result.sons.add children
|
||||
result = semExpr(c, result)
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode =
|
||||
result = defaultNodeField(c, a, a.typ, checkDefault)
|
||||
@@ -745,17 +739,19 @@ proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
|
||||
break
|
||||
case n.kind
|
||||
of nkImportStmt:
|
||||
result = false
|
||||
for x in n:
|
||||
if x.kind == nkIdent:
|
||||
let f = checkModuleName(g.config, x, false)
|
||||
if f == g.systemModule.info.fileIndex:
|
||||
return true
|
||||
of nkImportExceptStmt, nkFromStmt:
|
||||
result = false
|
||||
if n[0].kind == nkIdent:
|
||||
let f = checkModuleName(g.config, n[0], false)
|
||||
if f == g.systemModule.info.fileIndex:
|
||||
return true
|
||||
else: discard
|
||||
else: result = false
|
||||
|
||||
proc isEmptyTree(n: PNode): bool =
|
||||
case n.kind
|
||||
@@ -766,6 +762,58 @@ proc isEmptyTree(n: PNode): bool =
|
||||
of nkEmpty, nkCommentStmt: result = true
|
||||
else: result = false
|
||||
|
||||
proc decl(c: PContext, n: PNode, kind: TSymKind): PNode =
|
||||
if n[0].kind == nkIdent:
|
||||
var s = newSym(kind, n[0].ident, c.idgen, getCurrOwner(c), n.info)
|
||||
s.flags.incl sfToplevelDecl
|
||||
# pragmaCallable(c, s, n, allRoutinePragmas)
|
||||
|
||||
result = n
|
||||
if n[^1].kind != nkEmpty:
|
||||
if s.kind in OverloadableSyms:
|
||||
addInterfaceOverloadableSymAt(c, c.currentScope, s)
|
||||
else:
|
||||
addInterfaceDeclAt(c, c.currentScope, s)
|
||||
|
||||
result[0] = newSymNode(s)
|
||||
else:
|
||||
result = n
|
||||
|
||||
import reorder
|
||||
|
||||
proc semSignature(c: PContext, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkProcDef:
|
||||
result = decl(c, n, skProc)
|
||||
of nkMethodDef:
|
||||
result = decl(c, n, skMethod)
|
||||
of nkConverterDef:
|
||||
result = decl(c, n, skConverter)
|
||||
of nkMacroDef:
|
||||
result = decl(c, n, skMacro)
|
||||
of nkTemplateDef:
|
||||
result = decl(c, n, skTemplate)
|
||||
of nkIteratorDef:
|
||||
result = decl(c, n, skIterator)
|
||||
of nkIncludeStmt:
|
||||
result = n
|
||||
for i in 0..<n.len:
|
||||
var f = checkModuleName(c.config, n[i])
|
||||
if f != InvalidFileIdx:
|
||||
if containsOrIncl(c.includedFiles, f.int):
|
||||
localError(c.config, n[i].info, "recursive dependency: '$1'" %
|
||||
toMsgFilename(c.config, f))
|
||||
else:
|
||||
let nn = includeModule(c.graph, c.module, f)
|
||||
result = semSignature(c, nn)
|
||||
excl(c.includedFiles, f.int)
|
||||
of nkStmtList:
|
||||
result = copyNode(n)
|
||||
for i in 0..<n.len:
|
||||
result.add semSignature(c, n[i])
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
if c.topStmts == 0 and not isImportSystemStmt(c.graph, n):
|
||||
if sfSystemModule notin c.module.flags and not isEmptyTree(n):
|
||||
@@ -779,6 +827,9 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = semAllTypeSections(c, n)
|
||||
else:
|
||||
result = n
|
||||
# if noforwardDecl in c.features:
|
||||
# debug result
|
||||
result = semSignature(c, result)
|
||||
result = semStmt(c, result, {})
|
||||
when false:
|
||||
# Code generators are lazy now and can deal with undeclared procs, so these
|
||||
|
||||
@@ -68,7 +68,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
# `matches` may find new symbols, so keep track of count
|
||||
var symCount = c.currentScope.symbols.counter
|
||||
|
||||
var o: TOverloadIter = default(TOverloadIter)
|
||||
var o: TOverloadIter
|
||||
# https://github.com/nim-lang/Nim/issues/21272
|
||||
# prevent mutation during iteration by storing them in a seq
|
||||
# luckily `initCandidateSymbols` does just that
|
||||
@@ -82,7 +82,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
|
||||
# starts at 1 because 0 is already done with setup, only needs checking
|
||||
var nextSymIndex = 1
|
||||
var z: TCandidate # current candidate
|
||||
var z: TCandidate = default(TCandidate) # current candidate
|
||||
while true:
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
|
||||
@@ -215,7 +215,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
|
||||
var maybeWrongSpace = false
|
||||
|
||||
var candidatesAll: seq[string]
|
||||
var candidatesAll: seq[string] = @[]
|
||||
var candidates = ""
|
||||
var skipped = 0
|
||||
for err in errors:
|
||||
@@ -236,89 +236,44 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
candidates.add("\n")
|
||||
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
|
||||
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
|
||||
if n.len > 1:
|
||||
if verboseTypeMismatch notin c.config.legacyFeatures:
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam:
|
||||
if nArg == nil:
|
||||
candidates.add(" unknown named parameter")
|
||||
else:
|
||||
candidates.add(" unknown named parameter: " & $nArg[0])
|
||||
candidates.add "\n"
|
||||
of kAlreadyGiven:
|
||||
candidates.add(" named param already provided: " & $nArg[0])
|
||||
candidates.add "\n"
|
||||
of kPositionalAlreadyGiven:
|
||||
candidates.add(" positional param was already given as named param")
|
||||
candidates.add "\n"
|
||||
of kExtraArg:
|
||||
candidates.add(" extra argument given")
|
||||
candidates.add "\n"
|
||||
of kMissingParam:
|
||||
candidates.add(" missing parameter: " & nameParam)
|
||||
candidates.add "\n"
|
||||
of kVarNeeded:
|
||||
doAssert nArg != nil
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
candidates.add " expression '"
|
||||
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
|
||||
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
||||
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam:
|
||||
if nArg == nil:
|
||||
candidates.add("\n unknown named parameter")
|
||||
else:
|
||||
candidates.add("\n unknown named parameter: " & $nArg[0])
|
||||
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
|
||||
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
|
||||
of kExtraArg: candidates.add("\n extra argument given")
|
||||
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
|
||||
of kTypeMismatch, kVarNeeded:
|
||||
doAssert nArg != nil
|
||||
let wanted = err.firstMismatch.formal.typ
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
candidates.add("\n required type for " & nameParam & ": ")
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
|
||||
candidates.add "\n but expression '"
|
||||
if err.firstMismatch.kind == kVarNeeded:
|
||||
candidates.add renderNotLValue(nArg)
|
||||
candidates.add "' is immutable, not 'var'"
|
||||
candidates.add "\n"
|
||||
of kTypeMismatch:
|
||||
doAssert nArg != nil
|
||||
let wanted = err.firstMismatch.formal.typ
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
doAssert wanted != nil
|
||||
else:
|
||||
candidates.add renderTree(nArg)
|
||||
candidates.add "' is of type: "
|
||||
let got = nArg.typ
|
||||
if got != nil and got.kind == tyProc and wanted.kind == tyProc:
|
||||
# These are proc mismatches so,
|
||||
# add the extra explict detail of the mismatch
|
||||
candidates.add " expression '"
|
||||
candidates.add renderTree(nArg)
|
||||
candidates.add "' is of type: "
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, got)
|
||||
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, got)
|
||||
doAssert wanted != nil
|
||||
if got != nil:
|
||||
if got.kind == tyProc and wanted.kind == tyProc:
|
||||
# These are proc mismatches so,
|
||||
# add the extra explict detail of the mismatch
|
||||
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
|
||||
effectProblem(wanted, got, candidates, c)
|
||||
candidates.add "\n"
|
||||
of kUnknown: discard "do not break 'nim check'"
|
||||
else:
|
||||
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
||||
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam:
|
||||
if nArg == nil:
|
||||
candidates.add("\n unknown named parameter")
|
||||
else:
|
||||
candidates.add("\n unknown named parameter: " & $nArg[0])
|
||||
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
|
||||
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
|
||||
of kExtraArg: candidates.add("\n extra argument given")
|
||||
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
|
||||
of kTypeMismatch, kVarNeeded:
|
||||
doAssert nArg != nil
|
||||
let wanted = err.firstMismatch.formal.typ
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
candidates.add("\n required type for " & nameParam & ": ")
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
|
||||
candidates.add "\n but expression '"
|
||||
if err.firstMismatch.kind == kVarNeeded:
|
||||
candidates.add renderNotLValue(nArg)
|
||||
candidates.add "' is immutable, not 'var'"
|
||||
else:
|
||||
candidates.add renderTree(nArg)
|
||||
candidates.add "' is of type: "
|
||||
let got = nArg.typ
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, got)
|
||||
doAssert wanted != nil
|
||||
if got != nil:
|
||||
if got.kind == tyProc and wanted.kind == tyProc:
|
||||
# These are proc mismatches so,
|
||||
# add the extra explict detail of the mismatch
|
||||
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
|
||||
effectProblem(wanted, got, candidates, c)
|
||||
|
||||
of kUnknown: discard "do not break 'nim check'"
|
||||
candidates.add "\n"
|
||||
of kUnknown: discard "do not break 'nim check'"
|
||||
candidates.add "\n"
|
||||
if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
|
||||
n.kind == nkCommand:
|
||||
maybeWrongSpace = true
|
||||
@@ -399,7 +354,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
|
||||
proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
var errors: CandidateErrors = @[]
|
||||
var o: TOverloadIter = default(TOverloadIter)
|
||||
var o: TOverloadIter
|
||||
let headSymbol = n[0]
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
@@ -415,13 +370,14 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
notFoundError(c, n, errors)
|
||||
|
||||
proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
|
||||
result = ""
|
||||
if c.compilesContextId > 0:
|
||||
# we avoid running more diagnostic when inside a `compiles(expr)`, to
|
||||
# errors while running diagnostic (see test D20180828T234921), and
|
||||
# also avoid slowdowns in evaluating `compiles(expr)`.
|
||||
discard
|
||||
else:
|
||||
var o: TOverloadIter = default(TOverloadIter)
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, f)
|
||||
while sym != nil:
|
||||
result &= "\n found $1" % [getSymRepr(c.config, sym)]
|
||||
@@ -450,8 +406,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds, flags: TExprFlags,
|
||||
errors: var CandidateErrors,
|
||||
errorsEnabled: bool): TCandidate =
|
||||
result = default(TCandidate)
|
||||
var initialBinding: PNode
|
||||
var alt: TCandidate
|
||||
var alt: TCandidate = default(TCandidate)
|
||||
var f = n[0]
|
||||
if f.kind == nkBracketExpr:
|
||||
# fill in the bindings:
|
||||
@@ -465,7 +422,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter, result, alt, errors, efExplain in flags,
|
||||
errorsEnabled, flags)
|
||||
|
||||
var dummyErrors: CandidateErrors = @[]
|
||||
var dummyErrors: CandidateErrors
|
||||
template pickSpecialOp(headSymbol) =
|
||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||
filter, result, alt, dummyErrors, efExplain in flags,
|
||||
@@ -556,15 +513,6 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
||||
for i in 1..<n.len:
|
||||
instGenericConvertersArg(c, n[i], x)
|
||||
|
||||
proc markConvertersUsed*(c: PContext, n: PNode) =
|
||||
assert n.kind in nkCallKinds
|
||||
for i in 1..<n.len:
|
||||
var a = n[i]
|
||||
if a == nil: continue
|
||||
if a.kind == nkHiddenDeref: a = a[0]
|
||||
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
|
||||
markUsed(c, a.info, a[0].sym)
|
||||
|
||||
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||
var m = newCandidate(c, f)
|
||||
result = paramTypesMatch(m, f, a, arg, nil)
|
||||
@@ -616,8 +564,64 @@ proc getCallLineInfo(n: PNode): TLineInfo =
|
||||
discard
|
||||
result = n.info
|
||||
|
||||
proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
n: PNode, flags: TExprFlags): PNode =
|
||||
proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
|
||||
## Helper proc to inherit bound generic parameters from expectedType into x.
|
||||
## Does nothing if 'inferGenericTypes' isn't in c.features.
|
||||
if inferGenericTypes notin c.features: return
|
||||
if expectedType == nil or x.callee[0] == nil: return # required for inference
|
||||
|
||||
var
|
||||
flatUnbound: seq[PType] = @[]
|
||||
flatBound: seq[PType] = @[]
|
||||
# seq[(result type, expected type)]
|
||||
var typeStack = newSeq[(PType, PType)]()
|
||||
|
||||
template stackPut(a, b) =
|
||||
## skips types and puts the skipped version on stack
|
||||
# It might make sense to skip here one by one. It's not part of the main
|
||||
# type reduction because the right side normally won't be skipped
|
||||
const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink }
|
||||
let
|
||||
x = a.skipTypes(toSkip)
|
||||
y = if a.kind notin toSkip: b
|
||||
else: b.skipTypes(toSkip)
|
||||
typeStack.add((x, y))
|
||||
|
||||
stackPut(x.callee[0], expectedType)
|
||||
|
||||
while typeStack.len() > 0:
|
||||
let (t, u) = typeStack.pop()
|
||||
if t == u or t == nil or u == nil or t.kind == tyAnything or u.kind == tyAnything:
|
||||
continue
|
||||
case t.kind
|
||||
of ConcreteTypes, tyGenericInvocation, tyUncheckedArray:
|
||||
# nested, add all the types to stack
|
||||
let
|
||||
startIdx = if u.kind in ConcreteTypes: 0 else: 1
|
||||
endIdx = min(u.len() - startIdx, t.len())
|
||||
|
||||
for i in startIdx ..< endIdx:
|
||||
# early exit with current impl
|
||||
if t[i] == nil or u[i] == nil: return
|
||||
stackPut(t[i], u[i])
|
||||
of tyGenericParam:
|
||||
let prebound = x.bindings.idTableGet(t).PType
|
||||
if prebound != nil:
|
||||
continue # Skip param, already bound
|
||||
|
||||
# fully reduced generic param, bind it
|
||||
if t notin flatUnbound:
|
||||
flatUnbound.add(t)
|
||||
flatBound.add(u)
|
||||
else:
|
||||
discard
|
||||
# update bindings
|
||||
for i in 0 ..< flatUnbound.len():
|
||||
x.bindings.idTablePut(flatUnbound[i], flatBound[i])
|
||||
|
||||
proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
n: PNode, flags: TExprFlags;
|
||||
expectedType: PType = nil): PNode =
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
let info = getCallLineInfo(n)
|
||||
@@ -637,10 +641,12 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
if x.calleeSym.magic in {mArrGet, mArrPut}:
|
||||
finalCallee = x.calleeSym
|
||||
else:
|
||||
c.inheritBindings(x, expectedType)
|
||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||
else:
|
||||
# For macros and templates, the resolved generic params
|
||||
# are added as normal params.
|
||||
c.inheritBindings(x, expectedType)
|
||||
for s in instantiateGenericParamList(c, gp, x.bindings):
|
||||
case s.kind
|
||||
of skConst:
|
||||
@@ -649,21 +655,14 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
else:
|
||||
x.call.add c.graph.emptyNode
|
||||
of skType:
|
||||
var tn = newSymNode(s, n.info)
|
||||
# this node will be used in template substitution,
|
||||
# pretend this is an untyped node and let regular sem handle the type
|
||||
# to prevent problems where a generic parameter is treated as a value
|
||||
tn.typ = nil
|
||||
x.call.add tn
|
||||
x.call.add newSymNode(s, n.info)
|
||||
else:
|
||||
internalAssert c.config, false
|
||||
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
markConvertersUsed(c, result)
|
||||
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
|
||||
if finalCallee.magic notin {mArrGet, mArrPut}:
|
||||
result.typ = finalCallee.typ[0]
|
||||
result.typ = finalCallee.typ[0]
|
||||
updateDefaultParams(result)
|
||||
|
||||
proc canDeref(n: PNode): bool {.inline.} =
|
||||
@@ -676,7 +675,8 @@ proc tryDeref(n: PNode): PNode =
|
||||
result.add n
|
||||
|
||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds, flags: TExprFlags): PNode =
|
||||
filter: TSymKinds, flags: TExprFlags;
|
||||
expectedType: PType = nil): PNode =
|
||||
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
|
||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
||||
if r.state == csMatch:
|
||||
@@ -686,7 +686,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
message(c.config, n.info, hintUserRaw,
|
||||
"Non-matching candidates for " & renderTree(n) & "\n" &
|
||||
candidates)
|
||||
result = semResolvedCall(c, r, n, flags)
|
||||
result = semResolvedCall(c, r, n, flags, expectedType)
|
||||
else:
|
||||
if efDetermineType in flags and c.inGenericContext > 0 and c.matchedConcept == nil:
|
||||
result = semGenericStmt(c, n)
|
||||
@@ -696,7 +696,10 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
# this time enabling all the diagnostic output (this should fail again)
|
||||
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
||||
elif efNoUndeclared notin flags:
|
||||
result = nil
|
||||
notFoundError(c, n, errors)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc explicitGenericInstError(c: PContext; n: PNode): PNode =
|
||||
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
|
||||
@@ -714,8 +717,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
if formal.kind == tyStatic and arg.kind != tyStatic:
|
||||
let evaluated = c.semTryConstExpr(c, n[i])
|
||||
if evaluated != nil:
|
||||
arg = newTypeS(tyStatic, c)
|
||||
arg.sons = @[evaluated.typ]
|
||||
arg = newTypeS(tyStatic, c, sons = @[evaluated.typ])
|
||||
arg.n = evaluated
|
||||
let tm = typeRel(m, formal, arg)
|
||||
if tm in {isNone, isConvertible}: return nil
|
||||
@@ -726,18 +728,14 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
onUse(info, s)
|
||||
result = newSymNode(newInst, info)
|
||||
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
## sems generic params in subscript expression
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
for i in 1..<n.len:
|
||||
let e = semExprWithType(c, n[i])
|
||||
if e.typ == nil:
|
||||
n[i].typ = errorType(c)
|
||||
else:
|
||||
n[i].typ = e.typ.skipTypes({tyTypeDesc})
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
setGenericParams(c, n)
|
||||
var s = s
|
||||
var a = n[0]
|
||||
if a.kind == nkSym:
|
||||
@@ -820,7 +818,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS
|
||||
if resolved != nil:
|
||||
result.s = resolved[0].sym
|
||||
result.state = bsMatch
|
||||
if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}):
|
||||
if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct):
|
||||
result.state = bsReturnNotMatch
|
||||
elif result.s.magic in {mArrPut, mArrGet}:
|
||||
# cannot borrow these magics for now
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user