mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
2 Commits
version-2-
...
pr_fix_sig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aacf94d72c | ||
|
|
c1b90783eb |
69
.github/stale.yml
vendored
Normal file
69
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 365
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 30
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- ARC
|
||||
- bounty
|
||||
- Codegen
|
||||
- Crash
|
||||
- Generics
|
||||
- High Priority
|
||||
- Macros
|
||||
- Next release
|
||||
- Showstopper
|
||||
- Static[T]
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity.
|
||||
If you think it is still a valid PR, please rebase it on the latest devel;
|
||||
otherwise it will be closed. Thank you for your contributions.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
# closeComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 20
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: pulls
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
||||
29
.github/workflows/bisects.yml
vendored
29
.github/workflows/bisects.yml
vendored
@@ -1,29 +0,0 @@
|
||||
# See https://github.com/juancarlospaco/nimrun-action/issues/3#issuecomment-1607344901
|
||||
name: issue comments bisects
|
||||
on:
|
||||
issue_comment:
|
||||
types: created
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install OpenSSL (Windows)
|
||||
if: |
|
||||
runner.os == 'Windows'
|
||||
run: choco install openssl.light --version=1.1.1.0 # OpenSSL 3.x removed SSL_library_init
|
||||
shell: 'powershell'
|
||||
|
||||
# v2 wont work here, because uses "hardcoded" nim versions, action "dynamically" finds version with bug.
|
||||
- uses: jiro4989/setup-nim-action@v1
|
||||
with:
|
||||
nim-version: 'devel'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install --no-install-recommends -yq valgrind
|
||||
|
||||
- uses: juancarlospaco/nimrun-action@nim
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
115
.github/workflows/ci_bench.yml
vendored
115
.github/workflows/ci_bench.yml
vendored
@@ -1,115 +0,0 @@
|
||||
name: Benchmarks CI
|
||||
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@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Build csourcesAny'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
|
||||
|
||||
- name: 'Build koch'
|
||||
shell: bash
|
||||
run: nim c koch
|
||||
|
||||
- name: 'Build Nim'
|
||||
shell: bash
|
||||
run: ./koch boot -d:release -d:nimStrictMode --lib:lib
|
||||
|
||||
- name: 'Build Nimble'
|
||||
shell: bash
|
||||
run: ./koch nimble
|
||||
|
||||
- name: 'Action'
|
||||
shell: bash
|
||||
run: nim c -r -d:release ci/action.nim
|
||||
|
||||
- name: 'Checkout minimize'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'nim-lang/ci_bench'
|
||||
path: minimize
|
||||
|
||||
- name: 'Run minimize benchmarks'
|
||||
shell: bash
|
||||
run: ./minimize/minimize ci-bench
|
||||
|
||||
- name: 'Restore minimize cached database'
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: minimize.csv
|
||||
key: minimize-db-key
|
||||
|
||||
- name: 'Update minimize db'
|
||||
shell: bash
|
||||
run: ./minimize/minimize update-db
|
||||
|
||||
- name: 'Save minimize cached database'
|
||||
if: |
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
|
||||
matrix.target == 'linux'
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: minimize.csv
|
||||
key: minimize-db-key
|
||||
|
||||
- name: 'Generate minimize report'
|
||||
shell: bash
|
||||
run: ./minimize/minimize generate-report
|
||||
|
||||
- name: 'Archive minimize report'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: minimize-report
|
||||
path: |
|
||||
minimize/minimize.html
|
||||
minimize/minimize.csv
|
||||
|
||||
# Requires additional permissions, see:
|
||||
# https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566
|
||||
# - name: 'Publish HTML report'
|
||||
# uses: rossjrw/pr-preview-action@v1
|
||||
# with:
|
||||
# source-dir: minimize
|
||||
# umbrella-dir: minimize
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract md summary
|
||||
run: |
|
||||
cat minimize/summary.md >> $GITHUB_STEP_SUMMARY
|
||||
8
.github/workflows/ci_docs.yml
vendored
8
.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-15
|
||||
os: macos-11
|
||||
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
if: |
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
|
||||
matrix.target == 'linux'
|
||||
uses: crazy-max/ghaction-github-pages@v5
|
||||
uses: crazy-max/ghaction-github-pages@v3
|
||||
with:
|
||||
build_dir: doc/html
|
||||
env:
|
||||
|
||||
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
|
||||
23
.github/workflows/ci_packages.yml
vendored
23
.github/workflows/ci_packages.yml
vendored
@@ -17,13 +17,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-14]
|
||||
os: [ubuntu-20.04, macos-11]
|
||||
cpu: [amd64]
|
||||
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
cpu: amd64
|
||||
- os: macos-14
|
||||
cpu: arm64
|
||||
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60 # refs bug #18178
|
||||
@@ -32,27 +28,26 @@ jobs:
|
||||
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v6
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: '16.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-get install --no-install-recommends -yq \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev liblapack-dev libpcre3 xorg-dev
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
# XXX can't find boehm and gtk on macos 13
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
|
||||
24
.github/workflows/ci_publish.yml
vendored
24
.github/workflows/ci_publish.yml
vendored
@@ -11,20 +11,20 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04]
|
||||
os: [ubuntu-20.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v6
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 24
|
||||
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
|
||||
@@ -60,7 +71,7 @@ jobs:
|
||||
run: nim c -r -d:release ci/action.nim
|
||||
|
||||
- name: 'Comment'
|
||||
uses: actions/github-script@v9
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
@@ -76,3 +87,4 @@ jobs:
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
|
||||
25
.github/workflows/stale.yml
vendored
25
.github/workflows/stale.yml
vendored
@@ -1,25 +0,0 @@
|
||||
# https://github.com/actions/stale#usage
|
||||
name: Stale pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Midnight.
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
days-before-pr-stale: 365
|
||||
days-before-pr-close: 30
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]"
|
||||
exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority"
|
||||
stale-pr-message: >
|
||||
This pull request is stale because it has been open for 1 year with no activity.
|
||||
Contribute more commits on the pull request and rebase it on the latest devel,
|
||||
or it will be closed in 30 days. Thank you for your contributions.
|
||||
close-pr-message: >
|
||||
This pull request has been marked as stale and closed due to inactivity after 395 days.
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -67,7 +67,6 @@ testament.db
|
||||
|
||||
/csources
|
||||
/csources_v1
|
||||
/csources_v2
|
||||
|
||||
/dist/
|
||||
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it
|
||||
@@ -110,5 +109,3 @@ htmldocs
|
||||
nimdoc.out.css
|
||||
# except here:
|
||||
!/nimdoc/testproject/expected/*
|
||||
pkgs/
|
||||
/compiler/compiler/
|
||||
|
||||
62
.gitlab-ci.yml
Normal file
62
.gitlab-ci.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
# xxx unused, out of date
|
||||
|
||||
image: ubuntu:18.04
|
||||
|
||||
stages:
|
||||
- pre-build
|
||||
- build
|
||||
- deploy
|
||||
- test
|
||||
|
||||
.linux_set_path: &linux_set_path_def
|
||||
before_script:
|
||||
- export PATH=$(pwd)/bin${PATH:+:$PATH}
|
||||
tags:
|
||||
- linux
|
||||
|
||||
.windows_set_path: &win_set_path_def
|
||||
before_script:
|
||||
- set PATH=%CD%\bin;%PATH%
|
||||
tags:
|
||||
- windows
|
||||
|
||||
|
||||
build-windows:
|
||||
stage: build
|
||||
script:
|
||||
- ci\build.bat
|
||||
artifacts:
|
||||
paths:
|
||||
- bin\nim.exe
|
||||
- bin\nimd.exe
|
||||
- compiler\nim.exe
|
||||
- koch.exe
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- windows
|
||||
|
||||
deploy-windows:
|
||||
stage: deploy
|
||||
script:
|
||||
- koch.exe winrelease
|
||||
artifacts:
|
||||
paths:
|
||||
- build/*.exe
|
||||
- build/*.zip
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- windows
|
||||
- fast
|
||||
|
||||
|
||||
|
||||
test-windows:
|
||||
stage: test
|
||||
<<: *win_set_path_def
|
||||
script:
|
||||
- call ci\deps.bat
|
||||
- nim c testament\tester
|
||||
- testament\tester.exe all
|
||||
tags:
|
||||
- windows
|
||||
- fast
|
||||
@@ -20,32 +20,32 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
vmImage: 'ubuntu-20.04'
|
||||
CPU: amd64
|
||||
# regularly breaks, refs bug #17325
|
||||
# Linux_i386:
|
||||
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
# vmImage: 'ubuntu-18.04'
|
||||
# CPU: i386
|
||||
OSX_arm64:
|
||||
vmImage: 'macos-15'
|
||||
CPU: arm64
|
||||
OSX_arm64_cpp:
|
||||
vmImage: 'macos-15'
|
||||
CPU: arm64
|
||||
Linux_i386:
|
||||
# on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
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
|
||||
|
||||
@@ -14,7 +14,7 @@ else
|
||||
fi
|
||||
|
||||
# Find out where the pretty printer Python module is
|
||||
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py"
|
||||
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py"
|
||||
|
||||
# Run GDB with the additional arguments that load the pretty printers
|
||||
# Set the environment variable `NIM_GDB` to overwrite the call to a
|
||||
|
||||
@@ -3,7 +3,7 @@ for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i)
|
||||
|
||||
for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi)
|
||||
|
||||
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py
|
||||
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py
|
||||
set @NIM_GDB=gdb.exe
|
||||
|
||||
@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt
|
||||
|
||||
@@ -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
|
||||
|
||||
386
changelog.md
386
changelog.md
@@ -1,135 +1,319 @@
|
||||
# v2.2.0 - yyyy-mm-dd
|
||||
# v2.0.0 - yyyy-mm-dd
|
||||
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
|
||||
|
||||
- `-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.
|
||||
- `addr` is now available for all addressable locations,
|
||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
||||
|
||||
- Certain definitions from the default `system` module have been moved to
|
||||
the following new modules:
|
||||
|
||||
- `std/syncio`
|
||||
- `std/assertions`
|
||||
- `std/formatfloat`
|
||||
- `std/objectdollar`
|
||||
- `std/widestrs`
|
||||
- `std/typedthreads`
|
||||
- `std/sysatomics`
|
||||
|
||||
In the future, these definitions will be removed from the `system` module,
|
||||
and their respective modules will have to be imported to use them.
|
||||
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
|
||||
may be used.
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
|
||||
symbols in the `system` module:
|
||||
- Aliases with `Error` suffix to exception types that have a `Defect` suffix
|
||||
(see [exceptions](https://nim-lang.org/docs/exceptions.html)):
|
||||
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
|
||||
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
|
||||
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
|
||||
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
|
||||
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
|
||||
`DeadThreadError`, `NilAccessError`
|
||||
- `addQuitProc`, replaced by `exitprocs.addExitProc`
|
||||
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
|
||||
- `TaintedString`, formerly a distinct alias to `string`
|
||||
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
|
||||
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
|
||||
in the `system` module.
|
||||
|
||||
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
|
||||
|
||||
- The `gc:v2` option is removed.
|
||||
|
||||
- The `mainmodule` and `m` options are removed.
|
||||
|
||||
- The `threads:on` option is now the default.
|
||||
|
||||
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
|
||||
`experimental:flexibleOptionalParams`.
|
||||
|
||||
- Automatic dereferencing (experimental feature) is removed.
|
||||
|
||||
- The `Math.trunc` polyfill for targeting Internet Explorer was
|
||||
previously included in most JavaScript output files.
|
||||
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
|
||||
If you are targeting Internet Explorer, you may choose to enable this option
|
||||
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
|
||||
Nim uses `Math.trunc` for the division and modulo operators for integers.
|
||||
|
||||
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
|
||||
`sink` for optimization purposes.
|
||||
|
||||
- The `nimPreviewDotLikeOps` define is going to be removed or deprecated.
|
||||
|
||||
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
|
||||
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
|
||||
```nim
|
||||
type Foo = distinct ptr int
|
||||
|
||||
# Before:
|
||||
var x: Foo = nil
|
||||
# After:
|
||||
var x: Foo = Foo(nil)
|
||||
```
|
||||
- Removed two type pragma syntaxes deprecated since 0.20, namely
|
||||
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`.
|
||||
|
||||
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
|
||||
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
|
||||
This decision was made with the assumption that the old syntax was used rarely;
|
||||
if your code used the old syntax, please be aware of this change.
|
||||
|
||||
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
|
||||
are no longer experimental.
|
||||
|
||||
- Removed the `nimIncrSeqV3` define.
|
||||
|
||||
- `macros.getImpl` for `const` symbols now returns the full definition node
|
||||
(as `nnkConstDef`) rather than the AST of the constant value.
|
||||
|
||||
- Lock levels are deprecated, now a noop.
|
||||
|
||||
- ORC is now the default memory management strategy. Use
|
||||
`--mm:refc` for a transition period.
|
||||
|
||||
- `strictEffects` are no longer experimental.
|
||||
Use `legacy:laxEffects` to keep backward compatibility.
|
||||
|
||||
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
||||
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
|
||||
|
||||
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
|
||||
This warning will become an error in future versions! Use a `cast` operation
|
||||
like `cast[cstring](x)` instead.
|
||||
|
||||
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
|
||||
|
||||
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
|
||||
|
||||
- Redefining templates with the same signature was previously
|
||||
allowed to support certain macro code. To do this explicitly, the
|
||||
`{.redefine.}` pragma has been added. Note that this is only for templates.
|
||||
Implicit redefinition of templates is now deprecated and will give an error in the future.
|
||||
|
||||
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
|
||||
|
||||
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
|
||||
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
|
||||
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
|
||||
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
- OpenSSL 3 is now supported.
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
filename argument for more informative errors.
|
||||
- Module `colors` expanded with missing colors from the CSS color standard.
|
||||
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
- The `md5` module now works at compile time and in JavaScript.
|
||||
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables.
|
||||
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
|
||||
making limiting it to just the first char (`last = 0`) valid.
|
||||
- `random.rand` now works with `Ordinal`s.
|
||||
- Undeprecated `os.isvalidfilename`.
|
||||
- `std/oids` now uses `int64` to store time internally (before it was int32).
|
||||
- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`.
|
||||
- `std/uri.Uri.isIpv6` is now exported.
|
||||
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
|
||||
|
||||
|
||||
- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`.
|
||||
- `std/jsfetch.newFetchOptions` now has default values for all parameters
|
||||
- `std/jsformdata` now accepts `Blob` data type.
|
||||
|
||||
|
||||
[//]: # "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.
|
||||
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
|
||||
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
|
||||
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
|
||||
instead of `--mm:orc`.
|
||||
- A `$` template is provided for `Path` in `std/paths`.
|
||||
- Added ISO 8601 week date utilities in `times`:
|
||||
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
|
||||
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
|
||||
- Added a `initDateTime` overload to create a datetime from an ISO week date.
|
||||
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
|
||||
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
|
||||
- Added new modules which were part of `std/os`:
|
||||
- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling.
|
||||
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
|
||||
- Added `std/cmdline` for reading command line parameters.
|
||||
- Added `sep` parameter in `std/uri` to specify the query separator.
|
||||
- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
|
||||
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
|
||||
in `jscore` for JavaScript targets.
|
||||
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
|
||||
- Added `complex.sgn` for obtaining the phase of complex numbers.
|
||||
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
|
||||
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
|
||||
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
|
||||
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
|
||||
`toggleAttribute`, and `matches` to `std/dom`.
|
||||
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
|
||||
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
|
||||
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
|
||||
- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse.
|
||||
- Added `safe` parameter to `base64.encodeMime`.
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
|
||||
- Deprecated `selfExe` for Nimscript.
|
||||
- Deprecated `std/sums`.
|
||||
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
|
||||
Now only `byte` and `char` are supported.
|
||||
|
||||
[//]: # "Removals:"
|
||||
- Removed deprecated module `parseopt2`.
|
||||
- Removed deprecated module `sharedstrings`.
|
||||
- Removed deprecated module `dom_extensions`.
|
||||
- Removed deprecated module `LockFreeHash`.
|
||||
- Removed deprecated module `events`.
|
||||
- Removed deprecated `oids.oidToString`.
|
||||
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
|
||||
- Removed deprecated `jsre.test` and `jsre.toString`.
|
||||
- Removed deprecated `math.c_frexp`.
|
||||
- Removed deprecated `` httpcore.`==` ``.
|
||||
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
|
||||
- Removed deprecated `osproc.poDemon`, symbol with typo.
|
||||
- Removed deprecated `tables.rightSize`.
|
||||
|
||||
|
||||
- Removed deprecated `posix.CLONE_STOPPED`.
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma
|
||||
which can be used to disable certain effects in proc types.
|
||||
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
|
||||
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
|
||||
for the right-hand side of type definitions in type sections. Previously
|
||||
they would error with "invalid indentation".
|
||||
|
||||
- Compile-time define changes:
|
||||
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
|
||||
In the command line, this is defined as `-d:a.b.c`. Older versions can
|
||||
use accents as in ``defined(`a.b.c`)`` to access such defines.
|
||||
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
|
||||
now support a string argument for qualified define names.
|
||||
|
||||
- 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.
|
||||
```nim
|
||||
# -d:package.FooBar=42
|
||||
const FooBar {.intdefine: "package.FooBar".}: int = 5
|
||||
echo FooBar # 42
|
||||
```
|
||||
|
||||
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.
|
||||
This was added to help disambiguate similar define names for different packages.
|
||||
In older versions, this could only be achieved with something like the following:
|
||||
|
||||
```nim
|
||||
const FooBar = block:
|
||||
const `package.FooBar` {.intdefine.}: int = 5
|
||||
`package.FooBar`
|
||||
```
|
||||
- A generic `define` pragma for constants has been added that interprets
|
||||
the value of the define based on the type of the constant value.
|
||||
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma)
|
||||
for a list of supported types.
|
||||
|
||||
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
|
||||
- Templates now accept macro pragmas.
|
||||
- Macro pragmas for var/let/const sections have been redesigned in a way that works
|
||||
similarly to routine macro pragmas. The new behavior is documented in the
|
||||
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
|
||||
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||
allowing multiple type definitions to be injected in place of the original type definition.
|
||||
|
||||
```nim
|
||||
import macros
|
||||
macro multiply(amount: static int, s: untyped): untyped =
|
||||
let name = $s[0].basename
|
||||
result = newNimNode(nnkTypeSection)
|
||||
for i in 1 .. amount:
|
||||
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||
type
|
||||
Foo = object
|
||||
Bar {.multiply: 3.} = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
# becomes
|
||||
type
|
||||
Foo = object
|
||||
Bar1 = object
|
||||
x, y, z: int
|
||||
Bar2 = object
|
||||
x, y, z: int
|
||||
Bar3 = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
```
|
||||
|
||||
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
|
||||
has been implemented for a variety of basic cases. For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
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"
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
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.
|
||||
- `cstring` is now accepted as a selector in `case` statements, removing the
|
||||
need to convert to `string`. On the JS backend, this is translated directly
|
||||
to a `switch` statement.
|
||||
|
||||
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 now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
|
||||
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
|
||||
|
||||
```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
|
||||
|
||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||
|
||||
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
|
||||
|
||||
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
|
||||
without requiring `-d:nimVersion140` which is now a noop.
|
||||
|
||||
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
|
||||
|
||||
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
|
||||
related functions produced on the backend. This prevents conflicts with other Nim
|
||||
static libraries.
|
||||
|
||||
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
|
||||
|
||||
|
||||
## Tool changes
|
||||
|
||||
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.
|
||||
|
||||
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`).
|
||||
|
||||
33
changelogs/changelog.md
Normal file
33
changelogs/changelog.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# v1.xx.x - yyyy-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
|
||||
|
||||
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
|
||||
|
||||
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
## Tool changes
|
||||
@@ -1,330 +0,0 @@
|
||||
# v2.0.0 - 2023-08-01
|
||||
|
||||
Version 2.0 is a big milestone with too many changes to list them all here.
|
||||
|
||||
For a full list see [details](changelog_2_0_0_details.html).
|
||||
|
||||
|
||||
## New features
|
||||
|
||||
### Better tuple unpacking
|
||||
|
||||
Tuple unpacking for variables is now treated as syntax sugar that directly
|
||||
expands into multiple assignments. Along with this, tuple unpacking for
|
||||
variables can now be nested.
|
||||
|
||||
```nim
|
||||
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
|
||||
|
||||
# Now nesting is supported!
|
||||
let (x, (_, y), _, z) = returnsNestedTuple()
|
||||
|
||||
```
|
||||
|
||||
### Improved type inference
|
||||
|
||||
A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) has been implemented for a variety of basic cases.
|
||||
|
||||
For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
### Forbidden Tags
|
||||
|
||||
[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition
|
||||
of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types.
|
||||
|
||||
For example:
|
||||
|
||||
```nim
|
||||
|
||||
type IO = object ## input/output effect
|
||||
proc readLine(): string {.tags: [IO].} = discard
|
||||
proc echoLine(): void = discard
|
||||
|
||||
proc no_IO_please() {.forbids: [IO].} =
|
||||
# this is OK because it didn't define any tag:
|
||||
echoLine()
|
||||
# the compiler prevents this:
|
||||
let y = readLine()
|
||||
|
||||
```
|
||||
|
||||
### New standard library modules
|
||||
|
||||
The famous `os` module got an overhaul. Several of its features are available
|
||||
under a new interface that introduces a `Path` abstraction. A `Path` is
|
||||
a `distinct string`, which improves the type safety when dealing with paths, files
|
||||
and directories.
|
||||
|
||||
Use:
|
||||
|
||||
- `std/oserrors` for OS error reporting.
|
||||
- `std/envvars` for environment variables handling.
|
||||
- `std/paths` for path handling.
|
||||
- `std/dirs` for directory creation/deletion/traversal.
|
||||
- `std/files` for file existence checking, file deletions and moves.
|
||||
- `std/symlinks` for symlink handling.
|
||||
- `std/appdirs` for accessing configuration/home/temp directories.
|
||||
- `std/cmdline` for reading command line parameters.
|
||||
|
||||
### Consistent underscore handling
|
||||
|
||||
The underscore identifier (`_`) is now generally not added to scope when
|
||||
used as the name of a definition. While this was already the case for
|
||||
variables, it is now also the case for routine parameters, generic
|
||||
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
|
||||
|
||||
```nim
|
||||
proc foo(_: int): int = _ + 1
|
||||
echo foo(1)
|
||||
|
||||
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
|
||||
echo foo[int]()
|
||||
|
||||
proc _() = echo "_"
|
||||
_()
|
||||
|
||||
type _ = int
|
||||
let x: _ = 3
|
||||
```
|
||||
|
||||
Whereas the following code now compiles:
|
||||
|
||||
```nim
|
||||
proc foo(_, _: int): int = 123
|
||||
echo foo(1, 2)
|
||||
|
||||
proc foo[_, _](): int = 123
|
||||
echo foo[int, bool]()
|
||||
|
||||
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
|
||||
echo foo(int, bool)
|
||||
|
||||
proc _() = echo "one"
|
||||
proc _() = echo "two"
|
||||
|
||||
type _ = int
|
||||
type _ = float
|
||||
```
|
||||
|
||||
### JavaScript codegen improvement
|
||||
|
||||
The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
|
||||
JS code generation, code using these types to interface with the JS backend
|
||||
may need to be updated. Note that `int` and `uint` are not affected.
|
||||
|
||||
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
|
||||
and in the case of potential bugs with the new implementation, the
|
||||
old behavior is currently still supported with the command line option
|
||||
`--jsbigint64:off`.
|
||||
|
||||
|
||||
## Docgen improvements
|
||||
|
||||
`Markdown` is now the default markup language of doc comments (instead
|
||||
of the legacy `RstMarkdown` mode). In this release we begin to separate
|
||||
RST and Markdown features to better follow specification of each
|
||||
language, with the focus on Markdown development.
|
||||
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
|
||||
|
||||
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
|
||||
select the markup language mode in the doc comments of the current `.nim`
|
||||
file for processing by `nim doc`:
|
||||
|
||||
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
|
||||
some Pandoc Markdown features + some RST features that are missing
|
||||
in our current implementation of CommonMark and Pandoc Markdown.
|
||||
2. `RST` closely follows the RST spec with few additional Nim features.
|
||||
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
|
||||
is kept for the sake of compatibility and ease of migration.
|
||||
|
||||
* Added separate `md2html` and `rst2html` commands for processing
|
||||
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
|
||||
|
||||
* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
|
||||
* Docgen now supports concise syntax for referencing Nim symbols:
|
||||
instead of specifying HTML anchors directly one can use original
|
||||
Nim symbol declarations (adding the aforementioned link brackets
|
||||
`[...]` around them).
|
||||
* To use this feature across modules, a new `importdoc` directive was added.
|
||||
Using this feature for referencing also helps to ensure that links
|
||||
(inside one module or the whole project) are not broken.
|
||||
* Added support for RST & Markdown quote blocks (blocks starting with `>`).
|
||||
* Added a popular Markdown definition lists extension.
|
||||
* Added Markdown indented code blocks (blocks indented by >= 4 spaces).
|
||||
* Added syntax for additional parameters to Markdown code blocks:
|
||||
|
||||
```nim test="nim c $1"
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## C++ interop enhancements
|
||||
|
||||
Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
|
||||
Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize
|
||||
the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types.
|
||||
|
||||
It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```cpp
|
||||
|
||||
struct Base {
|
||||
int someValue;
|
||||
Base(int inValue) {
|
||||
someValue = inValue;
|
||||
};
|
||||
};
|
||||
|
||||
class IPrinter {
|
||||
public:
|
||||
virtual void print() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
```nim
|
||||
|
||||
type
|
||||
Base* {.importcpp, inheritable.} = object
|
||||
someValue*: int32
|
||||
IPrinter* {.importcpp.} = object
|
||||
|
||||
const objTemplate = """
|
||||
struct $1 : public $3, public IPrinter {
|
||||
$2
|
||||
};
|
||||
""";
|
||||
|
||||
type NimChild {.codegenDecl: objTemplate .} = object of Base
|
||||
|
||||
proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} =
|
||||
echo "It calls the base constructor passing " & $this.someValue
|
||||
this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`.
|
||||
|
||||
proc print*(self: NimChild) {.virtual.} =
|
||||
echo "Some value is " & $self.someValue
|
||||
|
||||
let child = makeNimChild(10)
|
||||
child.print()
|
||||
```
|
||||
|
||||
It outputs:
|
||||
|
||||
```
|
||||
It calls the base constructor passing 10
|
||||
Some value is 20
|
||||
```
|
||||
|
||||
|
||||
## ARC/ORC refinements
|
||||
|
||||
With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete:
|
||||
|
||||
1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable.
|
||||
2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations.
|
||||
3. Destructors now take a parameter of the attached object type `T` directly and don't have to take a `var T` parameter.
|
||||
|
||||
With these important optimizations we improved the runtime of the compiler and important benchmarks by 0%! Wait ... what?
|
||||
Yes, unfortunately it turns out that for a modern optimizer like in GCC or LLVM there is no difference.
|
||||
|
||||
But! This refined model is more efficient once separate compilation enters the picture. In other words, as we think of
|
||||
providing a stable ABI it is important not to lose any efficiency in the calling conventions.
|
||||
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
|
||||
- nimgrep now offers the option `--inContext` (and `--notInContext`), which
|
||||
allows to filter only matches with the context block containing a given pattern.
|
||||
- nimgrep: names of options containing "include/exclude" are deprecated,
|
||||
e.g. instead of `--includeFile` and `--excludeFile` we have
|
||||
`--filename` and `--notFilename` respectively.
|
||||
Also, the semantics are now consistent for such positive/negative filters.
|
||||
- Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions.
|
||||
|
||||
|
||||
## Porting guide
|
||||
|
||||
### Block and Break
|
||||
|
||||
Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. In other words, turn:
|
||||
|
||||
```nim
|
||||
|
||||
block:
|
||||
a()
|
||||
if cond:
|
||||
break
|
||||
b()
|
||||
|
||||
```
|
||||
|
||||
Into:
|
||||
|
||||
```nim
|
||||
|
||||
block maybePerformB:
|
||||
a()
|
||||
if cond:
|
||||
break maybePerformB
|
||||
b()
|
||||
|
||||
```
|
||||
|
||||
### Strict funcs
|
||||
|
||||
The definition of `"strictFuncs"` was changed.
|
||||
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
|
||||
The new definition is: "A store to a ref/ptr deref is forbidden."
|
||||
|
||||
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
|
||||
accepted:
|
||||
|
||||
```nim
|
||||
|
||||
{.experimental: "strictFuncs".}
|
||||
|
||||
type Node = ref object
|
||||
s: string
|
||||
|
||||
func create(s: string): Node =
|
||||
result = Node()
|
||||
result.s = s # store to result[]
|
||||
|
||||
```
|
||||
|
||||
Now it has to be rewritten to:
|
||||
|
||||
```nim
|
||||
|
||||
{.experimental: "strictFuncs".}
|
||||
|
||||
type Node = ref object
|
||||
s: string
|
||||
|
||||
func create(s: string): Node =
|
||||
result = Node(s: s)
|
||||
|
||||
```
|
||||
|
||||
### Standard library
|
||||
|
||||
Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` to install them:
|
||||
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
- `std/md5` => `checksums/md5`
|
||||
- `std/sha1` => `checksums/sha1`
|
||||
- `std/sums` => `sums`
|
||||
@@ -1,560 +0,0 @@
|
||||
# v2.0.0 - 2023-08-01
|
||||
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- ORC is now the default memory management strategy. Use
|
||||
`--mm:refc` for a transition period.
|
||||
|
||||
- The `threads:on` option is now the default.
|
||||
|
||||
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `ValueError`.
|
||||
|
||||
- `addr` is now available for all addressable locations,
|
||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
||||
|
||||
- Certain definitions from the default `system` module have been moved to
|
||||
the following new modules:
|
||||
|
||||
- `std/syncio`
|
||||
- `std/assertions`
|
||||
- `std/formatfloat`
|
||||
- `std/objectdollar`
|
||||
- `std/widestrs`
|
||||
- `std/typedthreads`
|
||||
- `std/sysatomics`
|
||||
|
||||
In the future, these definitions will be removed from the `system` module,
|
||||
and their respective modules will have to be imported to use them.
|
||||
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
|
||||
may be used.
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
|
||||
symbols in the `system` module:
|
||||
- Aliases with an `Error` suffix to exception types that have a `Defect` suffix
|
||||
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
|
||||
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
|
||||
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
|
||||
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
|
||||
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
|
||||
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
|
||||
`DeadThreadError`, `NilAccessError`
|
||||
- `addQuitProc`, replaced by `exitprocs.addExitProc`
|
||||
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
|
||||
- `TaintedString`, formerly a distinct alias to `string`
|
||||
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
|
||||
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
|
||||
in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`.
|
||||
|
||||
- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore.
|
||||
|
||||
- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to
|
||||
`pointer` anymore. `cast` may be used instead.
|
||||
|
||||
- The `gc:v2` option is removed.
|
||||
|
||||
- The `mainmodule` and `m` options are removed.
|
||||
|
||||
- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/405))
|
||||
are now opt-in via `experimental:flexibleOptionalParams`.
|
||||
|
||||
- Automatic dereferencing (experimental feature) is removed.
|
||||
|
||||
- The `Math.trunc` polyfill for targeting Internet Explorer was
|
||||
previously included in most JavaScript output files.
|
||||
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
|
||||
If you are targeting Internet Explorer, you may choose to enable this option
|
||||
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
|
||||
Nim uses `Math.trunc` for the division and modulo operators for integers.
|
||||
|
||||
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
|
||||
`sink` for optimization purposes.
|
||||
|
||||
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fulfill its promises.
|
||||
|
||||
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
|
||||
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
|
||||
```nim
|
||||
type Foo = distinct ptr int
|
||||
|
||||
# Before:
|
||||
var x: Foo = nil
|
||||
# After:
|
||||
var x: Foo = Foo(nil)
|
||||
```
|
||||
- Removed two type pragma syntaxes deprecated since 0.20, namely
|
||||
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. Instead,
|
||||
use `type Foo[T] {.final.} = object`.
|
||||
|
||||
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
|
||||
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
|
||||
This decision was made with the assumption that the old syntax was used rarely;
|
||||
if your code used the old syntax, please be aware of this change.
|
||||
|
||||
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
|
||||
are no longer experimental.
|
||||
|
||||
- `macros.getImpl` for `const` symbols now returns the full definition node
|
||||
(as `nnkConstDef`) rather than the AST of the constant value.
|
||||
|
||||
- Lock levels are deprecated, now a noop.
|
||||
|
||||
- `strictEffects` are no longer experimental.
|
||||
Use `legacy:laxEffects` to keep backward compatibility.
|
||||
|
||||
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
||||
if the execution fails for whatever reason. To get back legacy behaviour, use `-d:nimLegacyGorgeErrors`.
|
||||
|
||||
- Pointer to `cstring` conversions now trigger a `[PtrToCstringConv]` warning.
|
||||
This warning will become an error in future versions! Use a `cast` operation
|
||||
like `cast[cstring](x)` instead.
|
||||
|
||||
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
|
||||
|
||||
- Redefining templates with the same signature was previously
|
||||
allowed to support certain macro code. To do this explicitly, the
|
||||
`{.redefine.}` pragma has been added. Note that this is only for templates.
|
||||
Implicit redefinition of templates is now deprecated and will give an error in the future.
|
||||
|
||||
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
|
||||
|
||||
- Several Standard libraries have been moved to nimble packages, use `nimble` to install them:
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
- `std/md5` => `checksums/md5`
|
||||
- `std/sha1` => `checksums/sha1`
|
||||
- `std/sums` => `std/sums`
|
||||
|
||||
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
|
||||
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
|
||||
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
|
||||
|
||||
- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning:
|
||||
```nim
|
||||
try:
|
||||
discard
|
||||
except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept]
|
||||
discard
|
||||
```
|
||||
|
||||
- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection.
|
||||
|
||||
- The underscore identifier (`_`) is now generally not added to scope when
|
||||
used as the name of a definition. While this was already the case for
|
||||
variables, it is now also the case for routine parameters, generic
|
||||
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
|
||||
|
||||
```nim
|
||||
proc foo(_: int): int = _ + 1
|
||||
echo foo(1)
|
||||
|
||||
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
|
||||
echo foo[int]()
|
||||
|
||||
proc _() = echo "_"
|
||||
_()
|
||||
|
||||
type _ = int
|
||||
let x: _ = 3
|
||||
```
|
||||
|
||||
Whereas the following code now compiles:
|
||||
|
||||
```nim
|
||||
proc foo(_, _: int): int = 123
|
||||
echo foo(1, 2)
|
||||
|
||||
proc foo[_, _](): int = 123
|
||||
echo foo[int, bool]()
|
||||
|
||||
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
|
||||
echo foo(int, bool)
|
||||
|
||||
proc _() = echo "one"
|
||||
proc _() = echo "two"
|
||||
|
||||
type _ = int
|
||||
type _ = float
|
||||
```
|
||||
|
||||
- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
|
||||
|
||||
- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
|
||||
JS code generation, code using these types to interface with the JS backend
|
||||
may need to be updated. Note that `int` and `uint` are not affected.
|
||||
|
||||
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
|
||||
and in the case of potential bugs with the new implementation, the
|
||||
old behavior is currently still supported with the command line option
|
||||
`--jsbigint64:off`.
|
||||
|
||||
- The `proc` and `iterator` type classes now respectively only match
|
||||
procs and iterators. Previously both type classes matched any of
|
||||
procs or iterators.
|
||||
|
||||
```nim
|
||||
proc prc(): int =
|
||||
123
|
||||
|
||||
iterator iter(): int =
|
||||
yield 123
|
||||
|
||||
proc takesProc[T: proc](x: T) = discard
|
||||
proc takesIter[T: iterator](x: T) = discard
|
||||
|
||||
# always compiled:
|
||||
takesProc(prc)
|
||||
takesIter(iter)
|
||||
# no longer compiles:
|
||||
takesProc(iter)
|
||||
takesIter(prc)
|
||||
```
|
||||
|
||||
- The `proc` and `iterator` type classes now accept a calling convention pragma
|
||||
(i.e. `proc {.closure.}`) that must be shared by matching proc or iterator
|
||||
types. Previously, pragmas were parsed but discarded if no parameter list
|
||||
was given.
|
||||
|
||||
This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with
|
||||
an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma
|
||||
node in the same place as in a concrete `proc` or `iterator` type node. This
|
||||
state of the AST may be unexpected to existing code, both due to the
|
||||
replacement of the `nnkFormalParams` node as well as having child nodes
|
||||
unlike other type class AST.
|
||||
|
||||
- Signed integer literals in `set` literals now default to a range type of
|
||||
`0..255` instead of `0..65535` (the maximum size of sets).
|
||||
|
||||
- `case` statements with `else` branches put before `elif`/`of` branches in macros
|
||||
are rejected with "invalid order of case branches".
|
||||
|
||||
- Destructors now default to `.raises: []` (i.e. destructors must not raise
|
||||
unlisted exceptions) and explicitly raising destructors are implementation
|
||||
defined behavior.
|
||||
|
||||
- The very old, undocumented `deprecated` pragma statement syntax for
|
||||
deprecated aliases is now a no-op. The regular deprecated pragma syntax is
|
||||
generally sufficient instead.
|
||||
|
||||
```nim
|
||||
# now does nothing:
|
||||
{.deprecated: [OldName: NewName].}
|
||||
|
||||
# instead use:
|
||||
type OldName* {.deprecated: "use NewName instead".} = NewName
|
||||
const oldName* {.deprecated: "use newName instead".} = newName
|
||||
```
|
||||
|
||||
`defined(nimalias)` can be used to check for versions when this syntax was
|
||||
available; however since code that used this syntax is usually very old,
|
||||
these deprecated aliases are likely not used anymore and it may make sense
|
||||
to simply remove these statements.
|
||||
|
||||
- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer
|
||||
declared when they are not available on the backend. Previously it would call
|
||||
`doAssert false` at runtime despite the condition being checkable at compile-time.
|
||||
|
||||
- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated.
|
||||
|
||||
- Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
- OpenSSL 3 is now supported.
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
`filename` argument for more informative errors.
|
||||
- The `colors` module is expanded with missing colors from the CSS color standard.
|
||||
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
- The `md5` module now works at compile time and in JavaScript.
|
||||
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef`, to support `const` tables.
|
||||
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
|
||||
making limiting it to just the first char (`last = 0`) valid.
|
||||
- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator.
|
||||
- `random.rand` now works with `Ordinal`s.
|
||||
- Undeprecated `os.isvalidfilename`.
|
||||
- `std/oids` now uses `int64` to store time internally (before, it was int32).
|
||||
- `std/uri.Uri` dollar (`$`) improved, precalculates the `string` result length from the `Uri`.
|
||||
- `std/uri.Uri.isIpv6` is now exported.
|
||||
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
|
||||
|
||||
|
||||
- `std/jsfetch.newFetchOptions` now has default values for all parameters.
|
||||
- `std/jsformdata` now accepts the `Blob` data type.
|
||||
|
||||
- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433).
|
||||
|
||||
- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the Linux `getrandom` syscall.
|
||||
|
||||
This compile flag only affects Linux builds and is necessary if either compiling on a Linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On Linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since Linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (`sysrand` in particular).
|
||||
|
||||
[//]: # "Additions:"
|
||||
- Added ISO 8601 week date utilities in `times`:
|
||||
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
|
||||
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
|
||||
- Added an `initDateTime` overload to create a `DateTime` from an ISO week date.
|
||||
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
|
||||
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
|
||||
- Added new modules which were previously part of `std/os`:
|
||||
- Added `std/oserrors` for OS error reporting.
|
||||
- Added `std/envvars` for environment variables handling.
|
||||
- Added `std/cmdline` for reading command line parameters.
|
||||
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
|
||||
- Added `sep` parameter in `std/uri` to specify the query separator.
|
||||
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
|
||||
- Added `complex.sgn` for obtaining the phase of complex numbers.
|
||||
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
|
||||
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
|
||||
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
|
||||
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
|
||||
`toggleAttribute`, and `matches` to `std/dom`.
|
||||
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices).
|
||||
- Added `capacity` for `string` and `seq` to return the current capacity, see [RFC #460](https://github.com/nim-lang/RFCs/issues/460).
|
||||
- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse.
|
||||
- Added a `safe` parameter to `base64.encodeMime`.
|
||||
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
|
||||
- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences.
|
||||
- `std/jscore` for the JavaScript target:
|
||||
+ Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
|
||||
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask).
|
||||
+ Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`.
|
||||
- Added `BackwardsIndex` overload for `CacheSeq`.
|
||||
- Added support for nested `with` blocks in `std/with`.
|
||||
- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time.
|
||||
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
- Deprecated `selfExe` for Nimscript.
|
||||
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
|
||||
Now only `byte` and `char` are supported.
|
||||
|
||||
[//]: # "Removals:"
|
||||
- Removed deprecated module `parseopt2`.
|
||||
- Removed deprecated module `sharedstrings`.
|
||||
- Removed deprecated module `dom_extensions`.
|
||||
- Removed deprecated module `LockFreeHash`.
|
||||
- Removed deprecated module `events`.
|
||||
- Removed deprecated `oids.oidToString`.
|
||||
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
|
||||
- Removed deprecated `jsre.test` and `jsre.toString`.
|
||||
- Removed deprecated `math.c_frexp`.
|
||||
- Removed deprecated `` httpcore.`==` ``.
|
||||
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that take wrong argument types.
|
||||
- Removed deprecated `osproc.poDemon`, symbol with typo.
|
||||
- Removed deprecated `tables.rightSize`.
|
||||
|
||||
|
||||
- Removed deprecated `posix.CLONE_STOPPED`.
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma
|
||||
which can be used to disable certain effects in proc types.
|
||||
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
|
||||
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
|
||||
for the right-hand side of type definitions in type sections. Previously
|
||||
they would error with "invalid indentation".
|
||||
|
||||
- Compile-time define changes:
|
||||
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
|
||||
In the command line, this is defined as `-d:a.b.c`. Older versions can
|
||||
use backticks as in ``defined(`a.b.c`)`` to access such defines.
|
||||
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
|
||||
now support a string argument for qualified define names.
|
||||
|
||||
```nim
|
||||
# -d:package.FooBar=42
|
||||
const FooBar {.intdefine: "package.FooBar".}: int = 5
|
||||
echo FooBar # 42
|
||||
```
|
||||
|
||||
This was added to help disambiguate similar define names for different packages.
|
||||
In older versions, this could only be achieved with something like the following:
|
||||
|
||||
```nim
|
||||
const FooBar = block:
|
||||
const `package.FooBar` {.intdefine.}: int = 5
|
||||
`package.FooBar`
|
||||
```
|
||||
- A generic `define` pragma for constants has been added that interprets
|
||||
the value of the define based on the type of the constant value.
|
||||
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-nimdefine-pragma)
|
||||
for a list of supported types.
|
||||
|
||||
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
|
||||
- Templates now accept macro pragmas.
|
||||
- Macro pragmas for var/let/const sections have been redesigned in a way that works
|
||||
similarly to routine macro pragmas. The new behavior is documented in the
|
||||
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
|
||||
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||
allowing multiple type definitions to be injected in place of the original type definition.
|
||||
|
||||
```nim
|
||||
import macros
|
||||
|
||||
macro multiply(amount: static int, s: untyped): untyped =
|
||||
let name = $s[0].basename
|
||||
result = newNimNode(nnkTypeSection)
|
||||
for i in 1 .. amount:
|
||||
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||
|
||||
type
|
||||
Foo = object
|
||||
Bar {.multiply: 3.} = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
# becomes
|
||||
type
|
||||
Foo = object
|
||||
Bar1 = object
|
||||
x, y, z: int
|
||||
Bar2 = object
|
||||
x, y, z: int
|
||||
Bar3 = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
```
|
||||
|
||||
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
|
||||
has been implemented for a variety of basic cases. For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
- `cstring` is now accepted as a selector in `case` statements, removing the
|
||||
need to convert to `string`. On the JS backend, this is translated directly
|
||||
to a `switch` statement.
|
||||
|
||||
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
|
||||
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
|
||||
|
||||
- IBM Z architecture and macOS m1 arm64 architecture are supported.
|
||||
|
||||
- `=wasMoved` can now be overridden by users.
|
||||
|
||||
- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code
|
||||
generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care.
|
||||
|
||||
- Tuple unpacking for variables is now treated as syntax sugar that directly
|
||||
expands into multiple assignments. Along with this, tuple unpacking for
|
||||
variables can now be nested.
|
||||
|
||||
```nim
|
||||
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
|
||||
|
||||
let (x, (_, y), _, z) = returnsNestedTuple()
|
||||
# roughly becomes
|
||||
let
|
||||
tmpTup1 = returnsNestedTuple()
|
||||
x = tmpTup1[0]
|
||||
tmpTup2 = tmpTup1[1]
|
||||
y = tmpTup2[1]
|
||||
z = tmpTup1[3]
|
||||
```
|
||||
|
||||
As a result `nnkVarTuple` nodes in variable sections will no longer be
|
||||
reflected in `typed` AST.
|
||||
|
||||
- C++ interoperability:
|
||||
- New [`virtual`](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma added.
|
||||
- Improvements to [`constructor`](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||
|
||||
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
|
||||
|
||||
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
|
||||
without requiring `-d:nimVersion140` which is now a noop.
|
||||
|
||||
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
|
||||
|
||||
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
|
||||
related functions produced on the backend. This prevents conflicts with other Nim
|
||||
static libraries.
|
||||
|
||||
- When compiling for release, the flag `-fno-math-errno` is used for GCC.
|
||||
- Removed deprecated `LineTooLong` hint.
|
||||
- Line numbers and file names of source files work correctly inside templates for JavaScript targets.
|
||||
|
||||
- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers.
|
||||
|
||||
|
||||
## Docgen
|
||||
|
||||
- `Markdown` is now the default markup language of doc comments (instead
|
||||
of the legacy `RstMarkdown` mode). In this release we begin to separate
|
||||
RST and Markdown features to better follow specification of each
|
||||
language, with the focus on Markdown development.
|
||||
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
|
||||
|
||||
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
|
||||
select the markup language mode in the doc comments of the current `.nim`
|
||||
file for processing by `nim doc`:
|
||||
|
||||
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
|
||||
some Pandoc Markdown features + some RST features that are missing
|
||||
in our current implementation of CommonMark and Pandoc Markdown.
|
||||
2. `RST` closely follows the RST spec with few additional Nim features.
|
||||
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
|
||||
is kept for the sake of compatibility and ease of migration.
|
||||
|
||||
* Added separate `md2html` and `rst2html` commands for processing
|
||||
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
|
||||
|
||||
- Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
|
||||
- Docgen now supports concise syntax for referencing Nim symbols:
|
||||
instead of specifying HTML anchors directly one can use original
|
||||
Nim symbol declarations (adding the aforementioned link brackets
|
||||
`[...]` around them).
|
||||
* To use this feature across modules, a new `importdoc` directive was added.
|
||||
Using this feature for referencing also helps to ensure that links
|
||||
(inside one module or the whole project) are not broken.
|
||||
- Added support for RST & Markdown quote blocks (blocks starting with `>`).
|
||||
- Added a popular Markdown definition lists extension.
|
||||
- Added Markdown indented code blocks (blocks indented by >= 4 spaces).
|
||||
- Added syntax for additional parameters to Markdown code blocks:
|
||||
|
||||
```nim test="nim c $1"
|
||||
...
|
||||
```
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
|
||||
- nimgrep added the option `--inContext` (and `--notInContext`), which
|
||||
allows to filter only matches with the context block containing a given pattern.
|
||||
- nimgrep: names of options containing "include/exclude" are deprecated,
|
||||
e.g. instead of `--includeFile` and `--excludeFile` we have
|
||||
`--filename` and `--notFilename` respectively.
|
||||
Also the semantics are now consistent for such positive/negative filters.
|
||||
- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice.
|
||||
@@ -58,11 +58,7 @@ _nimNumCpu(){
|
||||
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
|
||||
# OpenBSD: $(sysctl -n hw.ncpuonline)
|
||||
# windows: $NUMBER_OF_PROCESSORS ?
|
||||
if env | grep -q '^NIMCORES='; then
|
||||
echo $NIMCORES
|
||||
else
|
||||
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
|
||||
fi
|
||||
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
|
||||
}
|
||||
|
||||
_nimBuildCsourcesIfNeeded(){
|
||||
|
||||
282
compiler/ast.nim
282
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,12 +227,11 @@ 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]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # 52 flags!
|
||||
TSymFlag* = enum # 49 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
@@ -284,7 +283,7 @@ type
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
sfDiscardable, # returned value may be discarded implicitly
|
||||
sfOverridden, # proc is overridden
|
||||
sfOverriden, # proc is overridden
|
||||
sfCallsite # A flag for template symbols to tell the
|
||||
# compiler it should use line information from
|
||||
# the calling side of the macro, not from the
|
||||
@@ -304,8 +303,6 @@ type
|
||||
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
|
||||
sfSingleUsedTemp # For temporaries that we know will only be used once
|
||||
sfNoalias # 'noalias' annotation, means C's 'restrict'
|
||||
# for templates and macros, means cannot be called
|
||||
# as a lone symbol (cannot use alias syntax)
|
||||
sfEffectsDelayed # an 'effectsDelayed' parameter
|
||||
sfGeneratedType # A anonymous generic type that is generated by the compiler for
|
||||
# objects that do not have generic parameters in case one of the
|
||||
@@ -313,10 +310,6 @@ type
|
||||
#
|
||||
# This is disallowed but can cause the typechecking to go into
|
||||
# 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
|
||||
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
|
||||
sfWasGenSym # symbol was 'gensym'ed
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
@@ -342,8 +335,8 @@ const
|
||||
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
sfExperimental* = sfOverridden # module uses the .experimental switch
|
||||
sfGoto* = sfOverridden # var is used for 'goto' code generation
|
||||
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||
sfGoto* = sfOverriden # var is used for 'goto' code generation
|
||||
sfWrittenTo* = sfBorrow # param is assigned to
|
||||
# currently unimplemented
|
||||
sfBase* = sfDiscriminant
|
||||
@@ -517,13 +510,10 @@ type
|
||||
nfLastRead # this node is a last read
|
||||
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
|
||||
nfUseDefaultField # node has a default value (object constructor)
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
@@ -593,8 +583,6 @@ type
|
||||
tfIsConstructor
|
||||
tfEffectSystemWorkaround
|
||||
tfIsOutParam
|
||||
tfSendable
|
||||
tfImplicitStatic
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
@@ -630,12 +618,13 @@ type
|
||||
# file (it is loaded on demand, which may
|
||||
# mean: never)
|
||||
skPackage, # symbol is a package (used for canonicalization)
|
||||
skAlias # an alias (needs to be resolved immediately)
|
||||
TSymKinds* = set[TSymKind]
|
||||
|
||||
const
|
||||
routineKinds* = {skProc, skFunc, skMethod, skIterator,
|
||||
skConverter, skMacro, skTemplate}
|
||||
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds
|
||||
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds
|
||||
|
||||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
@@ -696,7 +685,7 @@ type
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
|
||||
mMove, mWasMoved, mDestroy, mTrace,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
@@ -717,7 +706,7 @@ type
|
||||
mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext,
|
||||
|
||||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetStrVal, mNLineInfo,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf,
|
||||
mNBindSym, mNCallSite,
|
||||
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
|
||||
@@ -807,8 +796,6 @@ type
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
@@ -829,6 +816,9 @@ type
|
||||
locOther # location is something other
|
||||
TLocFlag* = enum
|
||||
lfIndirect, # backend introduced a pointer
|
||||
lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates
|
||||
# that the symbol has been imported via 'importc: "fullname"' and
|
||||
# no format string.
|
||||
lfNoDeepCopy, # no need for a deep copy
|
||||
lfNoDecl, # do not declare it in C
|
||||
lfDynamicLib, # link symbol to dynamic library
|
||||
@@ -863,7 +853,7 @@ type
|
||||
# keep in sync with PackedLib
|
||||
kind*: TLibKind
|
||||
generated*: bool # needed for the backends:
|
||||
isOverridden*: bool
|
||||
isOverriden*: bool
|
||||
name*: Rope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
@@ -902,9 +892,6 @@ type
|
||||
typ*: PType
|
||||
name*: PIdent
|
||||
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.:
|
||||
@@ -926,9 +913,7 @@ type
|
||||
# for modules, an unique index corresponding
|
||||
# to the module's fileIdx
|
||||
# for variables a slot index for the evaluator
|
||||
offset*: int32 # offset of record field
|
||||
disamb*: int32 # disambiguation number; the basic idea is that
|
||||
# `<procname>__<module>_<disamb>`
|
||||
offset*: int # offset of record field
|
||||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
# reference to another object to save space)
|
||||
@@ -936,7 +921,7 @@ type
|
||||
cname*: string # resolved C declaration name in importc decl, e.g.:
|
||||
# proc fun() {.importc: "$1aux".} => cname = funaux
|
||||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl and virtual pragmas in the hope
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# it won't cause problems
|
||||
# for skModule the string literal to output for
|
||||
# deprecated modules.
|
||||
@@ -946,10 +931,8 @@ type
|
||||
TTypeSeq* = seq[PType]
|
||||
|
||||
TTypeAttachedOp* = enum ## as usual, order is important here
|
||||
attachedWasMoved,
|
||||
attachedDestructor,
|
||||
attachedAsgn,
|
||||
attachedDup,
|
||||
attachedSink,
|
||||
attachedTrace,
|
||||
attachedDeepCopy
|
||||
@@ -1093,8 +1076,7 @@ const
|
||||
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
|
||||
nfFromTemplate, nfDefaultRefsParam,
|
||||
nfExecuteOnReload, nfLastRead,
|
||||
nfFirstWrite, nfSkipFieldChecking,
|
||||
nfDisabledOpenSym}
|
||||
nfFirstWrite, nfUseDefaultField}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
@@ -1110,7 +1092,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}
|
||||
@@ -1134,11 +1116,11 @@ const
|
||||
|
||||
proc getPIdent*(a: PNode): PIdent {.inline.} =
|
||||
## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`.
|
||||
# xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice}
|
||||
# which may simplify code.
|
||||
case a.kind
|
||||
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
|
||||
@@ -1154,17 +1136,13 @@ type
|
||||
symId*: int32
|
||||
typeId*: int32
|
||||
sealed*: bool
|
||||
disambTable*: CountTable[PIdent]
|
||||
|
||||
const
|
||||
PackageModuleId* = -3'i32
|
||||
|
||||
proc idGeneratorFromModule*(m: PSym): IdGenerator =
|
||||
assert m.kind == skModule
|
||||
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0, disambTable: initCountTable[PIdent]())
|
||||
|
||||
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
|
||||
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
|
||||
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
|
||||
|
||||
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
|
||||
assert(not x.sealed)
|
||||
@@ -1258,11 +1236,8 @@ 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:
|
||||
@@ -1359,15 +1334,11 @@ when false:
|
||||
echo k
|
||||
echo v
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
|
||||
info: TLineInfo; options: TOptions = {}): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
assert not name.isNil
|
||||
let id = nextSymId idgen
|
||||
result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id,
|
||||
options: options, owner: owner, offset: defaultOffset,
|
||||
disamb: getOrDefault(idgen.disambTable, name).int32)
|
||||
idgen.disambTable.inc name
|
||||
options: options, owner: owner, offset: defaultOffset)
|
||||
when false:
|
||||
if id.module == 48 and id.item == 39:
|
||||
writeStackTrace()
|
||||
@@ -1460,9 +1431,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 +1439,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 +1447,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
|
||||
@@ -1565,7 +1498,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||
|
||||
const
|
||||
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
|
||||
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
|
||||
"=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
|
||||
|
||||
proc `$`*(s: PSym): string =
|
||||
if s != nil:
|
||||
@@ -1573,107 +1506,6 @@ 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 =
|
||||
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]
|
||||
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
|
||||
result = PType(kind: kind, owner: owner, size: defaultSize,
|
||||
align: defaultAlignment, itemId: id,
|
||||
@@ -1720,8 +1552,8 @@ proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
|
||||
proc exactReplica*(t: PType): PType =
|
||||
result = copyType(t, t.itemId, t.owner)
|
||||
|
||||
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
|
||||
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
|
||||
proc copySym*(s: PSym; id: ItemId): PSym =
|
||||
result = newSym(s.kind, s.name, id, s.owner, s.info, s.options)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
result.flags = s.flags
|
||||
@@ -1736,9 +1568,9 @@ proc copySym*(s: PSym; idgen: IdGenerator): PSym =
|
||||
result.bitsize = s.bitsize
|
||||
result.alignment = s.alignment
|
||||
|
||||
proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo;
|
||||
proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
|
||||
options: TOptions): PSym =
|
||||
result = newSym(s.kind, newIdent, idgen, s.owner, info, options)
|
||||
result = newSym(s.kind, newIdent, id, s.owner, info, options)
|
||||
# keep ID!
|
||||
result.ast = s.ast
|
||||
#result.id = s.id # XXX figure out what to do with the ID.
|
||||
@@ -1784,7 +1616,7 @@ 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 +1625,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
|
||||
@@ -1858,8 +1690,6 @@ proc copyNode*(src: PNode): PNode =
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
|
||||
template transitionNodeKindCommon(k: TNodeKind) =
|
||||
let obj {.inject.} = n[]
|
||||
@@ -1912,8 +1742,6 @@ template copyNodeImpl(dst, src, processSonsStmt) =
|
||||
if src == nil: return
|
||||
dst = newNode(src.kind)
|
||||
dst.info = src.info
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
dst.typ = src.typ
|
||||
dst.flags = src.flags * PersistentNodeFlags
|
||||
dst.comment = src.comment
|
||||
@@ -2062,15 +1890,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.} =
|
||||
@@ -2080,6 +1906,20 @@ proc isCompileTimeProc*(s: PSym): bool {.inline.} =
|
||||
result = s.kind == skMacro or
|
||||
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
|
||||
|
||||
proc isRunnableExamples*(n: PNode): bool =
|
||||
# Templates and generics don't perform symbol lookups.
|
||||
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
|
||||
n.kind == nkIdent and n.ident.s == "runnableExamples"
|
||||
|
||||
proc requiredParams*(s: PSym): int =
|
||||
# Returns the number of required params (without default values)
|
||||
# XXX: Perhaps we can store this in the `offset` field of the
|
||||
# symbol instead?
|
||||
for i in 1..<s.typ.len:
|
||||
if s.typ.n[i].sym.ast != nil:
|
||||
return i - 1
|
||||
return s.typ.len - 1
|
||||
|
||||
proc hasPattern*(s: PSym): bool {.inline.} =
|
||||
result = isRoutine(s) and s.ast[patternPos].kind != nkEmpty
|
||||
|
||||
@@ -2132,7 +1972,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,11 +1989,11 @@ 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
|
||||
# result does not have to be object type
|
||||
assert result.sym != nil
|
||||
|
||||
proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
assert t != nil
|
||||
@@ -2167,7 +2007,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
result = true
|
||||
|
||||
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
|
||||
@@ -2175,12 +2015,10 @@ proc skipColon*(n: PNode): PNode =
|
||||
result = n[1]
|
||||
|
||||
proc findUnresolvedStatic*(n: PNode): PNode =
|
||||
# n.typ == nil: see issue #14802
|
||||
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
|
||||
return n
|
||||
if n.typ != nil and n.typ.kind == tyTypeDesc:
|
||||
let t = skipTypes(n.typ, {tyTypeDesc})
|
||||
if t.kind == tyGenericParam and t.len == 0:
|
||||
return n
|
||||
|
||||
for son in n:
|
||||
let n = son.findUnresolvedStatic
|
||||
if n != nil: return n
|
||||
@@ -2218,12 +2056,6 @@ proc isClosureIterator*(typ: PType): bool {.inline.} =
|
||||
proc isClosure*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and typ.callConv == ccClosure
|
||||
|
||||
proc isNimcall*(s: PSym): bool {.inline.} =
|
||||
s.typ.callConv == ccNimCall
|
||||
|
||||
proc isExplicitCallConv*(s: PSym): bool {.inline.} =
|
||||
tfExplicitCallConv in s.typ.flags
|
||||
|
||||
proc isSinkParam*(s: PSym): bool {.inline.} =
|
||||
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ import strutils except addf
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
when not defined(nimHasCursor):
|
||||
{.pragma: cursor.}
|
||||
|
||||
proc hashNode*(p: RootRef): Hash
|
||||
proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
|
||||
# Convert a tree into its YAML representation; this is used by the
|
||||
@@ -330,7 +333,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
|
||||
sonsRope = rope("null")
|
||||
elif containsOrIncl(marker, n.id):
|
||||
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
|
||||
strutils.toHex(cast[int](n), sizeof(n) * 2))]
|
||||
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
|
||||
else:
|
||||
if n.len > 0:
|
||||
sonsRope = rope("[")
|
||||
@@ -890,7 +893,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,6 +1057,14 @@ 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 =
|
||||
for sym in symbols:
|
||||
if result.len > 0:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import pragmas, options, ast, trees
|
||||
|
||||
proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
optionsStack.add options
|
||||
|
||||
proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
options = optionsStack[^1]
|
||||
optionsStack.setLen(optionsStack.len-1)
|
||||
|
||||
proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions,
|
||||
n: PNode, start: int) =
|
||||
pushBackendOption(optionsStack, options)
|
||||
for i in start..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind in nkPragmaCallKinds and it.len == 2 and it[1].kind == nkIntLit:
|
||||
let sw = whichPragma(it[0])
|
||||
let opts = pragmaToOptions(sw)
|
||||
if opts != {}:
|
||||
if it[1].intVal != 0:
|
||||
options.incl opts
|
||||
else:
|
||||
options.excl opts
|
||||
|
||||
template processPopBackendOption*(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
popBackendOption(optionsStack, options)
|
||||
@@ -68,7 +68,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
|
||||
result.links[j] = h.links[Mhalf + j]
|
||||
else:
|
||||
for j in 0..<Mhalf:
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
result.vals[j] = move h.vals[Mhalf + j]
|
||||
else:
|
||||
shallowCopy(result.vals[j], h.vals[Mhalf + j])
|
||||
@@ -91,7 +91,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
|
||||
if less(key, h.keys[j]): break
|
||||
inc j
|
||||
for i in countdown(h.entries, j+1):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
h.vals[i] = move h.vals[i-1]
|
||||
else:
|
||||
shallowCopy(h.vals[i], h.vals[i-1])
|
||||
|
||||
@@ -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!
|
||||
@@ -83,10 +82,6 @@ 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:
|
||||
@@ -134,7 +129,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
var list: TLoc
|
||||
initLoc(list, 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
|
||||
@@ -142,7 +137,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
var list: TLoc
|
||||
initLoc(list, 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 +145,26 @@ 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) =
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (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})
|
||||
# but first produce the required index checks:
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c, ty)
|
||||
if prepareForMutation:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
genBoundsCheck(p, a, b, c)
|
||||
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
|
||||
@@ -283,7 +267,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
|
||||
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
|
||||
# Aliasing is preferred over stack overflows.
|
||||
# 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
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
|
||||
getSize(p.config, a.lode.typ) < 1024:
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
@@ -306,8 +290,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
|
||||
var n = if n.kind != nkHiddenAddr: n else: n[0]
|
||||
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):
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
|
||||
initLocExpr(p, n, a)
|
||||
if n.kind in {nkCharLit..nkNilLit}:
|
||||
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
|
||||
@@ -315,33 +298,18 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
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
|
||||
initLocExprSingleUse(p, n[0], a)
|
||||
# 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)]
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
@@ -423,11 +391,9 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
|
||||
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:
|
||||
@@ -507,7 +473,6 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
discard "resetLoc(p, d)"
|
||||
pl.add(addrLoc(p.config, d))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
|
||||
@@ -285,23 +285,15 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
|
||||
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
|
||||
|
||||
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
|
||||
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
|
||||
assert d.k != locNone
|
||||
# getTemp(p, d.t, d)
|
||||
|
||||
case a.t.skipTypes(abstractVar).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(a.lode):
|
||||
if needTempForOpenArray in flags:
|
||||
var tmp: TLoc
|
||||
getTemp(p, a.t, tmp)
|
||||
linefmt(p, cpsStmts, "$2 = $1; $n",
|
||||
[a.rdLoc, tmp.rdLoc])
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
|
||||
[rdLoc(d), tmp.rdLoc])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
|
||||
[rdLoc(d), a.rdLoc])
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
|
||||
[rdLoc(d), a.rdLoc])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
|
||||
[rdLoc(d), a.rdLoc])
|
||||
@@ -344,7 +336,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
of tyString:
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
genGenericAsgn(p, dest, src, flags)
|
||||
elif ({needToCopy, needToCopySinkParam} * flags == {} and src.storage != OnStatic) or canMove(p, src.lode, dest):
|
||||
elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest):
|
||||
genRefAssign(p, dest, src)
|
||||
else:
|
||||
if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
|
||||
@@ -390,7 +382,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
of tyArray:
|
||||
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcOrc, gcHooks}:
|
||||
genGenericAsgn(p, dest, src, flags)
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
@@ -400,7 +392,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
# open arrays are always on the stack - really? What if a sequence is
|
||||
# passed to an open array?
|
||||
if reifiedOpenArray(dest.lode):
|
||||
genOpenArrayConv(p, dest, src, flags)
|
||||
genOpenArrayConv(p, dest, src)
|
||||
elif containsGarbageCollectedRef(dest.t):
|
||||
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
|
||||
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
|
||||
@@ -409,7 +401,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
# bug #4799, keep the nimCopyMem for a while
|
||||
#"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);\n",
|
||||
#"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
|
||||
"$1 = $2;$n",
|
||||
[rdLoc(dest), rdLoc(src)])
|
||||
of tySet:
|
||||
@@ -458,10 +450,9 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||
[addrLoc(p.config, dest), rdLoc(src),
|
||||
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
|
||||
of tyOpenArray, tyVarargs:
|
||||
let source = addrLocOrTemp(src)
|
||||
linefmt(p, cpsStmts,
|
||||
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $2->Field1, $3);$n",
|
||||
[addrLoc(p.config, dest), source,
|
||||
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
|
||||
[addrLoc(p.config, dest), addrLocOrTemp(src),
|
||||
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
|
||||
of tySet:
|
||||
if mapSetType(p.config, ty) == ctArray:
|
||||
@@ -602,7 +593,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# skipping 'range' is correct here as we'll generate a proper range check
|
||||
# later via 'chckRange'
|
||||
let t = e.typ.skipTypes(abstractRange)
|
||||
if optOverflowCheck notin p.options or (m in {mSucc, mPred} and t.kind in {tyUInt..tyUInt64}):
|
||||
if optOverflowCheck notin p.options:
|
||||
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
putIntoDest(p, d, e, res)
|
||||
else:
|
||||
@@ -624,7 +615,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
if t.kind == tyInt64: prc64[m] else: prc[m])
|
||||
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
|
||||
else:
|
||||
let res = "($1)(($2) $3 ($4))" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
putIntoDest(p, d, e, res)
|
||||
|
||||
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
@@ -761,8 +752,23 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||
skipTypes(typ, abstractInstOwned).kind in {tyVar} and
|
||||
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
|
||||
|
||||
proc derefBlock(p: BProc, e: PNode, d: var TLoc) =
|
||||
# We transform (block: x)[] to (block: x[])
|
||||
let e0 = e[0]
|
||||
var n = shallowCopy(e0)
|
||||
n.typ = e.typ
|
||||
for i in 0 ..< e0.len - 1:
|
||||
n[i] = e0[i]
|
||||
n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1])
|
||||
expr p, n, d
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam)
|
||||
if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}:
|
||||
# bug #20107. Watch out to not deref the pointer too late.
|
||||
derefBlock(p, e, d)
|
||||
return
|
||||
|
||||
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
|
||||
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
|
||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||
@@ -830,10 +836,8 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e[0], a)
|
||||
putIntoDest(p, d, e, "&" & a.r, a.storage)
|
||||
#Message(e.info, warnUser, "HERE NEW &")
|
||||
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ):
|
||||
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ):
|
||||
expr(p, e[0], d)
|
||||
# bug #19497
|
||||
d.lode = e
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, e[0], a)
|
||||
@@ -941,17 +945,10 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
var discIndex = newRopeAppender()
|
||||
rdSetElemLoc(p.config, v, u.t, discIndex)
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let base = disc.typ.skipTypes(abstractInst+{tyRange})
|
||||
case base.kind
|
||||
of tyEnum:
|
||||
const code = "{ #raiseFieldErrorStr($1, $2); "
|
||||
let toStrProc = getToStringProc(p.module.g.graph, base)
|
||||
# XXX need to modify this logic for IC.
|
||||
# need to analyze nkFieldCheckedExpr and marks procs "used" like range checks in dce
|
||||
var toStr: TLoc
|
||||
expr(p, newSymNode(toStrProc), toStr)
|
||||
let enumStr = "$1($2)" % [rdLoc(toStr), rdLoc(v)]
|
||||
linefmt(p, cpsStmts, code, [strLit, enumStr])
|
||||
# not sure how to use `genEnumToStr` here
|
||||
if p.config.getStdlibVersion < (1, 5, 1):
|
||||
const code = "{ #raiseFieldError($1); "
|
||||
linefmt(p, cpsStmts, code, [strLit])
|
||||
else:
|
||||
const code = "{ #raiseFieldError2($1, (NI)$2); "
|
||||
linefmt(p, cpsStmts, code, [strLit, discIndex])
|
||||
@@ -962,8 +959,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
var firstLit = newRopeAppender()
|
||||
int64Literal(cast[int](first), firstLit)
|
||||
let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info)
|
||||
const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); "
|
||||
linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName])
|
||||
if p.config.getStdlibVersion < (1,5,1):
|
||||
const code = "{ #raiseFieldError($1); "
|
||||
linefmt(p, cpsStmts, code, [strLit])
|
||||
else:
|
||||
const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); "
|
||||
linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName])
|
||||
|
||||
raiseInstr(p, p.s(cpsStmts))
|
||||
linefmt p, cpsStmts, "}$n", []
|
||||
@@ -1039,8 +1040,8 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
putIntoDest(p, d, n,
|
||||
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
|
||||
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType) =
|
||||
let ty = arrTyp
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
|
||||
let ty = skipTypes(arr.t, abstractVarRange)
|
||||
case ty.kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(arr.lode):
|
||||
@@ -1426,7 +1427,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
|
||||
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
|
||||
|
||||
if a.storage == OnHeap and usesWriteBarrier(p.config):
|
||||
if canFormAcycle(p.module.g.graph, a.t):
|
||||
if canFormAcycle(a.t):
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [a.rdLoc])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [a.rdLoc])
|
||||
@@ -1463,7 +1464,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
|
||||
var call: TLoc
|
||||
initLoc(call, locExpr, dest.lode, OnHeap)
|
||||
if dest.storage == OnHeap and usesWriteBarrier(p.config):
|
||||
if canFormAcycle(p.module.g.graph, dest.t):
|
||||
if canFormAcycle(dest.t):
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [dest.rdLoc])
|
||||
@@ -1506,12 +1507,11 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
initLocExpr(p, e[1], a)
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype),
|
||||
])
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) # bug #22560
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
@@ -1561,7 +1561,6 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
var tmp: TLoc
|
||||
var r: Rope
|
||||
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc} or nfAllFieldsSet notin e.flags
|
||||
if useTemp:
|
||||
getTemp(p, t, tmp)
|
||||
r = rdLoc(tmp)
|
||||
@@ -1570,13 +1569,10 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
t = t.lastSon.skipTypes(abstractInstOwned)
|
||||
r = "(*$1)" % [r]
|
||||
gcUsage(p.config, e)
|
||||
elif needsZeroMem:
|
||||
constructLoc(p, tmp)
|
||||
else:
|
||||
genObjectInit(p, cpsStmts, t, tmp, constructObj)
|
||||
constructLoc(p, tmp)
|
||||
else:
|
||||
if needsZeroMem: resetLoc(p, d)
|
||||
else: genObjectInit(p, cpsStmts, d.t, d, if isRef: constructRefObj else: constructObj)
|
||||
resetLoc(p, d)
|
||||
r = rdLoc(d)
|
||||
discard getTypeDesc(p.module, t)
|
||||
let ty = getUniqueType(t)
|
||||
@@ -1651,7 +1647,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
return
|
||||
if d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
initLocExpr(p, n[1], a)
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
let L = toInt(lengthOrd(p.config, n[1].typ))
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
@@ -1663,6 +1658,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(L, lit)
|
||||
genNewSeqAux(p, d, lit, L == 0)
|
||||
initLocExpr(p, n[1], a)
|
||||
# bug #5007; do not produce excessive C source code:
|
||||
if L < 10:
|
||||
for i in 0..<L:
|
||||
@@ -1708,7 +1704,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
|
||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) =
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let token = $genDisplayElem(MD5Digest(hashType(dest, p.config)))
|
||||
let token = $genDisplayElem(MD5Digest(hashType(dest)))
|
||||
appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token])
|
||||
else:
|
||||
# unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
|
||||
@@ -1889,27 +1885,18 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
initLocExpr(p, a[2], b)
|
||||
initLocExpr(p, a[3], c)
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, m, b, c, skipTypes(m.t, abstractVarRange))
|
||||
genBoundsCheck(p, m, b, c)
|
||||
if op == mHigh:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1)+1)", [rdLoc(b), rdLoc(c)]))
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
if not reifiedOpenArray(a):
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
|
||||
else: unaryExpr(p, e, d, "$1Len_0")
|
||||
else:
|
||||
let isDeref = a.kind in {nkHiddenDeref, nkDerefExpr}
|
||||
if op == mHigh:
|
||||
if isDeref:
|
||||
unaryExpr(p, e, d, "($1->Field1-1)")
|
||||
else:
|
||||
unaryExpr(p, e, d, "($1.Field1-1)")
|
||||
else:
|
||||
if isDeref:
|
||||
unaryExpr(p, e, d, "$1->Field1")
|
||||
else:
|
||||
unaryExpr(p, e, d, "$1.Field1")
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)")
|
||||
else: unaryExpr(p, e, d, "$1.Field1")
|
||||
of tyCstring:
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
||||
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
||||
@@ -1934,6 +1921,10 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
|
||||
else: internalError(p.config, e.info, "genArrayLen()")
|
||||
|
||||
proc makePtrType(baseType: PType; idgen: IdGenerator): PType =
|
||||
result = newType(tyPtr, nextTypeId idgen, baseType.owner)
|
||||
addSonSkipIntLit(result, baseType, idgen)
|
||||
|
||||
proc makeAddr(n: PNode; idgen: IdGenerator): PNode =
|
||||
if n.kind == nkHiddenAddr:
|
||||
result = n
|
||||
@@ -1956,7 +1947,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
if not p.module.compileToCpp:
|
||||
const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)"
|
||||
const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
|
||||
call.r = ropecg(p.module, setLenPattern, [
|
||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
|
||||
@@ -2216,15 +2207,8 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
var lbl = p.labels.rope
|
||||
var tmp: TLoc
|
||||
tmp.r = "LOC$1.source" % [lbl]
|
||||
let destsize = getSize(p.config, destt)
|
||||
let srcsize = getSize(p.config, srct)
|
||||
|
||||
if destsize > srcsize:
|
||||
linefmt(p, cpsLocals, "union { $1 dest; $2 source; } LOC$3;$n #nimZeroMem(&LOC$3, sizeof(LOC$3));$n",
|
||||
[getTypeDesc(p.module, e.typ), getTypeDesc(p.module, e[1].typ), lbl])
|
||||
else:
|
||||
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
|
||||
[getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl])
|
||||
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
|
||||
[getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl])
|
||||
tmp.k = locExpr
|
||||
tmp.lode = lodeTyp srct
|
||||
tmp.storage = OnStack
|
||||
@@ -2355,14 +2339,14 @@ proc genWasMoved(p: BProc; n: PNode) =
|
||||
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
|
||||
discard
|
||||
else:
|
||||
initLocExpr(p, n1, a, {lfEnforceDeref})
|
||||
initLocExpr(p, n1, a)
|
||||
resetLoc(p, a)
|
||||
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
|
||||
|
||||
proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[1].skipAddr, a, {lfEnforceDeref})
|
||||
initLocExpr(p, n[1].skipAddr, a)
|
||||
if n.len == 4:
|
||||
# generated by liftdestructors:
|
||||
var src: TLoc
|
||||
@@ -2372,38 +2356,8 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, n.typ, d)
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
genAssignment(p, d, a, {})
|
||||
var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved)
|
||||
if op == nil:
|
||||
resetLoc(p, a)
|
||||
else:
|
||||
var b: TLoc
|
||||
initLocExpr(p, newSymNode(op), b)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for
|
||||
# openarrays, but it probably shouldn't?
|
||||
var s: string
|
||||
if reifiedOpenArray(a.lode):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
s = "$1->Field0, $1->Field1" % [rdLoc(a)]
|
||||
else:
|
||||
s = "$1.Field0, $1.Field1" % [rdLoc(a)]
|
||||
else:
|
||||
s = "$1, $1Len_0" % [rdLoc(a)]
|
||||
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)])
|
||||
else:
|
||||
if n[1].kind == nkSym and isSinkParam(n[1].sym):
|
||||
var tmp: TLoc
|
||||
getTemp(p, n[1].typ.skipTypes({tySink}), tmp)
|
||||
genAssignment(p, tmp, a, {needToCopySinkParam})
|
||||
genAssignment(p, d, tmp, {})
|
||||
resetLoc(p, tmp)
|
||||
else:
|
||||
genAssignment(p, d, a, {})
|
||||
resetLoc(p, a)
|
||||
genAssignment(p, d, a, {})
|
||||
resetLoc(p, a)
|
||||
|
||||
proc genDestroy(p: BProc; n: PNode) =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
@@ -2454,10 +2408,7 @@ proc genDispose(p: BProc; n: PNode) =
|
||||
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
|
||||
|
||||
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
|
||||
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
|
||||
prepareForMutation = e[1].kind == nkHiddenDeref and
|
||||
e[1].typ.skipTypes(abstractInst).kind == tyString and
|
||||
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc})
|
||||
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon)
|
||||
if d.k == locNone: getTemp(p, e.typ, d)
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
|
||||
when false:
|
||||
@@ -2564,10 +2515,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
|
||||
of mSizeOf:
|
||||
let t = e[1].typ.skipTypes({tyTypeDesc})
|
||||
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkVar)])
|
||||
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)])
|
||||
of mAlignOf:
|
||||
let t = e[1].typ.skipTypes({tyTypeDesc})
|
||||
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkVar)])
|
||||
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)])
|
||||
of mOffsetOf:
|
||||
var dotExpr: PNode
|
||||
if e[1].kind == nkDotExpr:
|
||||
@@ -2577,7 +2528,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
else:
|
||||
internalError(p.config, e.info, "unknown ast")
|
||||
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
|
||||
let tname = getTypeDesc(p.module, t, dkVar)
|
||||
let tname = getTypeDesc(p.module, t, skVar)
|
||||
let member =
|
||||
if t.kind == tyTuple:
|
||||
"Field" & rope(dotExpr[1].sym.position)
|
||||
@@ -2639,9 +2590,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e)
|
||||
expr(p, n, d)
|
||||
of mDeepCopy:
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
|
||||
if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
|
||||
localError(p.config, e.info,
|
||||
"for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
|
||||
"for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
|
||||
|
||||
var a, b: TLoc
|
||||
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
|
||||
@@ -2656,8 +2607,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mAccessTypeField: genAccessTypeField(p, e, d)
|
||||
of mSlice: genSlice(p, e, d)
|
||||
of mTrace: discard "no code to generate"
|
||||
of mEnsureMove:
|
||||
expr(p, e[1], d)
|
||||
else:
|
||||
when defined(debugMagics):
|
||||
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
|
||||
@@ -2728,30 +2677,15 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
if not handleConstExpr(p, n, d):
|
||||
let t = n.typ
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
|
||||
var tmp: TLoc
|
||||
# bug #16331
|
||||
let doesAlias = lhsDoesAlias(d.lode, n)
|
||||
let dest = if doesAlias: addr(tmp) else: addr(d)
|
||||
if doesAlias:
|
||||
getTemp(p, n.typ, tmp)
|
||||
elif d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
|
||||
if d.k == locNone: getTemp(p, t, d)
|
||||
for i in 0..<n.len:
|
||||
var it = n[i]
|
||||
if it.kind == nkExprColonExpr: it = it[1]
|
||||
initLoc(rec, locExpr, it, dest[].storage)
|
||||
rec.r = "$1.Field$2" % [rdLoc(dest[]), rope(i)]
|
||||
initLoc(rec, locExpr, it, d.storage)
|
||||
rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
|
||||
rec.flags.incl(lfEnforceDeref)
|
||||
expr(p, it, rec)
|
||||
|
||||
if doesAlias:
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {})
|
||||
|
||||
proc isConstClosure(n: PNode): bool {.inline.} =
|
||||
result = n[0].kind == nkSym and isRoutine(n[0].sym) and
|
||||
n[1].kind == nkNilLit
|
||||
@@ -2842,7 +2776,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
rdMType(p, a, nilCheck, r)
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(dest)
|
||||
let token = $genDisplayElem(MD5Digest(hashType(dest, p.config)))
|
||||
let token = $genDisplayElem(MD5Digest(hashType(dest)))
|
||||
if nilCheck != "":
|
||||
linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ",
|
||||
[nilCheck, r, checkFor, token])
|
||||
@@ -2909,7 +2843,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
# expression not found in the cache:
|
||||
inc(p.module.labels)
|
||||
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ",
|
||||
[getTypeDesc(p.module, t, dkConst), tmp])
|
||||
[getTypeDesc(p.module, t, skConst), tmp])
|
||||
genBracedInit(p, n, isConst = true, t, p.module.s[cfsData])
|
||||
p.module.s[cfsData].addf(";$n", [])
|
||||
|
||||
@@ -2936,13 +2870,13 @@ proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) =
|
||||
if not genConstSetup(p, sym): return
|
||||
assert(sym.loc.r != "", $sym.name.s & $sym.itemId)
|
||||
if m.hcrOn:
|
||||
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]);
|
||||
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]);
|
||||
m.initProc.procSec(cpsLocals).addf(
|
||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
||||
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(q, sym)])
|
||||
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)])
|
||||
else:
|
||||
let headerDecl = "extern NIM_CONST $1 $2;$n" %
|
||||
[getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]
|
||||
[getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]
|
||||
m.s[cfsData].add(headerDecl)
|
||||
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
|
||||
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
|
||||
@@ -2958,7 +2892,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
|
||||
q.s[cfsData].add data
|
||||
if q.hcrOn:
|
||||
# generate the global pointer with the real name
|
||||
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkVar), sym.loc.r])
|
||||
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, skVar), sym.loc.r])
|
||||
# register it (but ignore the boolean result of hcrRegisterGlobal)
|
||||
q.initProc.procSec(cpsLocals).addf(
|
||||
"\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
|
||||
@@ -3118,7 +3052,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
of nkObjConstr: genObjConstr(p, n, d)
|
||||
of nkCast: genCast(p, n, d)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
|
||||
of nkAddr, nkHiddenAddr: genAddr(p, n, d)
|
||||
of nkHiddenAddr:
|
||||
if n[0].kind == nkDerefExpr:
|
||||
# addr ( deref ( x )) --> x
|
||||
var x = n[0][0]
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
x.typ = n.typ
|
||||
expr(p, x, d)
|
||||
return
|
||||
genAddr(p, n, d)
|
||||
of nkAddr: genAddr(p, n, d)
|
||||
of nkBracketExpr: genBracketExpr(p, n, d)
|
||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
|
||||
of nkDotExpr: genRecordField(p, n, d)
|
||||
@@ -3257,8 +3200,6 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) =
|
||||
result.add "}"
|
||||
of tyTuple:
|
||||
result.add "{"
|
||||
if p.vccAndC and t.len == 0:
|
||||
result.add "0"
|
||||
for i in 0..<t.len:
|
||||
if i > 0: result.add ", "
|
||||
getDefaultValue(p, t[i], info, result)
|
||||
@@ -3303,16 +3244,11 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
|
||||
isConst: bool, info: TLineInfo) =
|
||||
case obj.kind
|
||||
of nkRecList:
|
||||
let isUnion = tfUnion in t.flags
|
||||
for it in obj.sons:
|
||||
getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
|
||||
if isUnion:
|
||||
# generate only 1 field for default value of union
|
||||
return
|
||||
of nkRecCase:
|
||||
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
|
||||
var res = ""
|
||||
if count > 0: res.add ", "
|
||||
if count > 0: result.add ", "
|
||||
var branch = Zero
|
||||
if constOrNil != nil:
|
||||
## find kind value, default is zero if not specified
|
||||
@@ -3326,21 +3262,18 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
|
||||
break
|
||||
|
||||
let selectedBranch = caseObjDefaultBranch(obj, branch)
|
||||
res.add "{"
|
||||
result.add "{"
|
||||
var countB = 0
|
||||
let b = lastSon(obj[selectedBranch])
|
||||
# designated initilization is the only way to init non first element of unions
|
||||
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
|
||||
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
|
||||
res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
|
||||
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
|
||||
res.add "}"
|
||||
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
|
||||
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
|
||||
result.add "}"
|
||||
elif b.kind == nkSym:
|
||||
res.add "." & mangleRecFieldName(p.module, b.sym) & " = "
|
||||
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
|
||||
else:
|
||||
return
|
||||
result.add res
|
||||
result.add "." & mangleRecFieldName(p.module, b.sym) & " = "
|
||||
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
|
||||
result.add "}"
|
||||
|
||||
of nkSym:
|
||||
@@ -3396,8 +3329,6 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Rope) =
|
||||
|
||||
proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) =
|
||||
result.add "{"
|
||||
if p.vccAndC and n.len == 0 and n.typ.kind == tyArray:
|
||||
getDefaultValue(p, n.typ[1], n.info, result)
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if i > 0: result.add ",\n"
|
||||
@@ -3407,8 +3338,6 @@ proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) =
|
||||
|
||||
proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Rope) =
|
||||
result.add "{"
|
||||
if p.vccAndC and n.len == 0:
|
||||
result.add "0"
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if i > 0: result.add ",\n"
|
||||
@@ -3442,19 +3371,18 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope)
|
||||
|
||||
proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) =
|
||||
let base = t.skipTypes(abstractInst)[0]
|
||||
var data = rope""
|
||||
if n.len > 0:
|
||||
data.add(", {")
|
||||
for i in 0..<n.len:
|
||||
if i > 0: data.addf(",$n", [])
|
||||
genBracedInit(p, n[i], isConst, base, data)
|
||||
data.add("}")
|
||||
var data = rope"{"
|
||||
for i in 0..<n.len:
|
||||
if i > 0: data.addf(",$n", [])
|
||||
genBracedInit(p, n[i], isConst, base, data)
|
||||
data.add("}")
|
||||
|
||||
let payload = getTempName(p.module)
|
||||
|
||||
appcg(p.module, cfsStrData,
|
||||
"static $5 struct {$n" &
|
||||
" NI cap; $1 data[$2];$n" &
|
||||
"} $3 = {$2 | NIM_STRLIT_FLAG$4};$n", [
|
||||
"} $3 = {$2 | NIM_STRLIT_FLAG, $4};$n", [
|
||||
getTypeDesc(p.module, base), n.len, payload, data,
|
||||
if isConst: "const" else: ""])
|
||||
result.add "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
|
||||
|
||||
@@ -83,7 +83,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])
|
||||
@@ -97,7 +97,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
else:
|
||||
doAssert false, "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}:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#
|
||||
|
||||
# included from cgen.nim
|
||||
|
||||
const
|
||||
RangeExpandLimit = 256 # do not generate ranges
|
||||
# over 'RangeExpandLimit' elements
|
||||
@@ -18,7 +19,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)
|
||||
@@ -35,9 +36,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
if n.kind == nkEmpty:
|
||||
result = false
|
||||
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
|
||||
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
|
||||
result = true
|
||||
elif isInvalidReturnType(conf, n[0].typ, true):
|
||||
if isInvalidReturnType(conf, n[0].typ, true):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
@@ -290,28 +289,11 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
|
||||
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
|
||||
genBracedInit(p, value, isConst = false, v.typ, result)
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
|
||||
var params = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
let typ = skipTypes(value[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
assert(typ.len == typ.n.len)
|
||||
genOtherArg(p, value, i, typ, params, argsCounter)
|
||||
if params.len == 0:
|
||||
decl = runtimeFormat("$#;\n", [decl])
|
||||
else:
|
||||
decl = runtimeFormat("$#($#);\n", [decl, params])
|
||||
|
||||
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if sfGoto in v.flags:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
genGotoVar(p, value)
|
||||
return
|
||||
let imm = isAssignedImmediately(p.config, value)
|
||||
let isCppCtorCall = p.module.compileToCpp and imm and
|
||||
value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
|
||||
var targetProc = p
|
||||
var valueAsRope = ""
|
||||
potentialValueInit(p, v, value, valueAsRope)
|
||||
@@ -323,11 +305,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if sfPure in v.flags:
|
||||
# v.owner.kind != skModule:
|
||||
targetProc = p.module.preInitProc
|
||||
if isCppCtorCall and not containsHiddenPointer(v.typ):
|
||||
callGlobalVarCppCtor(targetProc, v, vn, value)
|
||||
else:
|
||||
assignGlobalVar(targetProc, vn, valueAsRope)
|
||||
|
||||
assignGlobalVar(targetProc, vn, valueAsRope)
|
||||
# XXX: be careful here.
|
||||
# Global variables should not be zeromem-ed within loops
|
||||
# (see bug #20).
|
||||
@@ -336,6 +314,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
# global variables will be initialized to zero.
|
||||
if valueAsRope.len == 0:
|
||||
var loc = v.loc
|
||||
|
||||
# When the native TLS is unavailable, a global thread-local variable needs
|
||||
# one more layer of indirection in order to access the TLS block.
|
||||
# Only do this for complex types that may need a call to `objectInit`
|
||||
@@ -349,21 +328,31 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
genVarPrototype(p.module.g.generatedHeader, vn)
|
||||
registerTraverseProc(p, v)
|
||||
else:
|
||||
let imm = isAssignedImmediately(p.config, value)
|
||||
if imm and p.module.compileToCpp and p.splitDecls == 0 and
|
||||
not containsHiddenPointer(v.typ) and
|
||||
nimErrorFlagAccessed notin p.flags:
|
||||
not containsHiddenPointer(v.typ):
|
||||
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
|
||||
# parameterless constructor followed by an assignment operator. So we
|
||||
# generate better code here: 'Foo f = x;'
|
||||
genLineDir(p, vn)
|
||||
var decl = localVarDecl(p, vn)
|
||||
let decl = localVarDecl(p, vn)
|
||||
var tmp: TLoc
|
||||
if isCppCtorCall:
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
line(p, cpsStmts, decl)
|
||||
if value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
sfConstructor in value[0].sym.flags:
|
||||
var params = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
let typ = skipTypes(value[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
assert(typ.len == typ.n.len)
|
||||
genOtherArg(p, value, i, typ, params, argsCounter)
|
||||
if params.len == 0:
|
||||
lineF(p, cpsStmts, "$#;$n", [decl])
|
||||
else:
|
||||
lineF(p, cpsStmts, "$#($#);$n", [decl, params])
|
||||
else:
|
||||
initLocExprSingleUse(p, value, tmp)
|
||||
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
|
||||
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
|
||||
return
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, imm)
|
||||
@@ -390,8 +379,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
startBlock(targetProc)
|
||||
if value.kind != nkEmpty and valueAsRope.len == 0:
|
||||
genLineDir(targetProc, vn)
|
||||
if not isCppCtorCall:
|
||||
loadInto(targetProc, vn, value, v.loc)
|
||||
loadInto(targetProc, vn, value, v.loc)
|
||||
if forHcr:
|
||||
endBlock(targetProc)
|
||||
|
||||
@@ -626,7 +614,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
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))
|
||||
appcg(p, cpsStmts, ";$n", [])
|
||||
lineF(p, cpsStmts, ";$n", [])
|
||||
genStmts(p, loopBody)
|
||||
|
||||
if optProfiler in p.options:
|
||||
@@ -666,7 +654,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t[1]
|
||||
assert(call.len == 4 or call.len == 5)
|
||||
assert(call.len in {4, 5})
|
||||
initLocExpr(p, call[1], rangeA)
|
||||
initLocExpr(p, call[2], rangeB)
|
||||
|
||||
@@ -779,7 +767,11 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
finallyActions(p)
|
||||
genLineDir(p, t)
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n", [])
|
||||
# reraise the last exception:
|
||||
if p.config.exc == excCpp:
|
||||
line(p, cpsStmts, "throw;\n")
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n", [])
|
||||
raiseInstr(p, p.s(cpsStmts))
|
||||
|
||||
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
@@ -971,11 +963,8 @@ 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)
|
||||
|
||||
@@ -1008,7 +997,7 @@ proc genRestoreFrameAfterException(p: BProc) =
|
||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
#[ code to generate:
|
||||
|
||||
std::exception_ptr error;
|
||||
std::exception_ptr error = nullptr;
|
||||
try {
|
||||
body;
|
||||
} catch (Exception e) {
|
||||
@@ -1039,7 +1028,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
inc(p.labels, 2)
|
||||
let etmp = p.labels
|
||||
|
||||
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
|
||||
p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp]))
|
||||
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
p.nestedTryStmts.add((fin, false, 0.Natural))
|
||||
@@ -1073,6 +1062,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
if hasIf: lineF(p, cpsStmts, "else ", [])
|
||||
startBlock(p)
|
||||
# we handled the error:
|
||||
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||
expr(p, t[i][0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
endBlock(p)
|
||||
@@ -1092,7 +1082,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(typeNode.typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1135,7 +1125,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
|
||||
if t[i].len == 1:
|
||||
# general except section:
|
||||
startBlock(p, "catch (...) {$n", [])
|
||||
startBlock(p, "catch (...) {", [])
|
||||
genExceptBranchBody(t[i][0])
|
||||
endBlock(p)
|
||||
catchAllPresent = true
|
||||
@@ -1161,7 +1151,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# general finally block:
|
||||
if t.len > 0 and t[^1].kind == nkFinally:
|
||||
if not catchAllPresent:
|
||||
startBlock(p, "catch (...) {$n", [])
|
||||
startBlock(p, "catch (...) {", [])
|
||||
genRestoreFrameAfterException(p)
|
||||
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||
endBlock(p)
|
||||
@@ -1311,8 +1301,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
|
||||
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1457,7 +1446,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1549,7 +1538,7 @@ proc determineSection(n: PNode): TCFileSection =
|
||||
result = cfsProcHeaders
|
||||
if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
|
||||
let sec = n[0].strVal
|
||||
if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND
|
||||
if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
|
||||
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
|
||||
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
|
||||
|
||||
@@ -1566,14 +1555,9 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
line(p, cpsStmts, s)
|
||||
|
||||
proc genPragma(p: BProc, n: PNode) =
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
for it in n.sons:
|
||||
case whichPragma(it)
|
||||
of wEmit: genEmit(p, it)
|
||||
of wPush:
|
||||
processPushBackendOption(p.optionsStack, p.options, n, i+1)
|
||||
of wPop:
|
||||
processPopBackendOption(p.optionsStack, p.options)
|
||||
else: discard
|
||||
|
||||
|
||||
@@ -1591,8 +1575,6 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
|
||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||
lit])
|
||||
if p.config.exc == excGoto:
|
||||
raiseExit(p)
|
||||
|
||||
when false:
|
||||
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
|
||||
@@ -1617,7 +1599,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
initLocExpr(p, e[0], a)
|
||||
getTemp(p, a.t, tmp)
|
||||
expr(p, e[1], tmp)
|
||||
if p.inUncheckedAssignSection == 0:
|
||||
if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0:
|
||||
let field = dotExpr[1].sym
|
||||
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
|
||||
message(p.config, e.info, warnCaseTransition)
|
||||
@@ -1634,11 +1616,10 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
let le = e[0]
|
||||
let ri = e[1]
|
||||
var a: TLoc
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
|
||||
initLoc(a, locNone, le, OnUnknown)
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
a.flags.incl(lfPrepareForMutation)
|
||||
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
|
||||
expr(p, le, a)
|
||||
a.flags.excl(lfPrepareForMutation)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,6 @@ import
|
||||
ast, types, hashes, strutils, msgs, wordrecg,
|
||||
platform, trees, options, cgendata
|
||||
|
||||
import std/[hashes, strutils, formatfloat]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -55,7 +53,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
|
||||
a = a + (a shl 3)
|
||||
a = a xor (a shr 11)
|
||||
a = a + (a shl 15)
|
||||
result = cast[Hash](uint(a))
|
||||
result = cast[Hash](a)
|
||||
|
||||
template getUniqueType*(key: PType): PType = key
|
||||
|
||||
@@ -124,19 +122,13 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
var pt = skipTypes(s.typ, typedescInst)
|
||||
assert skResult != s.kind
|
||||
|
||||
#note precedence: params override types
|
||||
if optByRef in s.options: return true
|
||||
elif sfByCopy in s.flags: return false
|
||||
elif tfByRef in pt.flags: return true
|
||||
if tfByRef in pt.flags: return true
|
||||
elif tfByCopy in pt.flags: return false
|
||||
case pt.kind
|
||||
of tyObject:
|
||||
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
|
||||
# forwarded objects are *always* passed by pointers for consistency!
|
||||
result = true
|
||||
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
# bug #23354:
|
||||
result = false
|
||||
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
|
||||
result = true # requested anyway
|
||||
elif (tfFinal in pt.flags) and (pt[0] == nil):
|
||||
@@ -153,64 +145,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
|
||||
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
import
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
||||
injectdestructors, astmsgs, modulepaths, backendpragmas
|
||||
|
||||
import pipelineutils
|
||||
injectdestructors, astmsgs, modulepaths
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -30,12 +28,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 +59,12 @@ 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 = {}) =
|
||||
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
|
||||
result.k = k
|
||||
result.storage = s
|
||||
result.lode = lode
|
||||
result.r = ""
|
||||
result.flags = flags
|
||||
result.flags = {}
|
||||
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
|
||||
# fills the loc if it is not already initialized
|
||||
@@ -222,20 +214,20 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
elif frmt[i] == '#' and frmt[i+1] == '#':
|
||||
inc(i, 2)
|
||||
strLit.add("#")
|
||||
else:
|
||||
strLit.add(frmt[i])
|
||||
inc(i)
|
||||
|
||||
var start = i
|
||||
while i < frmt.len:
|
||||
if frmt[i] != '$' and frmt[i] != '#': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
strLit.add(substr(frmt, start, i - 1))
|
||||
|
||||
flushStrLit()
|
||||
result.add newCall(ident"rope", resVar)
|
||||
|
||||
proc addIndent(p: BProc; result: var Rope) =
|
||||
var i = result.len
|
||||
let newLen = i + p.blocks.len
|
||||
result.setLen newLen
|
||||
while i < newLen:
|
||||
result[i] = '\t'
|
||||
inc i
|
||||
for i in 0..<p.blocks.len:
|
||||
result.add "\t".rope
|
||||
|
||||
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: untyped) =
|
||||
@@ -272,28 +264,14 @@ 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"))
|
||||
|
||||
proc genCLineDir(r: var Rope, fileIdx: FileIndex, 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"))
|
||||
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
|
||||
@@ -302,25 +280,17 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
p.lastLineInfo.fileIndex = info.fileIndex
|
||||
result = true
|
||||
|
||||
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)
|
||||
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
let line = t.info.safeLineNm
|
||||
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
|
||||
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.config)
|
||||
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 freshLineInfo(p, t.info):
|
||||
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
|
||||
[line, quotedFilename(p.config, t.info)])
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
|
||||
@@ -379,19 +349,19 @@ template mapTypeChooser(n: PNode): TSymKind =
|
||||
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||
|
||||
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
|
||||
result.add "(&" & a.r & ")"
|
||||
else:
|
||||
result.add a.r
|
||||
|
||||
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
|
||||
result = "(&" & a.r & ")"
|
||||
else:
|
||||
result = a.r
|
||||
|
||||
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
|
||||
p.module.compileToCpp:
|
||||
result = "(&" & a.r & ")"
|
||||
else:
|
||||
@@ -406,8 +376,6 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||
type
|
||||
TAssignmentFlag = enum
|
||||
needToCopy
|
||||
needToCopySinkParam
|
||||
needTempForOpenArray
|
||||
TAssignmentFlags = set[TAssignmentFlag]
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
|
||||
@@ -445,7 +413,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
|
||||
linefmt(p, cpsStmts,
|
||||
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
|
||||
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, descKindFromSymKind mapTypeChooser(a))])
|
||||
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
|
||||
else:
|
||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
|
||||
genAssignment(p, a, tmp, {})
|
||||
@@ -507,7 +475,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
# so we use getTypeDesc here rather than rdLoc(loc)
|
||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
[addrLoc(p.config, loc),
|
||||
getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))])
|
||||
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
|
||||
# XXX: We can be extra clever here and call memset only
|
||||
# on the bytes following the m_type field?
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||
@@ -524,14 +492,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
# avoid it:
|
||||
if not isOrHasImportedCppType(typ):
|
||||
if not isImportedCppType(typ):
|
||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
|
||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||
|
||||
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
@@ -549,10 +517,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
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])
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
@@ -570,7 +535,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
@@ -593,11 +558,8 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
||||
|
||||
genCLineDir(result, p, n.info, p.config)
|
||||
|
||||
result.add getTypeDesc(p.module, s.typ, dkVar)
|
||||
if sfCodegenDecl notin s.flags:
|
||||
result.add getTypeDesc(p.module, s.typ, skVar)
|
||||
if s.constraint.isNil:
|
||||
if sfRegister in s.flags: result.add(" register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# decl.add(" GC_GUARD")
|
||||
@@ -612,8 +574,8 @@ proc assignLocalVar(p: BProc, n: PNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let nl = if optLineDir in p.config.options: "" else: "\n"
|
||||
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
|
||||
let nl = if optLineDir in p.config.options: "" else: "\L"
|
||||
let decl = localVarDecl(p, n) & ";" & nl
|
||||
line(p, cpsLocals, decl)
|
||||
|
||||
include ccgthreadvars
|
||||
@@ -626,40 +588,6 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
|
||||
# and s.owner.kind == skModule # owner isn't always a module (global pragma on local var)
|
||||
# and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used
|
||||
|
||||
proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
|
||||
let s = n.sym
|
||||
if sfCodegenDecl notin s.flags:
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
||||
if p.hcrOn: decl.add("static ")
|
||||
elif sfImportc in s.flags: decl.add("extern ")
|
||||
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
|
||||
else: decl.add("N_LIB_PRIVATE ")
|
||||
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
|
||||
decl.add(td)
|
||||
if p.hcrOn: decl.add("*")
|
||||
if sfRegister in s.flags: decl.add(" register")
|
||||
if sfVolatile in s.flags: decl.add(" volatile")
|
||||
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
|
||||
else:
|
||||
if value != "":
|
||||
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
|
||||
else:
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
|
||||
|
||||
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
|
||||
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
|
||||
genGlobalVarDecl(p, vn, td, "", decl)
|
||||
decl.add " " & $s.loc.r
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
p.module.s[cfsVars].add decl
|
||||
|
||||
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
@@ -685,30 +613,29 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
internalError(p.config, n.info, ".threadvar variables cannot have a value")
|
||||
else:
|
||||
var decl: Rope = ""
|
||||
let td = getTypeDesc(p.module, s.loc.t, dkVar)
|
||||
genGlobalVarDecl(p, n, td, value, decl)
|
||||
var td = getTypeDesc(p.module, s.loc.t, skVar)
|
||||
if s.constraint.isNil:
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
||||
if p.hcrOn: decl.add("static ")
|
||||
elif sfImportc in s.flags: decl.add("extern ")
|
||||
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
|
||||
else: decl.add("N_LIB_PRIVATE ")
|
||||
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
|
||||
decl.add(td)
|
||||
if p.hcrOn: decl.add("*")
|
||||
if sfRegister in s.flags: decl.add(" register")
|
||||
if sfVolatile in s.flags: decl.add(" volatile")
|
||||
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
|
||||
if value != "":
|
||||
if p.module.compileToCpp and value.startsWith "{{}":
|
||||
# TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in
|
||||
# either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when
|
||||
# explicit constructors are around** due to overload resolution rules in place [^0][^1][^2]
|
||||
# *Workaround* here: have C++'s static initialization mechanism do the default init work,
|
||||
# for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness
|
||||
# (so far) *and yet* trying to achieve default initialization.
|
||||
# Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal;
|
||||
# need to figure out a better way, possibly by keeping around more data about the
|
||||
# imported objects' contructors?
|
||||
#
|
||||
# [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization
|
||||
# [^1]: https://cplusplus.github.io/CWG/issues/1518.html
|
||||
# [^2]: https://eel.is/c++draft/over.match.ctor
|
||||
decl.addf(" $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl.addf(" $1 = $2;$n", [s.loc.r, value])
|
||||
decl.addf(" $1 = $2;$n", [s.loc.r, value])
|
||||
else:
|
||||
decl.addf(" $1;$n", [s.loc.r])
|
||||
|
||||
else:
|
||||
if value != "":
|
||||
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
|
||||
else:
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
p.module.s[cfsVars].add(decl)
|
||||
if p.withinLoop > 0 and value == "":
|
||||
# fixes tests/run/tzeroarray:
|
||||
@@ -729,7 +656,7 @@ proc getLabel(p: BProc): TLabel =
|
||||
result = "LA" & rope(p.labels) & "_"
|
||||
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
p.s(cpsStmts).add("$1: ;$n" % [labl])
|
||||
lineF(p, cpsStmts, "$1: ;$n", [labl])
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
@@ -742,8 +669,8 @@ 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, result: var TLoc) =
|
||||
initLoc(result, locNone, e, OnUnknown)
|
||||
expr(p, e, result)
|
||||
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||
@@ -771,12 +698,8 @@ $1define nimfr_(proc, file) \
|
||||
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
|
||||
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
|
||||
|
||||
$1define nimln_(n) \
|
||||
FR_.line = n;
|
||||
|
||||
$1define nimlf_(n, file) \
|
||||
$1define nimln_(n, file) \
|
||||
FR_.line = n; FR_.filename = file;
|
||||
|
||||
"""
|
||||
if p.module.s[cfsFrameDefines].len == 0:
|
||||
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
|
||||
@@ -842,7 +765,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
initLoc(dest, locTemp, lib.path, OnStack)
|
||||
dest.r = getTempName(m)
|
||||
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
|
||||
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
|
||||
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
|
||||
expr(p, lib.path, dest)
|
||||
|
||||
m.s[cfsVars].add(p.s(cpsLocals))
|
||||
@@ -882,7 +805,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
params.add(rdLoc(a))
|
||||
params.add(", ")
|
||||
let load = "\t$1 = ($2) ($3$4));$n" %
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)]
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last[1]
|
||||
internalAssert(m.config, last.kind == nkStrLit)
|
||||
@@ -896,8 +819,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
else:
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||
|
||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
@@ -909,9 +832,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
inc(m.labels, 2)
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2* $1;$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||
|
||||
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
sym.loc.r = mangleDynLibProc(sym)
|
||||
@@ -942,9 +865,7 @@ proc cgsymValue(m: BModule, name: string): Rope =
|
||||
result.addActualSuffixForHCR(m.module, sym)
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
var nimbase = m.config.nimbasePattern
|
||||
if nimbase == "": nimbase = "nimbase.h"
|
||||
m.s[cfsHeaders].addf("\L#include \"$1\"\L", [nimbase])
|
||||
m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
|
||||
|
||||
for it in m.headerFiles:
|
||||
if it[0] == '#':
|
||||
@@ -993,19 +914,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,6 +926,10 @@ 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 =
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
@@ -1032,7 +949,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 +964,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 +976,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 +992,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 +1018,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 +1045,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])
|
||||
@@ -1163,7 +1062,7 @@ proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
|
||||
proc genProcBody(p: BProc; procBody: PNode) =
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}:
|
||||
p.flags.incl nimErrorFlagDeclared
|
||||
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
|
||||
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
|
||||
@@ -1171,13 +1070,10 @@ proc genProcBody(p: BProc; procBody: PNode) =
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
|
||||
proc genProcAux*(m: BModule, prc: PSym) =
|
||||
proc genProcAux(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = newRopeAppender()
|
||||
if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
|
||||
genMemberProcHeader(m, prc, header)
|
||||
else:
|
||||
genProcHeader(m, prc, header)
|
||||
genProcHeader(m, prc, header)
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
@@ -1185,15 +1081,12 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
if sfInjectDestructors in prc.flags:
|
||||
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
|
||||
|
||||
let tmpInfo = prc.info
|
||||
discard freshLineInfo(p, prc.info)
|
||||
|
||||
if sfPure notin prc.flags and prc.typ[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast[resultPos]
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
|
||||
if not isInvalidReturnType(m.config, prc.typ):
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
@@ -1204,16 +1097,8 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
# 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)
|
||||
else:
|
||||
fillResult(p.config, resNode, prc.typ)
|
||||
assignParam(p, res, prc.typ[0])
|
||||
@@ -1224,7 +1109,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:
|
||||
@@ -1238,8 +1123,6 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
closureSetup(p, prc)
|
||||
genProcBody(p, procBody)
|
||||
|
||||
prc.info = tmpInfo
|
||||
|
||||
var generatedProc: Rope
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if isNoReturn(p.module, prc):
|
||||
@@ -1291,7 +1174,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: return
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if sym.itemId.module != m.module.position and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
@@ -1327,20 +1210,6 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
if lfNoDecl in prc.loc.flags:
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
# register the procedure even though it is in a different dynamic library and will not be
|
||||
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
|
||||
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
|
||||
if isReloadable(q, prc):
|
||||
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
|
||||
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
|
||||
else:
|
||||
symInDynamicLibPartial(m, prc)
|
||||
elif prc.typ.callConv == ccInline:
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
# This also means that a check with ``q.declaredThings`` is wrong, we need
|
||||
@@ -1359,6 +1228,20 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
# prc.loc.r = mangleName(m, prc)
|
||||
genProcPrototype(m, prc)
|
||||
genProcAux(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
# register the procedure even though it is in a different dynamic library and will not be
|
||||
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
|
||||
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
|
||||
if isReloadable(q, prc):
|
||||
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
|
||||
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
|
||||
else:
|
||||
symInDynamicLibPartial(m, prc)
|
||||
elif sfImportc notin prc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
@@ -1422,14 +1305,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
assert(sym.loc.r != "")
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sfThread in sym.flags:
|
||||
declareThreadVar(m, sym, true)
|
||||
else:
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
|
||||
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
|
||||
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
|
||||
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar))
|
||||
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
|
||||
if m.hcrOn: m.s[cfsVars].add("*")
|
||||
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
|
||||
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
|
||||
@@ -1438,7 +1321,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
|
||||
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
|
||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
||||
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
|
||||
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
|
||||
|
||||
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
|
||||
result.addf("#define NIM_INTBITS $1\L", [
|
||||
@@ -1514,23 +1397,20 @@ proc genMainProc(m: BModule) =
|
||||
[handle, strLit])
|
||||
|
||||
preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
|
||||
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
|
||||
else:
|
||||
preMainCode.add("\tvoid* rtl_handle;\L")
|
||||
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
|
||||
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
|
||||
preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix])
|
||||
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
|
||||
preMainCode.add("\t(*inner)();\L")
|
||||
preMainCode.add("\tvoid* rtl_handle;\L")
|
||||
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
|
||||
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
|
||||
preMainCode.add("\tinner = PreMain;\L")
|
||||
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
|
||||
preMainCode.add("\t(*inner)();\L")
|
||||
else:
|
||||
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
|
||||
|
||||
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"
|
||||
posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L"
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L"
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L"
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L"
|
||||
|
||||
const
|
||||
# The use of a volatile function pointer to call Pre/NimMainInner
|
||||
@@ -1543,15 +1423,15 @@ proc genMainProc(m: BModule) =
|
||||
"}$N$N" &
|
||||
"$4" &
|
||||
"N_LIB_PRIVATE void $3PreMain(void) {$N" &
|
||||
"##if $5$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\t##if $5$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tinner = $3PreMainInner;$N" &
|
||||
"$1" &
|
||||
"\t(*inner)();$N" &
|
||||
"##else$N" &
|
||||
"\t##else$N" &
|
||||
"$1" &
|
||||
"\t$3PreMainInner();$N" &
|
||||
"##endif$N" &
|
||||
"\t##endif$N" &
|
||||
"}$N$N"
|
||||
|
||||
MainProcs =
|
||||
@@ -1566,17 +1446,17 @@ proc genMainProc(m: BModule) =
|
||||
|
||||
NimMainProc =
|
||||
"N_CDECL(void, $5NimMain)(void) {$N" &
|
||||
"##if $6$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\t##if $6$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"$4" &
|
||||
"\tinner = $5NimMainInner;$N" &
|
||||
"$2" &
|
||||
"\t(*inner)();$N" &
|
||||
"##else$N" &
|
||||
"\t##else$N" &
|
||||
"$4" &
|
||||
"$2" &
|
||||
"\t$5NimMainInner();$N" &
|
||||
"##endif$N" &
|
||||
"\t##endif$N" &
|
||||
"}$N$N"
|
||||
|
||||
NimMainBody = NimMainInner & NimMainProc
|
||||
@@ -1607,7 +1487,7 @@ proc genMainProc(m: BModule) =
|
||||
WinCDllMain =
|
||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
|
||||
" LPVOID lpvReserved) {$N" &
|
||||
"\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" &
|
||||
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
|
||||
"\treturn 1;$N}$N$N"
|
||||
|
||||
PosixNimDllMain = WinNimDllMain
|
||||
@@ -1641,11 +1521,11 @@ proc genMainProc(m: BModule) =
|
||||
m.includeHeader("<libc/component.h>")
|
||||
|
||||
let initStackBottomCall =
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
|
||||
inc(m.labels)
|
||||
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0"
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile])
|
||||
|
||||
if m.config.target.targetOS == osWindows and
|
||||
@@ -1744,7 +1624,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
hcrModuleMeta.addf("\t\"\"};$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
|
||||
[($sigHash(m.module, m.config)).rope])
|
||||
[($sigHash(m.module)).rope])
|
||||
if sfMainModule in m.module.flags:
|
||||
g.mainModProcs.add(hcrModuleMeta)
|
||||
g.mainModProcs.addf("static void* hcr_handle;$N", [])
|
||||
@@ -1785,7 +1665,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
if sfSystemModule in m.module.flags:
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
|
||||
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
@@ -1810,7 +1690,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:
|
||||
@@ -1836,10 +1716,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
prc.typ.sym = nil
|
||||
|
||||
if not containsOrIncl(m.declaredThings, prc.id):
|
||||
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
|
||||
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
|
||||
|
||||
result = "\t$1 = ($2) $3($4, $5);$n" %
|
||||
[tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
||||
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
@@ -1851,7 +1731,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])
|
||||
@@ -1915,15 +1795,12 @@ proc genInitCode(m: BModule) =
|
||||
if beforeRetNeeded in m.initProc.flags:
|
||||
prc.add("\tBeforeRet_: ;\n")
|
||||
|
||||
if m.config.exc == excGoto:
|
||||
if sfMainModule in m.module.flags and m.config.exc == excGoto:
|
||||
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
|
||||
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
|
||||
|
||||
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
||||
prc.add(deinitFrame(m.initProc))
|
||||
elif m.config.exc == excGoto:
|
||||
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
|
||||
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
|
||||
|
||||
prc.addf("}$N", [])
|
||||
|
||||
@@ -1966,40 +1843,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
|
||||
|
||||
@@ -2012,6 +1855,8 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
openNamespaceNim(m.config.cppCustomNamespace, result)
|
||||
if m.s[cfsFrameDefines].len > 0:
|
||||
result.add(m.s[cfsFrameDefines])
|
||||
else:
|
||||
result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n")
|
||||
|
||||
for i in cfsForwardTypes..cfsProcs:
|
||||
if m.s[i].len > 0:
|
||||
@@ -2028,17 +1873,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
|
||||
@@ -2092,7 +1929,10 @@ template injectG() {.dirty.} =
|
||||
graph.backend = newModuleList(graph)
|
||||
let g = BModuleList(graph.backend)
|
||||
|
||||
proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
injectG()
|
||||
result = newModule(g, module, graph.config)
|
||||
result.idgen = idgen
|
||||
@@ -2160,7 +2000,7 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) =
|
||||
|
||||
proc genTopLevelStmt*(m: BModule; n: PNode) =
|
||||
## Also called from `ic/cbackend.nim`.
|
||||
if pipelineutils.skipCodegen(m.config, n): return
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
m.initProc.options = initProcOptions(m)
|
||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
# XXX replicate this logic!
|
||||
@@ -2173,6 +2013,12 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
|
||||
else:
|
||||
genProcBody(m.initProc, transformedN)
|
||||
|
||||
proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b != nil:
|
||||
var m = BModule(b)
|
||||
genTopLevelStmt(m, n)
|
||||
|
||||
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
if optForceFullMake notin m.config.globalOptions:
|
||||
if not moduleHasChanged(m.g.graph, m.module):
|
||||
@@ -2238,7 +2084,7 @@ proc updateCachedModule(m: BModule) =
|
||||
cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
## Also called from IC.
|
||||
if sfMainModule in m.module.flags:
|
||||
# phase ordering problem here: We need to announce this
|
||||
@@ -2249,7 +2095,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
|
||||
for i in countdown(high(graph.globalDestructors), 0):
|
||||
n.add graph.globalDestructors[i]
|
||||
if pipelineutils.skipCodegen(m.config, n): return
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
if moduleHasChanged(graph, m.module):
|
||||
# if the module is cached, we don't regenerate the main proc
|
||||
# nor the dispatchers? But if the dispatchers changed?
|
||||
@@ -2260,10 +2106,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
|
||||
if m.hcrOn:
|
||||
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
|
||||
let sym = magicsys.getCompilerProc(m.g.graph, "programResult")
|
||||
# ignore when not available, could be a module imported early in `system`
|
||||
if sym != nil:
|
||||
cgsymImpl m, sym
|
||||
cgsym(m, "programResult")
|
||||
if m.inHcrInitGuard:
|
||||
endBlock(m.initProc)
|
||||
|
||||
@@ -2280,18 +2123,25 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
cgsym(m, "rawWrite")
|
||||
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
cgsym(m, "initThreadVarsEmulation")
|
||||
|
||||
if m.g.forwardedProcs.len == 0:
|
||||
incl m.flags, objHasKidsValid
|
||||
result = generateMethodDispatchers(graph, m.idgen)
|
||||
let disp = generateMethodDispatchers(graph)
|
||||
for x in disp: genProcAux(m, x.sym)
|
||||
|
||||
let mm = m
|
||||
m.g.modulesClosed.add mm
|
||||
|
||||
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil: return
|
||||
finalCodegenActions(graph, BModule(b), n)
|
||||
|
||||
proc genForwardedProcs(g: BModuleList) =
|
||||
# Forward declared proc:s lack bodies when first encountered, so they're given
|
||||
# a second pass here
|
||||
@@ -2318,3 +2168,5 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
|
||||
m.writeModule(pending=true)
|
||||
writeMapping(config, g.mapping)
|
||||
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
|
||||
|
||||
const cgenPass* = makePass(myOpen, myProcess, myClose)
|
||||
|
||||
@@ -86,7 +86,6 @@ type
|
||||
options*: TOptions # options that should be used for code
|
||||
# generation; this is the same as prc.options
|
||||
# unless prc == nil
|
||||
optionsStack*: seq[TOptions]
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
splitDecls*: int # > 0 if we are in some context for C++ that
|
||||
@@ -135,7 +134,6 @@ type
|
||||
# unconditionally...
|
||||
# nimtvDeps is VERY hard to cache because it's
|
||||
# not a list of IDs nor can it be made to be one.
|
||||
mangledPrcs*: HashSet[string]
|
||||
|
||||
TCGen = object of PPassContext # represents a C source file
|
||||
s*: TCFileSections # sections of the C file
|
||||
@@ -149,7 +147,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
|
||||
@@ -174,7 +172,6 @@ type
|
||||
|
||||
template config*(m: BModule): ConfigRef = m.g.config
|
||||
template config*(p: BProc): ConfigRef = p.module.g.config
|
||||
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
|
||||
|
||||
proc includeHeader*(this: BModule; header: string) =
|
||||
if not this.headerFiles.contains header:
|
||||
@@ -194,17 +191,15 @@ proc initBlock*(): TBlock =
|
||||
result.sections[i] = newRopeAppender()
|
||||
|
||||
proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
result = BProc(
|
||||
prc: prc,
|
||||
module: module,
|
||||
optionsStack: if module.initProc != nil: module.initProc.optionsStack
|
||||
else: @[],
|
||||
options: if prc != nil: prc.options
|
||||
else: module.config.options,
|
||||
blocks: @[initBlock()],
|
||||
sigConflicts: initCountTable[string]())
|
||||
if optQuirky in result.options:
|
||||
result.flags = {nimErrorFlagDisabled}
|
||||
new(result)
|
||||
result.prc = prc
|
||||
result.module = module
|
||||
result.options = if prc != nil: prc.options
|
||||
else: module.config.options
|
||||
result.blocks = @[initBlock()]
|
||||
result.nestedTryStmts = @[]
|
||||
result.finallySafePoints = @[]
|
||||
result.sigConflicts = initCountTable[string]()
|
||||
|
||||
proc newModuleList*(g: ModuleGraph): BModuleList =
|
||||
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),
|
||||
|
||||
@@ -95,8 +95,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]
|
||||
@@ -114,7 +113,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
s.ast[dispatcherPos] = dispatcher
|
||||
|
||||
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
var disp = copySym(s, idgen)
|
||||
var disp = copySym(s, nextSymId(idgen))
|
||||
incl(disp.flags, sfDispatcher)
|
||||
excl(disp.flags, sfExported)
|
||||
let old = disp.typ
|
||||
@@ -128,7 +127,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
disp.loc.r = ""
|
||||
if s.typ[0] != nil:
|
||||
if disp.ast.len > resultPos:
|
||||
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
|
||||
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen))
|
||||
else:
|
||||
# We've encountered a method prototype without a filled-in
|
||||
# resultPos slot. We put a placeholder in there that will
|
||||
@@ -214,7 +213,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
|
||||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
|
||||
var base = methods[0].ast[dispatcherPos].sym
|
||||
result = base
|
||||
var paramLen = base.typ.len
|
||||
@@ -273,7 +272,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idg
|
||||
nilchecks.flags.incl nfTransf # should not be further transformed
|
||||
result.ast[bodyPos] = nilchecks
|
||||
|
||||
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
|
||||
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
for bucket in 0..<g.methods.len:
|
||||
var relevantCols = initIntSet()
|
||||
@@ -283,4 +282,4 @@ proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
|
||||
# if multi-methods are not enabled, we are interested only in the first field
|
||||
break
|
||||
sortBucket(g.methods[bucket].methods, relevantCols)
|
||||
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))
|
||||
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))
|
||||
|
||||
@@ -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:
|
||||
@@ -183,7 +183,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
|
||||
ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
|
||||
|
||||
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
|
||||
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
|
||||
result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info)
|
||||
result.typ = typ
|
||||
assert(not typ.isNil)
|
||||
|
||||
@@ -855,9 +855,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkReturnStmt:
|
||||
# We're somewhere in try, transform to finally unrolling
|
||||
if ctx.nearestFinally == 0:
|
||||
# return is within the finally
|
||||
return
|
||||
assert(ctx.nearestFinally != 0)
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
@@ -1350,7 +1348,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
|
||||
let idefs = copyNode(it)
|
||||
for v in 0..it.len-3:
|
||||
if it[v].kind == nkSym:
|
||||
let x = copySym(it[v].sym, c.idgen)
|
||||
let x = copySym(it[v].sym, nextSymId(c.idgen))
|
||||
c.tab[it[v].sym.id] = x
|
||||
idefs.add newSymNode(x)
|
||||
else:
|
||||
@@ -1391,7 +1389,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
|
||||
discard c.finallys.pop()
|
||||
|
||||
of nkWhileStmt, nkBlockStmt:
|
||||
if not n.hasYields: return n
|
||||
if n.hasYields == false: return n
|
||||
c.blocks.add((n, c.finallys.len))
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
@@ -1433,9 +1431,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which will
|
||||
# be handled specially by lambda lifting. Local temp vars (if needed)
|
||||
# should follow the same logic.
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info)
|
||||
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info)
|
||||
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
|
||||
var n = preprocess(pc, n.toStmtList)
|
||||
#echo "transformed into ", n
|
||||
@@ -1468,10 +1466,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
||||
result = ctx.transformStateAssignments(result)
|
||||
result = ctx.wrapIntoStateLoop(result)
|
||||
|
||||
when false:
|
||||
echo "TRANSFORM TO STATES: "
|
||||
echo renderTree(result)
|
||||
# echo "TRANSFORM TO STATES: "
|
||||
# echo renderTree(result)
|
||||
|
||||
echo "exception table:"
|
||||
for i, e in ctx.exceptionTable:
|
||||
echo i, " -> ", e
|
||||
# echo "exception table:"
|
||||
# for i, e in ctx.exceptionTable:
|
||||
# echo i, " -> ", e
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
|
||||
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix
|
||||
|
||||
import
|
||||
options, idents, nimconf, extccomp, commands, msgs,
|
||||
@@ -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")
|
||||
|
||||
@@ -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}
|
||||
@@ -242,9 +238,9 @@ proc processCompile(conf: ConfigRef; filename: string) =
|
||||
extccomp.addExternalFileToCompile(conf, found)
|
||||
|
||||
const
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
|
||||
template warningOptionNoop(switch: string) =
|
||||
@@ -266,7 +262,6 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "go": result = conf.selectedGC == gcGo
|
||||
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)
|
||||
of "opt":
|
||||
case arg.normalize
|
||||
@@ -341,7 +336,6 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
||||
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
|
||||
of "panics": result = contains(conf.globalOptions, optPanics)
|
||||
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||
@@ -521,7 +515,14 @@ proc initOrcDefines*(conf: ConfigRef) =
|
||||
if conf.exc == excNone and conf.backend != backendCpp:
|
||||
conf.exc = excGoto
|
||||
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
|
||||
if isOrc:
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
else:
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
incl conf.globalOptions, optSeqDestructors
|
||||
incl conf.globalOptions, optTinyRtti
|
||||
@@ -531,11 +532,10 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
|
||||
if conf.exc == excNone and conf.backend != backendCpp:
|
||||
conf.exc = excGoto
|
||||
|
||||
proc unregisterArcOrc*(conf: ConfigRef) =
|
||||
proc unregisterArcOrc(conf: ConfigRef) =
|
||||
undefSymbol(conf.symbols, "gcdestructors")
|
||||
undefSymbol(conf.symbols, "gcarc")
|
||||
undefSymbol(conf.symbols, "gcorc")
|
||||
undefSymbol(conf.symbols, "gcatomicarc")
|
||||
undefSymbol(conf.symbols, "nimSeqsV2")
|
||||
undefSymbol(conf.symbols, "nimV2")
|
||||
excl conf.globalOptions, optSeqDestructors
|
||||
@@ -561,17 +561,9 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
conf.selectedGC = gcMarkAndSweep
|
||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||
of "destructors", "arc":
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
registerArcOrc(pass, conf)
|
||||
registerArcOrc(pass, conf, false)
|
||||
of "orc":
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "atomicarc":
|
||||
conf.selectedGC = gcAtomicArc
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
registerArcOrc(pass, conf)
|
||||
registerArcOrc(pass, conf, true)
|
||||
of "hooks":
|
||||
conf.selectedGC = gcHooks
|
||||
defineSymbol(conf.symbols, "gchooks")
|
||||
@@ -618,8 +610,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
var path = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
|
||||
if not nimbleDir.isEmpty and pass == passPP:
|
||||
path = nimbleDir / RelativeDir"pkgs2"
|
||||
nimblePath(conf, path, info)
|
||||
path = nimbleDir / RelativeDir"pkgs"
|
||||
nimblePath(conf, path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
@@ -659,11 +649,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "backend", "b":
|
||||
let backend = parseEnum(arg.normalize, TBackend.default)
|
||||
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
|
||||
if backend == backendJs: # bug #21209
|
||||
conf.globalOptions.excl {optThreadAnalysis, optThreads}
|
||||
if optRun in conf.globalOptions:
|
||||
# for now, -r uses nodejs, so define nodejs
|
||||
defineSymbol(conf.symbols, "nodejs")
|
||||
conf.backend = backend
|
||||
of "doccmd": conf.docCmd = arg
|
||||
of "define", "d":
|
||||
@@ -811,7 +796,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
defineSymbol(conf.symbols, "dll")
|
||||
of "staticlib":
|
||||
incl(conf.globalOptions, optGenStaticLib)
|
||||
incl(conf.globalOptions, optNoMain)
|
||||
excl(conf.globalOptions, optGenGuiApp)
|
||||
defineSymbol(conf.symbols, "library")
|
||||
defineSymbol(conf.symbols, "staticlib")
|
||||
@@ -835,16 +819,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "header":
|
||||
if conf != nil: conf.headerFile = arg
|
||||
incl(conf.globalOptions, optGenIndex)
|
||||
of "nimbasepattern":
|
||||
if conf != nil: conf.nimbasePattern = arg
|
||||
of "index":
|
||||
case arg.normalize
|
||||
of "", "on": conf.globalOptions.incl {optGenIndex}
|
||||
of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex}
|
||||
of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly}
|
||||
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||
of "noimportdoc":
|
||||
processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info)
|
||||
processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
|
||||
of "import":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -877,9 +853,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
setTarget(conf.target, conf.target.targetOS, cpu)
|
||||
of "run", "r":
|
||||
processOnOffSwitchG(conf, {optRun}, arg, pass, info)
|
||||
if conf.backend == backendJs:
|
||||
# for now, -r uses nodejs, so define nodejs
|
||||
defineSymbol(conf.symbols, "nodejs")
|
||||
of "maxloopiterationsvm":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.maxLoopIterationsVM = parseInt(arg)
|
||||
@@ -894,7 +867,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "verbosity":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let verbosity = parseInt(arg)
|
||||
if verbosity notin 0..3:
|
||||
if verbosity notin {0..3}:
|
||||
localError(conf, info, "invalid verbosity level: '$1'" % arg)
|
||||
conf.verbosity = verbosity
|
||||
var verb = NotesVerbosity[conf.verbosity]
|
||||
@@ -1027,9 +1000,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.exc = low(ExceptionSystem)
|
||||
defineSymbol(conf.symbols, "noCppExceptions")
|
||||
of "shownonexports":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
showNonExportedFields(conf)
|
||||
of "exceptions":
|
||||
case arg.normalize
|
||||
of "cpp": conf.exc = excCpp
|
||||
@@ -1084,6 +1054,29 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "expandarc":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.arcToExpand[arg] = "T"
|
||||
of "useversion":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
case arg
|
||||
of "1.0":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "0")
|
||||
# old behaviors go here:
|
||||
defineSymbol(conf.symbols, "nimOldRelativePathBehavior")
|
||||
undefSymbol(conf.symbols, "nimDoesntTrackDefects")
|
||||
ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect}
|
||||
conf.globalOptions.incl optNimV1Emulation
|
||||
of "1.2":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "2")
|
||||
conf.globalOptions.incl optNimV12Emulation
|
||||
of "1.6":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "6")
|
||||
conf.globalOptions.incl optNimV16Emulation
|
||||
else:
|
||||
localError(conf, info, "unknown Nim version; currently supported values are: `1.0`, `1.2`")
|
||||
# always be compatible with 1.x.100:
|
||||
defineSymbol(conf.symbols, "NimPatch", "100")
|
||||
of "benchmarkvm":
|
||||
processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
|
||||
of "profilevm":
|
||||
@@ -1097,8 +1090,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
|
||||
if optPanics in conf.globalOptions:
|
||||
defineSymbol(conf.symbols, "nimPanics")
|
||||
of "jsbigint64":
|
||||
processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info)
|
||||
of "sourcemap": # xxx document in --fullhelp
|
||||
conf.globalOptions.incl optSourcemap
|
||||
conf.options.incl optLineDir
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
include "../lib/system/compilation.nim"
|
||||
version = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
author = "Andreas Rumpf"
|
||||
description = "Compiler package providing the compiler sources as a library."
|
||||
license = "MIT"
|
||||
skipDirs = @["."]
|
||||
installDirs = @["compiler"]
|
||||
|
||||
import os
|
||||
|
||||
var compilerDir = ""
|
||||
|
||||
before install:
|
||||
rmDir("compiler")
|
||||
|
||||
let
|
||||
files = listFiles(".")
|
||||
dirs = listDirs(".")
|
||||
|
||||
mkDir("compiler")
|
||||
|
||||
for f in files:
|
||||
cpFile(f, "compiler" / f)
|
||||
|
||||
for d in dirs:
|
||||
cpDir(d, "compiler" / d)
|
||||
|
||||
requires "nim"
|
||||
@@ -27,7 +27,7 @@ const
|
||||
proc declareSelf(c: PContext; info: TLineInfo) =
|
||||
## Adds the magical 'Self' symbols to the current scope.
|
||||
let ow = getCurrOwner(c)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info)
|
||||
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
|
||||
s.typ.flags.incl {tfUnresolved, tfPacked}
|
||||
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
|
||||
@@ -62,7 +62,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode =
|
||||
result[i] = n[i]
|
||||
result[^1] = semConceptDecl(c, n[^1])
|
||||
of nkCommentStmt:
|
||||
result = n
|
||||
discard
|
||||
else:
|
||||
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
|
||||
result = n
|
||||
@@ -274,7 +274,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
|
||||
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
|
||||
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
|
||||
## 'n' is the nkProcDef or similar from the concept that we try to match.
|
||||
let candidates = searchInScopesAllCandidatesFilterBy(c, n[namePos].sym.name, kinds)
|
||||
let candidates = searchInScopesFilterBy(c, n[namePos].sym.name, kinds)
|
||||
for candidate in candidates:
|
||||
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
|
||||
m.magic = candidate.magic
|
||||
@@ -306,15 +306,13 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
|
||||
result = matchSyms(c, n, {skMethod}, m)
|
||||
of nkIteratorDef:
|
||||
result = matchSyms(c, n, {skIterator}, m)
|
||||
of nkCommentStmt:
|
||||
result = true
|
||||
else:
|
||||
# error was reported earlier.
|
||||
result = false
|
||||
|
||||
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var 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
|
||||
|
||||
@@ -25,7 +25,7 @@ proc undefSymbol*(symbols: StringTableRef; symbol: string) =
|
||||
# result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||
|
||||
iterator definedSymbolNames*(symbols: StringTableRef): string =
|
||||
for key in keys(symbols):
|
||||
for key, val in pairs(symbols):
|
||||
yield key
|
||||
|
||||
proc countDefinedSymbols*(symbols: StringTableRef): int =
|
||||
@@ -45,8 +45,10 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimNewTypedesc") # deadcode
|
||||
defineSymbol("nimrequiresnimframe") # deadcode
|
||||
defineSymbol("nimparsebiggestfloatmagic") # deadcode
|
||||
defineSymbol("nimalias") # deadcode
|
||||
defineSymbol("nimlocks") # deadcode
|
||||
defineSymbol("nimnode") # deadcode
|
||||
defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package
|
||||
# refs https://github.com/nim-lang/opengl/pull/79
|
||||
defineSymbol("nimvarargstyped") # deadcode
|
||||
defineSymbol("nimtypedescfixed") # deadcode
|
||||
defineSymbol("nimKnowsNimvm") # deadcode
|
||||
@@ -82,24 +84,10 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasSignatureHashInMacro") # deadcode
|
||||
defineSymbol("nimHasDefault") # deadcode
|
||||
defineSymbol("nimMacrosSizealignof") # deadcode
|
||||
defineSymbol("nimNoZeroExtendMagic") # deadcode
|
||||
defineSymbol("nimMacrosGetNodeId") # deadcode
|
||||
defineSymbol("nimFixedForwardGeneric") # deadcode
|
||||
defineSymbol("nimToOpenArrayCString") # deadcode
|
||||
defineSymbol("nimHasUsed") # deadcode
|
||||
defineSymbol("nimnomagic64") # deadcode
|
||||
defineSymbol("nimNewShiftOps") # deadcode
|
||||
defineSymbol("nimHasCursor") # deadcode
|
||||
defineSymbol("nimAlignPragma") # deadcode
|
||||
defineSymbol("nimHasExceptionsQuery") # deadcode
|
||||
defineSymbol("nimHasIsNamedTuple") # deadcode
|
||||
defineSymbol("nimHashOrdinalFixed") # deadcode
|
||||
defineSymbol("nimHasSinkInference") # deadcode
|
||||
defineSymbol("nimNewIntegerOps") # deadcode
|
||||
defineSymbol("nimHasInvariant") # deadcode
|
||||
|
||||
|
||||
|
||||
# > 0.20.0
|
||||
defineSymbol("nimNoZeroExtendMagic")
|
||||
defineSymbol("nimMacrosGetNodeId")
|
||||
for f in Feature:
|
||||
defineSymbol("nimHas" & $f)
|
||||
|
||||
@@ -110,18 +98,31 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
|
||||
defineSymbol("nimFixedOwned")
|
||||
defineSymbol("nimHasStyleChecks")
|
||||
defineSymbol("nimToOpenArrayCString")
|
||||
defineSymbol("nimHasUsed")
|
||||
defineSymbol("nimFixedForwardGeneric")
|
||||
defineSymbol("nimnomagic64")
|
||||
defineSymbol("nimNewShiftOps")
|
||||
defineSymbol("nimHasCursor")
|
||||
defineSymbol("nimAlignPragma")
|
||||
defineSymbol("nimHasExceptionsQuery")
|
||||
defineSymbol("nimHasIsNamedTuple")
|
||||
defineSymbol("nimHashOrdinalFixed")
|
||||
|
||||
when defined(nimHasLibFFI):
|
||||
# Renaming as we can't conflate input vs output define flags; e.g. this
|
||||
# will report the right thing regardless of whether user adds
|
||||
# `-d:nimHasLibFFI` in his user config.
|
||||
defineSymbol("nimHasLibFFIEnabled") # deadcode
|
||||
defineSymbol("nimHasLibFFIEnabled")
|
||||
|
||||
defineSymbol("nimHasStacktraceMsgs") # deadcode
|
||||
defineSymbol("nimHasSinkInference")
|
||||
defineSymbol("nimNewIntegerOps")
|
||||
defineSymbol("nimHasInvariant")
|
||||
defineSymbol("nimHasStacktraceMsgs")
|
||||
defineSymbol("nimDoesntTrackDefects")
|
||||
defineSymbol("nimHasLentIterators") # deadcode
|
||||
defineSymbol("nimHasDeclaredMagic") # deadcode
|
||||
defineSymbol("nimHasStacktracesModule") # deadcode
|
||||
defineSymbol("nimHasLentIterators")
|
||||
defineSymbol("nimHasDeclaredMagic")
|
||||
defineSymbol("nimHasStacktracesModule")
|
||||
defineSymbol("nimHasEffectTraitsModule")
|
||||
defineSymbol("nimHasCastPragmaBlocks")
|
||||
defineSymbol("nimHasDeclaredLocs")
|
||||
@@ -132,8 +133,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasCustomLiterals")
|
||||
defineSymbol("nimHasUnifiedTuple")
|
||||
defineSymbol("nimHasIterable")
|
||||
defineSymbol("nimHasTypeofVoid") # deadcode
|
||||
defineSymbol("nimHasDragonBox") # deadcode
|
||||
defineSymbol("nimHasTypeofVoid")
|
||||
defineSymbol("nimHasDragonBox")
|
||||
defineSymbol("nimHasHintAll")
|
||||
defineSymbol("nimHasTrace")
|
||||
defineSymbol("nimHasEffectsOf")
|
||||
@@ -143,23 +144,10 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||
defineSymbol("nimHasCstringCase")
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
defineSymbol("nimHasWarnCastSizes") # deadcode
|
||||
defineSymbol("nimHasOutParams")
|
||||
defineSymbol("nimHasSystemRaisesDefect")
|
||||
defineSymbol("nimHasWarnUnnamedBreak")
|
||||
defineSymbol("nimHasGenericDefine")
|
||||
defineSymbol("nimHasDefineAliases")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
defineSymbol("nimHasDup")
|
||||
defineSymbol("nimHasChecksums")
|
||||
defineSymbol("nimHasSendable")
|
||||
defineSymbol("nimAllowNonVarDestructor")
|
||||
defineSymbol("nimHasQuirky")
|
||||
defineSymbol("nimHasEnsureMove")
|
||||
defineSymbol("nimHasNoReturnError")
|
||||
|
||||
defineSymbol("nimHasCastExtendedVm")
|
||||
defineSymbol("nimHasGenericsOpenSym2")
|
||||
defineSymbol("nimHasNolineTooLong")
|
||||
defineSymbol("nimHasGenericsOpenSym3")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import options, ast, ropes, pathutils, msgs, lineinfos
|
||||
import options, ast, ropes, passes, pathutils, msgs, lineinfos
|
||||
|
||||
import modulegraphs
|
||||
|
||||
@@ -63,16 +63,12 @@ proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
sub.add "/pkgs/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
sub[^1] = '2'
|
||||
sub.add '/'
|
||||
start = s.find(sub) # /pkgs2
|
||||
if start < 0:
|
||||
return s
|
||||
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
result = s
|
||||
else:
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
|
||||
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
doAssert n.kind == nkSym, $n.kind
|
||||
@@ -83,7 +79,7 @@ proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
|
||||
addDependencyAux(b, parent, child)
|
||||
|
||||
proc addDotDependency*(c: PPassContext, n: PNode): PNode =
|
||||
proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
let g = PGen(c)
|
||||
let b = Backend(g.graph.backend)
|
||||
@@ -104,7 +100,10 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
|
||||
rope(project.splitFile.name), b.dotGraph],
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
@@ -113,3 +112,6 @@ proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPa
|
||||
if graph.backend == nil:
|
||||
graph.backend = Backend(dotGraph: "")
|
||||
result = g
|
||||
|
||||
const gendependPass* = makePass(open = myOpen, process = addDotDependency)
|
||||
|
||||
|
||||
@@ -264,8 +264,7 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
|
||||
c.blocks[i].raiseFixups.add lab1
|
||||
else:
|
||||
var trailingFinales: seq[PNode]
|
||||
if c.inTryStmt > 0:
|
||||
# Ok, we are in a try, lets see which (if any) try's we break out from:
|
||||
if c.inTryStmt > 0: #Ok, we are in a try, lets see which (if any) try's we break out from:
|
||||
for b in countdown(c.blocks.high, i):
|
||||
if c.blocks[b].isTryBlock:
|
||||
trailingFinales.add c.blocks[b].finale
|
||||
@@ -386,8 +385,7 @@ proc genCall(c: var Con; n: PNode) =
|
||||
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
|
||||
genDef(c, n[i])
|
||||
# every call can potentially raise:
|
||||
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
|
||||
inc c.interestingInstructions
|
||||
if false: # c.inTryStmt > 0 and canRaiseConservative(n[0]):
|
||||
# we generate the instruction sequence:
|
||||
# fork lab1
|
||||
# goto exceptionHandler (except or finally)
|
||||
@@ -495,7 +493,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
|
||||
gen(c, body)
|
||||
if root.kind == skResult:
|
||||
genImplicitReturn(c)
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
result = c.code # will move
|
||||
else:
|
||||
shallowCopy(result, c.code)
|
||||
|
||||
@@ -7,17 +7,13 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This is the Nim documentation generator. Cross-references are generated
|
||||
## by knowing how the anchors are going to be named.
|
||||
##
|
||||
## .. importdoc:: ../docgen.md
|
||||
##
|
||||
## For corresponding users' documentation see [Nim DocGen Tools Guide].
|
||||
# This is the documentation generator. Cross-references are generated
|
||||
# by knowing how the anchors are going to be named.
|
||||
|
||||
import
|
||||
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
|
||||
wordrecg, syntaxes, renderer, lexer,
|
||||
packages/docutils/[rst, rstidx, rstgen, dochelpers],
|
||||
packages/docutils/[rst, rstgen, dochelpers],
|
||||
json, xmltree, trees, types,
|
||||
typesrenderer, astalgo, lineinfos, intsets,
|
||||
pathutils, tables, nimpaths, renderverbatim, osproc, packages
|
||||
@@ -95,7 +91,7 @@ type
|
||||
jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering
|
||||
types: TStrTable
|
||||
sharedState: PRstSharedState
|
||||
standaloneDoc: bool # is markup (.rst/.md) document?
|
||||
standaloneDoc: bool
|
||||
conf*: ConfigRef
|
||||
cache*: IdentCache
|
||||
exampleCounter: int
|
||||
@@ -112,16 +108,13 @@ type
|
||||
proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
|
||||
proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
|
||||
|
||||
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
|
||||
let invalid = rstast.FileIndex(-1)
|
||||
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
|
||||
if result == invalid:
|
||||
let fname = toFullPath(d.conf, fileIndex)
|
||||
result = addFilename(d.sharedState, fname)
|
||||
d.nimToRstFid[fileIndex] = result
|
||||
|
||||
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
|
||||
addRstFileIndex(d, info.fileIndex)
|
||||
let invalid = rstast.FileIndex(-1)
|
||||
result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
|
||||
if result == invalid:
|
||||
let fname = toFullPath(d.conf, info)
|
||||
result = addFilename(d.sharedState, fname)
|
||||
d.nimToRstFid[info.fileIndex] = result
|
||||
|
||||
proc cmpDecimalsIgnoreCase(a, b: string): int =
|
||||
## For sorting with correct handling of cases like 'uint8' and 'uint16'.
|
||||
@@ -232,7 +225,7 @@ proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
if params.len > 0: check(0)
|
||||
for i in 2..<params.len: check(i)
|
||||
|
||||
template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
|
||||
template declareClosures =
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.MsgKind, arg: string) {.gcsafe.} =
|
||||
# translate msg kind:
|
||||
@@ -256,19 +249,9 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
|
||||
of mwBrokenLink: k = warnRstBrokenLink
|
||||
of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnRstFieldXNotSupported
|
||||
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
|
||||
of mwRstStyle: k = warnRstStyle
|
||||
{.gcsafe.}:
|
||||
let errorsAsWarnings = (roPreferMarkdown in d.sharedState.options) and
|
||||
not d.standaloneDoc # not tolerate errors in .rst/.md files
|
||||
if whichMsgClass(msgKind) == mcError and errorsAsWarnings:
|
||||
liMessage(conf, newLineInfo(conf, AbsoluteFile filename, line, col),
|
||||
k, arg, doNothing, instLoc(), ignoreError=true)
|
||||
# when our Markdown parser fails, we currently can only terminate the
|
||||
# parsing (and then we will return monospaced text instead of markup):
|
||||
raiseRecoverableError("")
|
||||
else:
|
||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.gcsafe.} =
|
||||
result = options.findFile(conf, s).string
|
||||
@@ -276,29 +259,10 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
|
||||
result = getCurrentDir() / s
|
||||
if not fileExists(result): result = ""
|
||||
|
||||
proc docgenFindRefFile(targetRelPath: string):
|
||||
tuple[targetPath: string, linkRelPath: string] {.gcsafe.} =
|
||||
let fromDir = splitFile(destFile).dir # dir where we reference from
|
||||
let basedir = os.splitFile(currentFilename.string).dir
|
||||
let outDirPath: RelativeFile =
|
||||
presentationPath(conf, AbsoluteFile(basedir / targetRelPath))
|
||||
# use presentationPath because `..` path can be be mangled to `_._`
|
||||
result.targetPath = string(conf.outDir / outDirPath)
|
||||
if not fileExists(result.targetPath):
|
||||
# this can happen if targetRelPath goes to parent directory `OUTDIR/..`.
|
||||
# Trying it, this may cause ambiguities, but allows us to insert
|
||||
# "packages" into each other, which is actually used in Nim repo itself.
|
||||
let destPath = fromDir / targetRelPath
|
||||
if destPath != result.targetPath and fileExists(destPath):
|
||||
result.targetPath = destPath
|
||||
|
||||
result.linkRelPath = relativePath(result.targetPath.splitFile.dir,
|
||||
fromDir).replace('\\', '/')
|
||||
|
||||
|
||||
proc parseRst(text: string,
|
||||
line, column: int,
|
||||
conf: ConfigRef, sharedState: PRstSharedState): PRstNode =
|
||||
declareClosures()
|
||||
result = rstParsePass1(text, line, column, sharedState)
|
||||
|
||||
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
|
||||
@@ -319,10 +283,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
outExt: string = HtmlExt, module: PSym = nil,
|
||||
standaloneDoc = false, preferMarkdown = true,
|
||||
hasToc = true): PDoc =
|
||||
let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
|
||||
declareClosures()
|
||||
new(result)
|
||||
let d = result # pass `d` to `declareClosures`:
|
||||
declareClosures(currentFilename = filename, destFile = destFile)
|
||||
result.module = module
|
||||
result.conf = conf
|
||||
result.cache = cache
|
||||
@@ -336,7 +298,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
result.hasToc = hasToc
|
||||
result.sharedState = newRstSharedState(
|
||||
options, filename.string,
|
||||
docgenFindFile, docgenFindRefFile, compilerMsgHandler, hasToc)
|
||||
docgenFindFile, compilerMsgHandler, hasToc)
|
||||
initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml),
|
||||
conf.configVars, filename.string,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
@@ -411,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
if gotten != status:
|
||||
rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output])
|
||||
result.emitted = initIntSet()
|
||||
result.destFile = destFile
|
||||
result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
|
||||
result.thisDir = result.destFile.AbsoluteFile.splitFile.dir
|
||||
|
||||
template dispA(conf: ConfigRef; dest: var string, xml, tex: string,
|
||||
@@ -428,19 +390,16 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
proc genComment(d: PDoc, n: PNode): PRstNode =
|
||||
if n.comment.len > 0:
|
||||
d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
|
||||
try:
|
||||
result = parseRst(n.comment,
|
||||
toLinenumber(n.info),
|
||||
toColumn(n.info) + DocColOffset,
|
||||
d.conf, d.sharedState)
|
||||
except ERecoverableError:
|
||||
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
|
||||
result = parseRst(n.comment,
|
||||
toLinenumber(n.info),
|
||||
toColumn(n.info) + DocColOffset,
|
||||
d.conf, d.sharedState)
|
||||
|
||||
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
|
||||
if n == nil: return nil
|
||||
result = genComment(d, n)
|
||||
if result == nil:
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy,
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
|
||||
nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}:
|
||||
# notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
|
||||
for i in 0..<n.len:
|
||||
@@ -578,13 +537,10 @@ proc runAllExamples(d: PDoc) =
|
||||
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
|
||||
# via command line
|
||||
# D20210224T221756:here
|
||||
var pathArgs = "--path:$path" % [ "path", quoteShell(d.conf.projectPath) ]
|
||||
for p in d.conf.searchPaths:
|
||||
pathArgs = "$args --path:$path" % [ "args", pathArgs, "path", quoteShell(p) ]
|
||||
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off $pathArgs --nimcache:$nimcache $rdoccmd $docCmd $file" % [
|
||||
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
|
||||
"nim", quoteShell(os.getAppFilename()),
|
||||
"backend", $d.conf.backend,
|
||||
"pathArgs", pathArgs,
|
||||
"path", quoteShell(d.conf.projectPath),
|
||||
"libpath", quoteShell(d.conf.libpath),
|
||||
"nimcache", quoteShell(outputDir),
|
||||
"file", quoteShell(outp),
|
||||
@@ -619,6 +575,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
let useRenderModule = false
|
||||
let loc = d.conf.toFileLineCol(n.info)
|
||||
let code = extractRunnableExamplesSource(d.conf, n)
|
||||
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
|
||||
|
||||
if d.conf.errorCounter > 0:
|
||||
return (rdoccmd, code)
|
||||
@@ -634,7 +591,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
docComment.comment = comment
|
||||
var runnableExamples = newTree(nkStmtList,
|
||||
docComment,
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, "std/assertions")),
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
|
||||
runnableExamples.info = n.info
|
||||
for a in n.lastSon: runnableExamples.add a
|
||||
@@ -648,7 +604,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
else:
|
||||
var code2 = code
|
||||
if code.len > 0 and "codeReordering" notin code:
|
||||
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
|
||||
# hacky but simplest solution, until we devise a way to make `{.line.}`
|
||||
# work without introducing a scope
|
||||
code2 = """
|
||||
@@ -659,7 +614,6 @@ $#
|
||||
#[
|
||||
$#
|
||||
]#
|
||||
import std/assertions
|
||||
import $#
|
||||
$#
|
||||
""" % [comment, d.filename.quoted, code2]
|
||||
@@ -811,24 +765,21 @@ proc isVisible(d: PDoc; n: PNode): bool =
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(d, n[0])
|
||||
|
||||
proc getName(n: PNode): string =
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
case n.kind
|
||||
of nkPostfix: result = getName(n[1])
|
||||
of nkPragmaExpr: result = getName(n[0])
|
||||
of nkSym: result = n.sym.renderDefinitionName
|
||||
of nkIdent: result = n.ident.s
|
||||
of nkPostfix: result = getName(d, n[1], splitAfter)
|
||||
of nkPragmaExpr: result = getName(d, n[0], splitAfter)
|
||||
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
|
||||
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
|
||||
of nkAccQuoted:
|
||||
result = "`"
|
||||
for i in 0..<n.len: result.add(getName(n[i]))
|
||||
result = "`"
|
||||
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
|
||||
result = getName(n[0])
|
||||
result = esc(d.target, "`")
|
||||
for i in 0..<n.len: result.add(getName(d, n[i], splitAfter))
|
||||
result.add esc(d.target, "`")
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getName(d, n[0], splitAfter)
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc getNameEsc(d: PDoc, n: PNode): string =
|
||||
esc(d.target, getName(n))
|
||||
|
||||
proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
|
||||
case n.kind
|
||||
of nkPostfix: result = getNameIdent(cache, n[1])
|
||||
@@ -839,7 +790,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 +804,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
|
||||
@@ -977,13 +928,6 @@ proc symbolPriority(k: TSymKind): int =
|
||||
else: 0 # including skProc which have higher priority
|
||||
# documentation itself has even higher priority 1
|
||||
|
||||
proc getTypeKind(n: PNode): string =
|
||||
case n[2].kind
|
||||
of nkEnumTy: "enum"
|
||||
of nkObjectTy: "object"
|
||||
of nkTupleTy: "tuple"
|
||||
else: ""
|
||||
|
||||
proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
## Converts symbol info (names/types/parameters) in `n` into format
|
||||
## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``.
|
||||
@@ -1027,13 +971,17 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
if kind != tkSpaces:
|
||||
result.generics.add(literal.nimIdentNormalize)
|
||||
|
||||
if k == skType: result.symTypeKind = getTypeKind(n)
|
||||
if k == skType:
|
||||
case n[2].kind
|
||||
of nkEnumTy: result.symTypeKind = "enum"
|
||||
of nkObjectTy: result.symTypeKind = "object"
|
||||
of nkTupleTy: result.symTypeKind = "tuple"
|
||||
else: discard
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonExports: bool = false) =
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
if (docFlags != kForceExport) and not isVisible(d, nameNode): return
|
||||
let
|
||||
name = getName(nameNode)
|
||||
nameEsc = esc(d.target, name)
|
||||
name = getName(d, nameNode)
|
||||
var plainDocstring = getPlainDocstring(n) # call here before genRecComment!
|
||||
var result = ""
|
||||
var literal, plainName = ""
|
||||
@@ -1060,12 +1008,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
inc(d.id)
|
||||
let
|
||||
plainNameEsc = esc(d.target, plainName.strip)
|
||||
typeDescr =
|
||||
if k == skType and getTypeKind(n) != "": getTypeKind(n)
|
||||
else: k.toHumanStr
|
||||
detailedName = typeDescr & " " & (
|
||||
detailedName = k.toHumanStr & " " & (
|
||||
if k in routineKinds: plainName else: name)
|
||||
uniqueName = if k in routineKinds: plainNameEsc else: nameEsc
|
||||
uniqueName = if k in routineKinds: plainNameEsc else: name
|
||||
sortName = if k in routineKinds: plainName.strip else: name
|
||||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||
@@ -1079,16 +1024,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
let lineinfo = rstast.TLineInfo(
|
||||
line: nameNode.info.line, col: nameNode.info.col,
|
||||
fileIndex: addRstFileIndex(d, nameNode.info))
|
||||
addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
|
||||
tooltip = detailedName, langSym = rstLangSymbol,
|
||||
priority = symbolPriority(k), info = lineinfo,
|
||||
module = addRstFileIndex(d, FileIndex d.module.position))
|
||||
addAnchorNim(d.sharedState, refn = symbolOrId, tooltip = detailedName,
|
||||
rstLangSymbol, priority = symbolPriority(k), info = lineinfo)
|
||||
|
||||
let renderFlags =
|
||||
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
|
||||
renderExpandUsing, renderNonExportedFields}
|
||||
else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing}
|
||||
nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc)
|
||||
nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments,
|
||||
renderDocComments, renderSyms, renderExpandUsing}, symbolOrIdEnc)
|
||||
|
||||
let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int)
|
||||
|
||||
@@ -1120,10 +1060,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
if e.sym.kind != skEnumField: continue
|
||||
let plain = renderPlainSymbolName(e)
|
||||
let symbolOrId = d.newUniquePlainSymbol(plain)
|
||||
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId,
|
||||
term = plain, linkTitle = nameNode.sym.name.s & '.' & plain,
|
||||
linkDesc = xmltree.escape(getPlainDocstring(e).docstringSummary),
|
||||
line = n.info.line.int)
|
||||
setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain,
|
||||
xmltree.escape(getPlainDocstring(e).docstringSummary))
|
||||
|
||||
d.tocSimple[k].add TocItem(
|
||||
sortName: sortName,
|
||||
@@ -1138,23 +1076,25 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
"itemSymOrID", symbolOrId.replace(",", ",<wbr>"),
|
||||
"itemSymOrIDEnc", symbolOrIdEnc])
|
||||
|
||||
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name,
|
||||
linkTitle = detailedName,
|
||||
linkDesc = xmltree.escape(plainDocstring.docstringSummary),
|
||||
line = n.info.line.int)
|
||||
# Ironically for types the complexSymbol is *cleaner* than the plainName
|
||||
# because it doesn't include object fields or documentation comments. So we
|
||||
# use the plain one for callable elements, and the complex for the rest.
|
||||
var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": "
|
||||
if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip))
|
||||
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
|
||||
|
||||
setIndexTerm(d[], external, symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
if k == skType and nameNode.kind == nkSym:
|
||||
d.types.strTableAdd nameNode.sym
|
||||
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
|
||||
if not isVisible(d, nameNode): return
|
||||
var
|
||||
name = getNameEsc(d, nameNode)
|
||||
name = getName(d, nameNode)
|
||||
comm = genRecComment(d, n)
|
||||
r: TSrcGen
|
||||
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
|
||||
if nonExports:
|
||||
renderFlags.incl renderNonExportedFields
|
||||
initTokRender(r, n, renderFlags)
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing})
|
||||
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm != nil:
|
||||
@@ -1339,13 +1279,12 @@ proc documentRaises*(cache: IdentCache; n: PNode) =
|
||||
if p5 != nil: n[pragmasPos].add p5
|
||||
if p6 != nil: n[pragmasPos].add p6
|
||||
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags = kDefault) =
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
|
||||
## Goes through nim nodes recursively and collects doc comments.
|
||||
## Main function for `doc`:option: command,
|
||||
## which is implemented in ``docgen2.nim``.
|
||||
template genItemAux(skind) =
|
||||
genItem(d, n, n[namePos], skind, docFlags)
|
||||
let showNonExports = optShowNonExportedFields in config.globalOptions
|
||||
case n.kind
|
||||
of nkPragma:
|
||||
let pragmaNode = findPragma(n, wDeprecated)
|
||||
@@ -1372,20 +1311,20 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
|
||||
if n[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n[i], n[i][0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags, showNonExports)
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags)
|
||||
of nkStmtList:
|
||||
for i in 0..<n.len: generateDoc(d, n[i], orig, config)
|
||||
for i in 0..<n.len: generateDoc(d, n[i], orig)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n[0][0]):
|
||||
generateDoc(d, lastSon(n[0]), orig, config)
|
||||
generateDoc(d, lastSon(n[0]), orig)
|
||||
of nkImportStmt:
|
||||
for it in n: traceDeps(d, it)
|
||||
of nkExportStmt:
|
||||
for it in n:
|
||||
if it.kind == nkSym:
|
||||
if d.module != nil and d.module == it.sym.owner:
|
||||
generateDoc(d, it.sym.ast, orig, config, kForceExport)
|
||||
generateDoc(d, it.sym.ast, orig, kForceExport)
|
||||
elif it.sym.ast != nil:
|
||||
exportSym(d, it.sym)
|
||||
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
|
||||
@@ -1398,31 +1337,9 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
|
||||
|
||||
proc overloadGroupName(s: string, k: TSymKind): string =
|
||||
## Turns a name like `f` into anchor `f-procs-all`
|
||||
#s & " " & k.toHumanStr & "s all"
|
||||
s & "-" & k.toHumanStr & "s-all"
|
||||
|
||||
proc setIndexTitle(d: PDoc, useMetaTitle: bool) =
|
||||
let titleKind = if d.standaloneDoc: ieMarkupTitle else: ieNimTitle
|
||||
let external = AbsoluteFile(d.destFile)
|
||||
.relativeTo(d.conf.outDir, '/')
|
||||
.changeFileExt(HtmlExt)
|
||||
.string
|
||||
var term, linkTitle: string
|
||||
if useMetaTitle and d.meta[metaTitle].len != 0:
|
||||
term = d.meta[metaTitleRaw]
|
||||
linkTitle = d.meta[metaTitleRaw]
|
||||
else:
|
||||
let filename = extractFilename(d.filename)
|
||||
term =
|
||||
if d.standaloneDoc: filename # keep .rst/.md extension
|
||||
else: changeFileExt(filename, "") # rm .nim extension
|
||||
linkTitle =
|
||||
if d.standaloneDoc: term # keep .rst/.md extension
|
||||
else: canonicalImport(d.conf, AbsoluteFile d.filename)
|
||||
if not d.standaloneDoc:
|
||||
linkTitle = "module " & linkTitle
|
||||
setIndexTerm(d[], titleKind, htmlFile = external, id = "",
|
||||
term = term, linkTitle = linkTitle)
|
||||
|
||||
proc finishGenerateDoc*(d: var PDoc) =
|
||||
## Perform 2nd RST pass for resolution of links/footnotes/headings...
|
||||
# copy file map `filenames` to ``rstgen.nim`` for its warnings
|
||||
@@ -1435,24 +1352,7 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
firstRst = fragment.rst
|
||||
break
|
||||
d.hasToc = d.hasToc or d.sharedState.hasToc
|
||||
# in --index:only mode we do NOT want to load other .idx, only write ours:
|
||||
let importdoc = optGenIndexOnly notin d.conf.globalOptions and
|
||||
optNoImportdoc notin d.conf.globalOptions
|
||||
preparePass2(d.sharedState, firstRst, importdoc)
|
||||
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
# Top-level doc.comments may contain titles and :idx: statements:
|
||||
for fragment in d.modDescPre:
|
||||
if fragment.isRst:
|
||||
traverseForIndex(d[], fragment.rst)
|
||||
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
|
||||
# Symbol-associated doc.comments may contain :idx: statements:
|
||||
for k in TSymKind:
|
||||
for _, overloadChoices in d.section[k].secItems:
|
||||
for item in overloadChoices:
|
||||
for fragment in item.descRst:
|
||||
if fragment.isRst:
|
||||
traverseForIndex(d[], fragment.rst)
|
||||
preparePass2(d.sharedState, firstRst)
|
||||
|
||||
# add anchors to overload groups before RST resolution
|
||||
for k in TSymKind:
|
||||
@@ -1462,25 +1362,13 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
let refn = overloadGroupName(plainName, k)
|
||||
let tooltip = "$1 ($2 overloads)" % [
|
||||
k.toHumanStr & " " & plainName, $overloadChoices.len]
|
||||
let name = nimIdentBackticksNormalize(plainName)
|
||||
# save overload group to ``.idx``
|
||||
let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').
|
||||
changeFileExt(HtmlExt).string
|
||||
setIndexTerm(d[], ieNimGroup, htmlFile = external, id = refn,
|
||||
term = name, linkTitle = k.toHumanStr,
|
||||
linkDesc = "", line = overloadChoices[0].info.line.int)
|
||||
if optGenIndexOnly in d.conf.globalOptions: continue
|
||||
addAnchorNim(d.sharedState, external=false, refn, tooltip,
|
||||
addAnchorNim(d.sharedState, refn, tooltip,
|
||||
LangSymbol(symKind: k.toHumanStr,
|
||||
name: name,
|
||||
name: nimIdentBackticksNormalize(plainName),
|
||||
isGroup: true),
|
||||
priority = symbolPriority(k),
|
||||
# select index `0` just to have any meaningful warning:
|
||||
info = overloadChoices[0].info,
|
||||
module = addRstFileIndex(d, FileIndex d.module.position))
|
||||
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
return
|
||||
info = overloadChoices[0].info)
|
||||
|
||||
# Finalize fragments of ``.nim`` or ``.rst`` file
|
||||
proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) =
|
||||
@@ -1533,13 +1421,10 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
|
||||
d.jEntriesFinal.add entry.json # generates docs
|
||||
|
||||
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
|
||||
completePass2(d.sharedState)
|
||||
|
||||
proc add(d: PDoc; j: JsonItem) =
|
||||
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
|
||||
|
||||
proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) =
|
||||
proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
|
||||
case n.kind
|
||||
of nkPragma:
|
||||
let doctypeNode = findPragma(n, wDoctype)
|
||||
@@ -1571,18 +1456,18 @@ proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool =
|
||||
if n[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
d.add genJsonItem(d, n[i], n[i][0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions)
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
for i in 0..<n.len:
|
||||
generateJson(d, n[i], config, includeComments)
|
||||
generateJson(d, n[i], includeComments)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n[0][0]):
|
||||
generateJson(d, lastSon(n[0]), config, includeComments)
|
||||
generateJson(d, lastSon(n[0]), includeComments)
|
||||
else: discard
|
||||
|
||||
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
|
||||
result = getNameEsc(d, nameNode) & "\n"
|
||||
result = getName(d, nameNode) & "\n"
|
||||
|
||||
proc generateTags*(d: PDoc, n: PNode, r: var string) =
|
||||
case n.kind
|
||||
@@ -1689,7 +1574,13 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
# Extract the title. Non API modules generate an entry in the index table.
|
||||
if d.meta[metaTitle].len != 0:
|
||||
title = d.meta[metaTitle]
|
||||
let external = AbsoluteFile(d.destFile)
|
||||
.relativeTo(d.conf.outDir, '/')
|
||||
.changeFileExt(HtmlExt)
|
||||
.string
|
||||
setIndexTerm(d[], external, "", title)
|
||||
else:
|
||||
# Modules get an automatic title for the HTML, but no entry in the index.
|
||||
title = canonicalImport(d.conf, AbsoluteFile d.filename)
|
||||
title = esc(d.target, title)
|
||||
var subtitle = ""
|
||||
@@ -1723,22 +1614,16 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
"moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", d.meta[metaAuthor],
|
||||
"version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics,
|
||||
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
"deprecationMsg", d.modDeprecationMsg]
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
|
||||
proc indexFile(d: PDoc): AbsoluteFile =
|
||||
let dir = d.conf.outDir
|
||||
result = dir / changeFileExt(presentationPath(d.conf,
|
||||
AbsoluteFile d.filename),
|
||||
IndexExt)
|
||||
let (finalDir, _, _) = result.string.splitFile
|
||||
createDir(finalDir)
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
let dest = indexFile(d)
|
||||
let dir = d.conf.outDir
|
||||
createDir(dir)
|
||||
let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt)
|
||||
writeIndexFile(d[], dest.string)
|
||||
|
||||
proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
|
||||
@@ -1749,9 +1634,6 @@ proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
|
||||
d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile
|
||||
|
||||
proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
d.conf.outFile = indexFile(d).relativeTo(d.conf.outDir) # just for display
|
||||
return
|
||||
runAllExamples(d)
|
||||
var content = genOutFile(d, groupedToc)
|
||||
if optStdout in d.conf.globalOptions:
|
||||
@@ -1816,7 +1698,7 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx, cache, conf)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(conf.projectFull, cache, conf, hasToc = true)
|
||||
generateDoc(d, ast, ast, conf)
|
||||
generateDoc(d, ast, ast)
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
@@ -1827,16 +1709,13 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
|
||||
var filen = addFileExt(filename, "txt")
|
||||
var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true,
|
||||
preferMarkdown = preferMarkdown, hasToc = false)
|
||||
try:
|
||||
let rst = parseRst(readFile(filen.string),
|
||||
line=LineRstInit, column=ColRstInit,
|
||||
conf, d.sharedState)
|
||||
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
except ERecoverableError:
|
||||
discard "already reported the error"
|
||||
let rst = parseRst(readFile(filen.string),
|
||||
line=LineRstInit, column=ColRstInit,
|
||||
conf, d.sharedState)
|
||||
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
|
||||
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef,
|
||||
preferMarkdown=false) =
|
||||
@@ -1855,7 +1734,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
status: int; content: string) {.gcsafe.} =
|
||||
localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1),
|
||||
warnUser, "the ':test:' attribute is not supported by this backend")
|
||||
generateJson(d, ast, conf)
|
||||
generateJson(d, ast)
|
||||
finishGenerateDoc(d)
|
||||
let json = d.jEntriesFinal
|
||||
let content = pretty(json)
|
||||
@@ -1867,7 +1746,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except IOError:
|
||||
except:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
@@ -1889,12 +1768,10 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except IOError:
|
||||
except:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
|
||||
if optGenIndexOnly in conf.globalOptions:
|
||||
return
|
||||
var content = mergeIndexes(dir)
|
||||
|
||||
var outFile = outFile
|
||||
@@ -1907,12 +1784,12 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
|
||||
"title", "Index",
|
||||
"subtitle", "", "tableofcontents", "", "moduledesc", "",
|
||||
"date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
"content", content, "author", "", "version", "", "analytics", ""]
|
||||
# no analytics because context is not available
|
||||
|
||||
try:
|
||||
writeFile(filename, code)
|
||||
except IOError:
|
||||
except:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
|
||||
@@ -1926,5 +1803,5 @@ proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile
|
||||
|
||||
try:
|
||||
writeFile(filename, $body)
|
||||
except IOError:
|
||||
except:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
options, ast, msgs, docgen, lineinfos, pathutils, packages
|
||||
options, ast, msgs, passes, docgen, lineinfos, pathutils, packages
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -38,25 +38,25 @@ template closeImpl(body: untyped) {.dirty.} =
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutput(g.doc, useWarning, groupedToc)
|
||||
|
||||
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutputJson(g.doc, useWarning)
|
||||
|
||||
proc processNode*(c: PPassContext, n: PNode): PNode =
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
if shouldProcess(g):
|
||||
generateDoc(g.doc, n, n, g.config)
|
||||
generateDoc(g.doc, n, n)
|
||||
|
||||
proc processNodeJson*(c: PPassContext, n: PNode): PNode =
|
||||
proc processNodeJson(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
if shouldProcess(g):
|
||||
generateJson(g.doc, n, g.config, false)
|
||||
generateJson(g.doc, n, false)
|
||||
|
||||
template myOpenImpl(ext: untyped) {.dirty.} =
|
||||
var g: PGen
|
||||
@@ -68,11 +68,20 @@ template myOpenImpl(ext: untyped) {.dirty.} =
|
||||
g.doc = d
|
||||
result = g
|
||||
|
||||
proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(HtmlExt)
|
||||
|
||||
proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc myOpenTex(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(TexExt)
|
||||
|
||||
proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc myOpenJson(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(JsonExt)
|
||||
|
||||
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
|
||||
const docgen2TexPass* = makePass(open = myOpenTex, process = processNode,
|
||||
close = close)
|
||||
const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson,
|
||||
close = closeJson)
|
||||
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
discard
|
||||
|
||||
@@ -6,12 +6,12 @@ when defined(nimPreviewSlimSystem):
|
||||
|
||||
|
||||
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
|
||||
result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info)
|
||||
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
|
||||
dest.typ = t
|
||||
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyString)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
@@ -67,12 +67,12 @@ proc searchObjCase(t: PType; field: PSym): PNode =
|
||||
doAssert result != nil
|
||||
|
||||
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
|
||||
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info)
|
||||
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
|
||||
dest.typ = field.typ
|
||||
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyUInt8)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
|
||||
@@ -77,7 +77,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||
theAddr = dllhandle.symAddr(name.cstring)
|
||||
if theAddr.isNil: globalError(conf, sym.info,
|
||||
"cannot import symbol: " & name & " from " & libPathMsg)
|
||||
result.intVal = cast[int](theAddr)
|
||||
result.intVal = cast[ByteAddress](theAddr)
|
||||
|
||||
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
|
||||
if t == nil: return addr libffi.type_void
|
||||
@@ -113,7 +113,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
|
||||
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
|
||||
template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v
|
||||
template `+!`(x, y: untyped): untyped =
|
||||
cast[pointer](cast[int](x) + y)
|
||||
cast[pointer](cast[ByteAddress](x) + y)
|
||||
|
||||
proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
|
||||
## computes the size of the blob
|
||||
@@ -369,13 +369,13 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
# in their unboxed representation so nothing it to be unpacked:
|
||||
result = n
|
||||
else:
|
||||
awi(nkPtrLit, cast[int](p))
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
of tyPtr, tyRef, tyVar, tyLent:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n == nil or n.kind == nkPtrLit:
|
||||
awi(nkPtrLit, cast[int](p))
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
elif n != nil and n.len == 1:
|
||||
internalAssert(conf, n.kind == nkRefTy)
|
||||
n[0] = unpack(conf, p, typ.lastSon, n[0])
|
||||
@@ -423,8 +423,8 @@ 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 sig: ParamList = default(ParamList)
|
||||
var cif: TCif
|
||||
var sig: ParamList
|
||||
# use the arguments' types for varargs support:
|
||||
for i in 1..<call.len:
|
||||
sig[i-1] = mapType(conf, call[i].typ)
|
||||
@@ -463,8 +463,8 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
info: TLineInfo): PNode =
|
||||
internalAssert conf, fn.kind == nkPtrLit
|
||||
|
||||
var cif: TCif = default(TCif)
|
||||
var sig: ParamList = default(ParamList)
|
||||
var cif: TCif
|
||||
var sig: ParamList
|
||||
for i in 0..len-1:
|
||||
var aTyp = args[i+start].typ
|
||||
if aTyp.isNil:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
|
||||
|
||||
type
|
||||
TemplCtx = object
|
||||
@@ -49,14 +49,13 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
|
||||
var x = PSym(idTableGet(c.mapping, s))
|
||||
if x == nil:
|
||||
x = copySym(s, c.idgen)
|
||||
x = copySym(s, nextSymId(c.idgen))
|
||||
# sem'check needs to set the owner properly later, see bug #9476
|
||||
x.owner = nil # c.genSymOwner
|
||||
#if x.kind == skParam and x.owner.kind == skModule:
|
||||
# internalAssert c.config, false
|
||||
idTablePut(c.mapping, s, x)
|
||||
if sfGenSym in s.flags:
|
||||
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
|
||||
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
|
||||
if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
|
||||
@@ -14,14 +14,12 @@
|
||||
|
||||
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
|
||||
|
||||
import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
|
||||
import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
|
||||
|
||||
import std / strutils except addf
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
import std/syncio
|
||||
|
||||
type
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
@@ -33,7 +31,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 +93,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 +120,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:
|
||||
@@ -331,9 +328,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
platform.OS[conf.target.targetOS].name & '.' &
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
if existsConfigVar(conf, fullCCname):
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
else:
|
||||
if result.len == 0:
|
||||
# not overridden for this cross compilation setting?
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
else:
|
||||
@@ -452,11 +447,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)
|
||||
@@ -538,7 +528,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
|
||||
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
|
||||
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
|
||||
# NOTE: should we need the full version, use -dumpfullversion
|
||||
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
|
||||
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1)
|
||||
if exitCode == 0:
|
||||
var major: int
|
||||
discard parseInt(s, major)
|
||||
@@ -586,7 +576,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
|
||||
compilePattern = joinPath(conf.cCompilerPath, exe)
|
||||
else:
|
||||
compilePattern = exe
|
||||
compilePattern = getCompilerExe(conf, c, isCpp)
|
||||
|
||||
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
|
||||
|
||||
@@ -840,22 +830,10 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
|
||||
else:
|
||||
writeFile(linkerArgs, args)
|
||||
try:
|
||||
when defined(macosx):
|
||||
execLinkCmd(conf, "xargs " & cmd.substr(0, last) & " < " & linkerArgs)
|
||||
else:
|
||||
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
|
||||
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
|
||||
finally:
|
||||
removeFile(linkerArgs)
|
||||
|
||||
proc linkViaShellScript(conf: ConfigRef; cmd: string) =
|
||||
let linkerScript = conf.projectName & "_" & "linkerScript.sh"
|
||||
writeFile(linkerScript, cmd)
|
||||
let shell = getEnv("SHELL")
|
||||
try:
|
||||
execLinkCmd(conf, shell & " " & linkerScript)
|
||||
finally:
|
||||
removeFile(linkerScript)
|
||||
|
||||
proc getObjFilePath(conf: ConfigRef, f: Cfile): string =
|
||||
if noAbsolutePaths(conf): f.obj.extractFilename
|
||||
else: f.obj.string
|
||||
@@ -873,20 +851,6 @@ proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
|
||||
else:
|
||||
result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name)
|
||||
|
||||
proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
|
||||
# Prevent linkcmd from exceeding the maximum command line length.
|
||||
# Windows's command line limit is about 8K (8191 characters) so C compilers on
|
||||
# Windows support a feature where the command line can be passed via ``@linkcmd``
|
||||
# to them.
|
||||
const MaxCmdLen = when defined(windows): 8_000 elif defined(macosx): 260_000 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
when defined(macosx):
|
||||
linkViaShellScript(conf, linkCmd)
|
||||
else:
|
||||
linkViaResponseFile(conf, linkCmd)
|
||||
else:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef) =
|
||||
var
|
||||
linkCmd: string
|
||||
@@ -963,7 +927,14 @@ proc callCCompiler*(conf: ConfigRef) =
|
||||
linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true)
|
||||
extraCmds = getExtraCmds(conf, mainOutput)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
preventLinkCmdMaxCmdLen(conf, linkCmd)
|
||||
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
|
||||
# Windows support a feature where the command line can be passed via ``@linkcmd``
|
||||
# to them.
|
||||
linkViaResponseFile(conf, linkCmd)
|
||||
else:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
for cmd in extraCmds:
|
||||
execExternalProgram(conf, cmd, hintExecuting)
|
||||
else:
|
||||
@@ -998,7 +969,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,14 +990,10 @@ 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)
|
||||
@@ -1051,7 +1018,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
var bcache: BuildCache
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except ValueError, KeyError, JsonKindError:
|
||||
except:
|
||||
let e = getCurrentException()
|
||||
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
|
||||
[e.msg, e.getStackTrace(), jsonFile.string]
|
||||
@@ -1068,7 +1035,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
cmds.add cmd
|
||||
prettyCmds.add displayProgressCC(conf, name, cmd)
|
||||
execCmdsInParallel(conf, cmds, prettyCb)
|
||||
preventLinkCmdMaxCmdLen(conf, bcache.linkcmd)
|
||||
execLinkCmd(conf, bcache.linkcmd)
|
||||
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
|
||||
|
||||
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
|
||||
|
||||
@@ -9,14 +9,12 @@
|
||||
|
||||
## Module that implements ``gorge`` for the compiler.
|
||||
|
||||
import msgs, os, osproc, streams, options,
|
||||
import msgs, std / sha1, os, osproc, streams, options,
|
||||
lineinfos, pathutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
proc readOutput(p: Process): (string, int) =
|
||||
result[0] = ""
|
||||
var output = p.outputStream
|
||||
|
||||
@@ -1047,12 +1047,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 =
|
||||
|
||||
@@ -50,10 +50,7 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
|
||||
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
|
||||
cgen.genTopLevelStmt(bmod, n)
|
||||
|
||||
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
if disps != nil:
|
||||
for disp in disps:
|
||||
genProcAux(bmod, disp.sym)
|
||||
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
|
||||
|
||||
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
|
||||
|
||||
@@ -7,15 +7,13 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import hashes, tables, intsets
|
||||
import hashes, tables, intsets, std/sha1
|
||||
import packed_ast, bitabs, rodfiles
|
||||
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
|
||||
pathutils, condsyms, packages, modulepaths]
|
||||
#import ".." / [renderer, astalgo]
|
||||
from os import removeFile, isAbsolute
|
||||
|
||||
import ../../dist/checksums/src/checksums/sha1
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions, formatfloat]
|
||||
|
||||
@@ -374,7 +372,7 @@ proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib
|
||||
if l.isNil: return
|
||||
result.kind = l.kind
|
||||
result.generated = l.generated
|
||||
result.isOverridden = l.isOverridden
|
||||
result.isOverriden = l.isOverriden
|
||||
result.name = toLitId($l.name, m)
|
||||
storeNode(result, l, path)
|
||||
|
||||
@@ -392,7 +390,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
|
||||
assert sfForward notin s.flags
|
||||
|
||||
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
|
||||
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
|
||||
position: s.position, offset: s.offset, options: s.options,
|
||||
name: s.name.s.toLitId(m))
|
||||
|
||||
storeNode(p, s, ast)
|
||||
@@ -421,7 +419,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 +766,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 +780,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)
|
||||
@@ -836,7 +830,6 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
options: s.options,
|
||||
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
|
||||
offset: if s.kind in routineKinds: defaultOffset else: s.offset,
|
||||
disamb: s.disamb,
|
||||
name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
|
||||
)
|
||||
|
||||
@@ -854,7 +847,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
if l.name.int == 0:
|
||||
result = nil
|
||||
else:
|
||||
result = PLib(generated: l.generated, isOverridden: l.isOverridden,
|
||||
result = PLib(generated: l.generated, isOverriden: l.isOverriden,
|
||||
kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
|
||||
loadAstBody(l, path)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ type
|
||||
PackedLib* = object
|
||||
kind*: TLibKind
|
||||
generated*: bool
|
||||
isOverridden*: bool
|
||||
isOverriden*: bool
|
||||
name*: LitId
|
||||
path*: NodeId
|
||||
|
||||
@@ -63,8 +63,7 @@ type
|
||||
alignment*: int # for alignment
|
||||
options*: TOptions
|
||||
position*: int
|
||||
offset*: int32
|
||||
disamb*: int32
|
||||
offset*: int
|
||||
externalName*: LitId # instead of TLoc
|
||||
locFlags*: TLocFlags
|
||||
annex*: PackedLib
|
||||
|
||||
@@ -141,7 +141,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")
|
||||
@@ -228,15 +228,10 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
|
||||
for i in 0..n.safeLen-1:
|
||||
importForwarded(c, n[i], exceptSet, fromMod, importSet)
|
||||
|
||||
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
|
||||
for i in 0..high(x):
|
||||
if x[i] == y: return
|
||||
x.add y
|
||||
|
||||
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
|
||||
result = realModule
|
||||
template createModuleAliasImpl(ident): untyped =
|
||||
createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options)
|
||||
createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options)
|
||||
if n.kind != nkImportAs: discard
|
||||
elif n.len != 2 or n[1].kind != nkIdent:
|
||||
localError(c.config, n.info, "module alias must be an identifier")
|
||||
@@ -250,7 +245,6 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
|
||||
result.options.incl optImportHidden
|
||||
c.unusedImports.add((result, n.info))
|
||||
c.importModuleMap[result.id] = realModule.id
|
||||
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
|
||||
|
||||
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
|
||||
var ret: typeof(result)
|
||||
@@ -304,15 +298,7 @@ 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)
|
||||
|
||||
@@ -337,26 +323,22 @@ proc evalImport*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkImportStmt, n.info)
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind in {nkInfix, nkPrefix} and it[^1].kind == nkBracket:
|
||||
let lastPos = it.len - 1
|
||||
var imp = copyNode(it)
|
||||
newSons(imp, it.len)
|
||||
for i in 0 ..< lastPos: imp[i] = it[i]
|
||||
imp[lastPos] = imp[0] # dummy entry, replaced in the loop
|
||||
for x in it[lastPos]:
|
||||
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
|
||||
let sep = it[0]
|
||||
let dir = it[1]
|
||||
var imp = newNodeI(nkInfix, it.info)
|
||||
imp.add sep
|
||||
imp.add dir
|
||||
imp.add sep # dummy entry, replaced in the loop
|
||||
for x in it[2]:
|
||||
# transform `a/b/[c as d]` to `/a/b/c as d`
|
||||
if x.kind == nkInfix and x[0].ident.s == "as":
|
||||
var impAs = copyNode(x)
|
||||
newSons(impAs, 3)
|
||||
impAs[0] = x[0]
|
||||
imp[lastPos] = x[1]
|
||||
let impAs = copyTree(x)
|
||||
imp[2] = x[1]
|
||||
impAs[1] = imp
|
||||
impAs[2] = x[2]
|
||||
impAs.info = x[2].info
|
||||
impMod(c, impAs, result)
|
||||
impMod(c, imp, result)
|
||||
else:
|
||||
imp[lastPos] = x
|
||||
imp.info = x.info
|
||||
imp[2] = x
|
||||
impMod(c, imp, result)
|
||||
else:
|
||||
impMod(c, it, result)
|
||||
|
||||
@@ -17,12 +17,12 @@ import
|
||||
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, lowerings, tables, modulegraphs,
|
||||
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
|
||||
varpartitions, aliasanalysis, dfa, wordrecg
|
||||
varpartitions, aliasanalysis, dfa
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
from trees import exprStructuralEquivalent, getRoot, whichPragma
|
||||
from trees import exprStructuralEquivalent, getRoot
|
||||
|
||||
type
|
||||
Con = object
|
||||
@@ -35,8 +35,6 @@ type
|
||||
idgen: IdGenerator
|
||||
body: PNode
|
||||
otherUsage: TLineInfo
|
||||
inUncheckedAssignSection: int
|
||||
inEnsureMove: int
|
||||
|
||||
Scope = object # we do scope-based memory management.
|
||||
# a scope is comparable to an nkStmtListExpr like
|
||||
@@ -67,11 +65,11 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
|
||||
result = ast.hasDestructor(t)
|
||||
when toDebug.len > 0:
|
||||
# for more effective debugging
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc}:
|
||||
assert(not containsGarbageCollectedRef(t))
|
||||
|
||||
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
|
||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info)
|
||||
sym.typ = typ
|
||||
s.vars.add(sym)
|
||||
result = newSymNode(sym)
|
||||
@@ -79,11 +77,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
proc nestedScope(parent: var Scope; body: PNode): Scope =
|
||||
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
|
||||
|
||||
type
|
||||
MoveOrCopyFlag = enum
|
||||
IsDecl, IsExplicitSink, IsReturn
|
||||
IsDecl, IsExplicitSink
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
|
||||
|
||||
@@ -161,8 +159,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
|
||||
@@ -186,16 +183,11 @@ proc isCursor(n: PNode): bool =
|
||||
template isUnpackedTuple(n: PNode): bool =
|
||||
## we move out all elements of unpacked tuples,
|
||||
## hence unpacked tuples themselves don't need to be destroyed
|
||||
## except it's already a cursor
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and
|
||||
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
|
||||
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
|
||||
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
|
||||
if inferredFromCopy:
|
||||
m.add ", which is inferred from unavailable '=copy'"
|
||||
|
||||
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
|
||||
if (opname == "=" or opname == "=copy") and ri != nil:
|
||||
m.add "; requires a copy because it's not the last read of '"
|
||||
m.add renderTree(ri)
|
||||
m.add '\''
|
||||
@@ -217,19 +209,15 @@ proc makePtrType(c: var Con, baseType: PType): PType =
|
||||
addSonSkipIntLit(result, baseType, c.idgen)
|
||||
|
||||
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
|
||||
var addrExp: PNode
|
||||
if op.typ != nil and op.typ.len > 1 and op.typ[1].kind != tyVar:
|
||||
addrExp = dest
|
||||
else:
|
||||
addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
addrExp.add(dest)
|
||||
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
addrExp.add(dest)
|
||||
result = newTree(nkCall, newSymNode(op), addrExp)
|
||||
|
||||
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||
var op = getAttachedOp(c.graph, t, kind)
|
||||
if op == nil or op.ast.isGenericRoutine:
|
||||
# give up and find the canonical type instead:
|
||||
let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||
if canon != nil:
|
||||
op = getAttachedOp(c.graph, canon, kind)
|
||||
@@ -260,20 +248,10 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
|
||||
proc isNoInit(dest: PNode): bool {.inline.} =
|
||||
result = dest.kind == nkSym and sfNoInit in dest.sym.flags
|
||||
|
||||
proc deepAliases(dest, ri: PNode): bool =
|
||||
case ri.kind
|
||||
of nkCallKinds, nkStmtListExpr, nkBracket, nkTupleConstr, nkObjConstr,
|
||||
nkCast, nkConv, nkObjUpConv, nkObjDownConv:
|
||||
for r in ri:
|
||||
if deepAliases(dest, r): return true
|
||||
return false
|
||||
else:
|
||||
return aliases(dest, ri) != no
|
||||
|
||||
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
|
||||
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
|
||||
isNoInit(dest) or IsReturn in flags:
|
||||
isNoInit(dest):
|
||||
# optimize sink call into a bitwise memcopy
|
||||
result = newTree(nkFastAsgn, dest, ri)
|
||||
else:
|
||||
@@ -284,19 +262,12 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
|
||||
else:
|
||||
# the default is to use combination of `=destroy(dest)` and
|
||||
# and copyMem(dest, source). This is efficient.
|
||||
if deepAliases(dest, ri):
|
||||
# consider: x = x + y, it is wrong to destroy the destination first!
|
||||
# tmp to support self assignments
|
||||
let tmp = c.getTemp(s, dest.typ, dest.info)
|
||||
result = newTree(nkStmtList, newTree(nkFastAsgn, tmp, dest), newTree(nkFastAsgn, dest, ri),
|
||||
c.genDestroy(tmp))
|
||||
else:
|
||||
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
|
||||
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
|
||||
|
||||
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,17 +284,16 @@ 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})
|
||||
if cyclicType(c.graph, t):
|
||||
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(t):
|
||||
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
|
||||
|
||||
proc genMarkCyclic(c: var Con; result, dest: PNode) =
|
||||
if c.graph.config.selectedGC == gcOrc:
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(c.graph, t):
|
||||
if cyclicType(t):
|
||||
if t.kind == tyRef:
|
||||
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
|
||||
else:
|
||||
@@ -337,9 +307,6 @@ proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
|
||||
assert ri.typ != nil
|
||||
|
||||
proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode =
|
||||
if c.inEnsureMove > 0:
|
||||
localError(c.graph.config, ri.info, errFailedMove, "cannot move '" & $ri &
|
||||
"', which introduces an implicit copy")
|
||||
let t = dest.typ
|
||||
if tfHasOwned in t.flags and ri.kind != nkNilLit:
|
||||
# try to improve the error message here:
|
||||
@@ -368,38 +335,30 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
|
||||
|
||||
if hasDestructor(c, objType):
|
||||
if getAttachedOp(c.graph, objType, attachedDestructor) != nil and
|
||||
sfOverridden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
|
||||
sfOverriden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
|
||||
localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor.
|
||||
It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""")
|
||||
result.add newTree(nkFastAsgn, le, tmp)
|
||||
return
|
||||
|
||||
# generate: if le != tmp: `=destroy`(le)
|
||||
if c.inUncheckedAssignSection != 0:
|
||||
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
|
||||
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
|
||||
cond.add le
|
||||
cond.add tmp
|
||||
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
|
||||
notExpr.add cond
|
||||
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
|
||||
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
|
||||
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
|
||||
cond.add le
|
||||
cond.add tmp
|
||||
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
|
||||
notExpr.add cond
|
||||
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
|
||||
result.add newTree(nkFastAsgn, le, tmp)
|
||||
|
||||
proc genWasMoved(c: var Con, n: PNode): PNode =
|
||||
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, n.typ, attachedWasMoved)
|
||||
if op != nil:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(n.typ, n, "=wasMoved")
|
||||
result = genOp(c, op, n)
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved)))
|
||||
result.add copyTree(n) #mWasMoved does not take the address
|
||||
#if n.kind != nkSym:
|
||||
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
|
||||
result.add copyTree(n) #mWasMoved does not take the address
|
||||
#if n.kind != nkSym:
|
||||
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
|
||||
|
||||
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
@@ -408,16 +367,13 @@ 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
|
||||
if not hasDestructor(c, n.typ):
|
||||
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
|
||||
result = copyTree(n)
|
||||
else:
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info)
|
||||
temp.typ = n.typ
|
||||
var v = newNodeI(nkLetSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -430,8 +386,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
|
||||
result.add v
|
||||
let nn = skipConv(n)
|
||||
if hasDestructor(c, n.typ):
|
||||
c.genMarkCyclic(result, nn)
|
||||
c.genMarkCyclic(result, nn)
|
||||
let wasMovedCall = c.genWasMoved(nn)
|
||||
result.add wasMovedCall
|
||||
result.add tempAsNode
|
||||
@@ -442,46 +397,21 @@ proc isCapturedVar(n: PNode): bool =
|
||||
|
||||
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 op = getAttachedOp(c.graph, typ, attachedDup)
|
||||
if op != nil and tfHasOwned notin typ.flags:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(nTyp, 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)
|
||||
|
||||
let src = p(n, c, s, normal)
|
||||
var newCall = newTreeIT(nkCall, src.info, src.typ,
|
||||
newSymNode(op),
|
||||
src)
|
||||
c.finishCopy(newCall, n, {}, isFromSink = true)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
newCall
|
||||
)
|
||||
else:
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
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:
|
||||
let tmp = c.getTemp(s, n.typ, n.info)
|
||||
if hasDestructor(c, n.typ):
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, isFromSink = true)
|
||||
result.add m
|
||||
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)
|
||||
if c.inEnsureMove > 0:
|
||||
localError(c.graph.config, n.info, errFailedMove,
|
||||
("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}:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc}:
|
||||
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 +427,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:
|
||||
@@ -515,14 +445,14 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
|
||||
# This was already done in the sink parameter handling logic.
|
||||
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
|
||||
let tmp = c.getTemp(s, arg.typ, arg.info)
|
||||
result.add c.genSink(s, tmp, arg, {IsDecl})
|
||||
result.add c.genSink(tmp, arg, {IsDecl})
|
||||
result.add tmp
|
||||
s.final.add c.genDestroy(tmp)
|
||||
else:
|
||||
result = arg
|
||||
|
||||
proc cycleCheck(n: PNode; c: var Con) =
|
||||
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
|
||||
if c.graph.config.selectedGC != gcArc: return
|
||||
var value = n[1]
|
||||
if value.kind == nkClosure:
|
||||
value = value[1]
|
||||
@@ -595,9 +525,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:
|
||||
@@ -725,24 +653,6 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = processCall(n[1][0], s)
|
||||
|
||||
of nkPragmaBlock:
|
||||
var inUncheckedAssignSection = 0
|
||||
let pragmaList = n[0]
|
||||
for pi in pragmaList:
|
||||
if whichPragma(pi) == wCast:
|
||||
case whichPragma(pi[1])
|
||||
of wUncheckedAssign:
|
||||
inUncheckedAssignSection = 1
|
||||
else:
|
||||
discard
|
||||
result = shallowCopy(n)
|
||||
inc c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||
for i in 0 ..< n.len-1:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
result[^1] = maybeVoid(n[^1], s)
|
||||
dec c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||
|
||||
else: assert(false)
|
||||
|
||||
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
@@ -755,7 +665,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,21 +680,9 @@ 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 =
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
|
||||
template process(child, s): untyped = p(child, c, s, mode)
|
||||
handleNestedTempl(n, process, tmpFlags = tmpFlags)
|
||||
elif mode == sinkArg:
|
||||
@@ -815,9 +713,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,7 +762,7 @@ 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:
|
||||
let inSpawn = c.inSpawn
|
||||
@@ -886,19 +781,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:
|
||||
@@ -906,17 +795,14 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
|
||||
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
|
||||
result[0] = copyTree(n[0])
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}:
|
||||
let destroyOld = c.genDestroy(result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
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:
|
||||
@@ -964,9 +850,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||
cycleCheck(n, c)
|
||||
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
|
||||
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
|
||||
if inReturn:
|
||||
flags.incl(IsReturn)
|
||||
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
|
||||
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
|
||||
elif isDiscriminantField(n[0]):
|
||||
result = c.genDiscriminantAsgn(s, n)
|
||||
@@ -986,7 +870,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
||||
result = shallowCopy(n)
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
@@ -1050,7 +934,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
of nkReturnStmt:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = p(n[i], c, s, mode, inReturn=true)
|
||||
result[i] = p(n[i], c, s, mode)
|
||||
s.needsTry = true
|
||||
of nkCast:
|
||||
result = shallowCopy(n)
|
||||
@@ -1068,7 +952,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
|
||||
proc sameLocation*(a, b: PNode): bool =
|
||||
proc sameConstant(a, b: PNode): bool =
|
||||
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
|
||||
a.kind in nkLiterals and a.intVal == b.intVal
|
||||
|
||||
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
|
||||
if a.kind in nkEndPoint and b.kind in nkEndPoint:
|
||||
@@ -1092,9 +976,9 @@ proc sameLocation*(a, b: PNode): bool =
|
||||
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
|
||||
else: false
|
||||
|
||||
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
# with side effects
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
|
||||
temp.typ = ri[1].typ
|
||||
var v = newNodeI(nkLetSection, ri[1].info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -1109,22 +993,14 @@ proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags:
|
||||
newAccess.add ri[0]
|
||||
newAccess.add tempAsNode
|
||||
|
||||
var snk = c.genSink(s, dest, newAccess, flags)
|
||||
var snk = c.genSink(dest, newAccess, flags)
|
||||
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
var ri = ri
|
||||
var isEnsureMove = 0
|
||||
if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mEnsureMove:
|
||||
ri = ri[1]
|
||||
isEnsureMove = 1
|
||||
if sameLocation(dest, ri):
|
||||
# rule (self-assignment-removal):
|
||||
result = newNodeI(nkEmpty, dest.info)
|
||||
elif isCursor(dest) or dest.typ.kind in {tyOpenArray, tyVarargs}:
|
||||
# hoisted openArray parameters might end up here
|
||||
# openArray types don't have a lifted assignment operation (it's empty)
|
||||
# bug #22132
|
||||
elif isCursor(dest):
|
||||
case ri.kind:
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
|
||||
@@ -1133,60 +1009,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
else:
|
||||
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
|
||||
else:
|
||||
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
|
||||
case ri2.kind
|
||||
case ri.kind
|
||||
of nkCallKinds:
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
of nkBracketExpr:
|
||||
if isUnpackedTuple(ri[0]):
|
||||
# unpacking of tuple: take over the elements
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s):
|
||||
if aliases(dest, ri) == no:
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
if isAtom(ri[1]):
|
||||
var snk = c.genSink(s, dest, ri, flags)
|
||||
var snk = c.genSink(dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
result = genFieldAccessSideEffects(c, s, dest, ri, flags)
|
||||
result = genFieldAccessSideEffects(c, dest, ri, flags)
|
||||
else:
|
||||
result = c.genSink(s, dest, destructiveMoveVar(ri, c, s), flags)
|
||||
result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags)
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
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):
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
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)
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
of nkSym:
|
||||
if isSinkParam(ri.sym) and isLastRead(ri, c, s):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
let snk = c.genSink(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):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
let snk = c.genSink(dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
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)
|
||||
result = c.genSink(dest, p(ri, c, s, sinkArg), flags)
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
|
||||
# We know the result will be a stmt so we use that fact to optimize
|
||||
@@ -1197,14 +1066,12 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
|
||||
canBeMoved(c, dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
let snk = c.genSink(dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
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
|
||||
@@ -65,12 +65,11 @@ Files: "compiler"
|
||||
Files: "doc"
|
||||
Files: "doc/html"
|
||||
Files: "tools"
|
||||
Files: "tools/debug/nim-gdb.py"
|
||||
Files: "tools/nim-gdb.py"
|
||||
Files: "nimpretty"
|
||||
Files: "testament"
|
||||
Files: "nimsuggest"
|
||||
Files: "nimsuggest/tests/*.nim"
|
||||
Files: "changelogs/*.md"
|
||||
|
||||
[Lib]
|
||||
Files: "lib"
|
||||
@@ -78,7 +77,6 @@ Files: "lib"
|
||||
[Other]
|
||||
Files: "examples"
|
||||
Files: "dist/nimble"
|
||||
Files: "dist/checksums"
|
||||
|
||||
Files: "tests"
|
||||
|
||||
@@ -92,7 +90,6 @@ Files: "bin/nimgrab.exe"
|
||||
Files: "bin/nimpretty.exe"
|
||||
Files: "bin/testament.exe"
|
||||
Files: "bin/nim-gdb.bat"
|
||||
Files: "bin/atlas.exe"
|
||||
|
||||
Files: "koch.exe"
|
||||
Files: "finish.exe"
|
||||
@@ -123,7 +120,6 @@ Files: "bin/nim"
|
||||
InstallScript: "yes"
|
||||
UninstallScript: "yes"
|
||||
Files: "bin/nim-gdb"
|
||||
Files: "build_all.sh"
|
||||
|
||||
|
||||
[InnoSetup]
|
||||
|
||||
@@ -33,27 +33,26 @@ template high*(t: typedesc[Int128]): Int128 = Max
|
||||
proc `$`*(a: Int128): string
|
||||
|
||||
proc toInt128*[T: SomeInteger | bool](arg: T): Int128 =
|
||||
{.noSideEffect.}:
|
||||
when T is bool: result.sdata(0) = int32(arg)
|
||||
elif T is SomeUnsignedInt:
|
||||
when sizeof(arg) <= 4:
|
||||
result.udata[0] = uint32(arg)
|
||||
else:
|
||||
result.udata[0] = uint32(arg and T(0xffffffff))
|
||||
result.udata[1] = uint32(arg shr 32)
|
||||
elif sizeof(arg) <= 4:
|
||||
result.sdata(0) = int32(arg)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(1) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
when T is bool: result.sdata(0) = int32(arg)
|
||||
elif T is SomeUnsignedInt:
|
||||
when sizeof(arg) <= 4:
|
||||
result.udata[0] = uint32(arg)
|
||||
else:
|
||||
let tmp = int64(arg)
|
||||
result.udata[0] = uint32(tmp and 0xffffffff)
|
||||
result.sdata(1) = int32(tmp shr 32)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
result.udata[0] = uint32(arg and T(0xffffffff))
|
||||
result.udata[1] = uint32(arg shr 32)
|
||||
elif sizeof(arg) <= 4:
|
||||
result.sdata(0) = int32(arg)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(1) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
else:
|
||||
let tmp = int64(arg)
|
||||
result.udata[0] = uint32(tmp and 0xffffffff)
|
||||
result.sdata(1) = int32(tmp shr 32)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
|
||||
template isNegative(arg: Int128): bool =
|
||||
arg.sdata(3) < 0
|
||||
|
||||
@@ -72,69 +72,6 @@ proc isValueOnlyType(t: PType): bool =
|
||||
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent}
|
||||
result = not types.searchTypeFor(t, wrap)
|
||||
|
||||
type
|
||||
SearchResult = enum
|
||||
NotFound, Abort, Found
|
||||
|
||||
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult
|
||||
|
||||
proc containsDangerousRefAux(n: PNode; marker: var IntSet): SearchResult =
|
||||
result = NotFound
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
result = containsDangerousRefAux(n[i], marker)
|
||||
if result == Found: return result
|
||||
of nkRecCase:
|
||||
assert(n[0].kind == nkSym)
|
||||
result = containsDangerousRefAux(n[0], marker)
|
||||
if result == Found: return result
|
||||
for i in 1..<n.len:
|
||||
case n[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = containsDangerousRefAux(lastSon(n[i]), marker)
|
||||
if result == Found: return result
|
||||
else: discard
|
||||
of nkSym:
|
||||
result = containsDangerousRefAux(n.sym.typ, marker)
|
||||
else: discard
|
||||
|
||||
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult =
|
||||
result = NotFound
|
||||
if t == nil: return result
|
||||
if containsOrIncl(marker, t.id): return result
|
||||
|
||||
if t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure):
|
||||
result = Found
|
||||
elif tfSendable in t.flags:
|
||||
result = Abort
|
||||
else:
|
||||
# continue the type traversal:
|
||||
result = NotFound
|
||||
|
||||
if result != NotFound: return result
|
||||
case t.kind
|
||||
of tyObject:
|
||||
if t[0] != nil:
|
||||
result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker)
|
||||
if result == NotFound: result = containsDangerousRefAux(t.n, marker)
|
||||
of tyGenericInst, tyDistinct, tyAlias, tySink:
|
||||
result = containsDangerousRefAux(lastSon(t), marker)
|
||||
of tyArray, tySet, tyTuple, tySequence:
|
||||
for i in 0..<t.len:
|
||||
result = containsDangerousRefAux(t[i], marker)
|
||||
if result == Found: return result
|
||||
else:
|
||||
discard
|
||||
|
||||
proc containsDangerousRef(t: PType): bool =
|
||||
# a `ref` type is "dangerous" if it occurs not within a type that is like `Isolated[T]`.
|
||||
# For example:
|
||||
# `ref int` # dangerous
|
||||
# `Isolated[ref int]` # not dangerous
|
||||
var marker = initIntSet()
|
||||
result = containsDangerousRefAux(t, marker) == Found
|
||||
|
||||
proc canAlias*(arg, ret: PType): bool =
|
||||
if isValueOnlyType(arg):
|
||||
# can alias only with addr(arg.x) and we don't care if it is not safe
|
||||
@@ -143,15 +80,12 @@ proc canAlias*(arg, ret: PType): bool =
|
||||
var marker = initIntSet()
|
||||
result = canAlias(arg, ret, marker)
|
||||
|
||||
const
|
||||
SomeVar = {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||
|
||||
proc containsVariable(n: PNode): bool =
|
||||
case n.kind
|
||||
of nodesToIgnoreSet:
|
||||
result = false
|
||||
of nkSym:
|
||||
result = n.sym.kind in SomeVar
|
||||
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||
else:
|
||||
for ch in n:
|
||||
if containsVariable(ch): return true
|
||||
@@ -175,7 +109,7 @@ proc checkIsolate*(n: PNode): bool =
|
||||
discard "fine, it is isolated already"
|
||||
else:
|
||||
let argType = n[i].typ
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
|
||||
if argType.canAlias(n.typ) or containsVariable(n[i]):
|
||||
# bug #19013: Alias information is not enough, we need to check for potential
|
||||
# "overlaps". I claim the problem can only happen by reading again from a location
|
||||
@@ -209,12 +143,6 @@ proc checkIsolate*(n: PNode): bool =
|
||||
result = checkIsolate(n[^1])
|
||||
else:
|
||||
result = false
|
||||
of nkSym:
|
||||
result = true
|
||||
if n.sym.kind in SomeVar:
|
||||
let argType = n.typ
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
|
||||
result = false
|
||||
else:
|
||||
# unanalysable expression:
|
||||
result = false
|
||||
|
||||
@@ -31,11 +31,9 @@ implements the required case distinction.
|
||||
import
|
||||
ast, trees, magicsys, options,
|
||||
nversion, msgs, idents, types,
|
||||
ropes, ccgutils, wordrecg, renderer,
|
||||
ropes, passes, ccgutils, wordrecg, renderer,
|
||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
|
||||
|
||||
import pipelineutils
|
||||
transf, injectdestructors, sourcemap, astmsgs
|
||||
|
||||
import json, sets, math, tables, intsets
|
||||
import strutils except addf
|
||||
@@ -50,7 +48,6 @@ type
|
||||
graph: ModuleGraph
|
||||
config: ConfigRef
|
||||
sigConflicts: CountTable[SigHash]
|
||||
initProc: PProc
|
||||
|
||||
BModule = ref TJSGen
|
||||
TJSTypeKind = enum # necessary JS "types"
|
||||
@@ -101,7 +98,6 @@ type
|
||||
prc: PSym
|
||||
globals, locals, body: Rope
|
||||
options: TOptions
|
||||
optionsStack: seq[TOptions]
|
||||
module: BModule
|
||||
g: PGlobals
|
||||
generatedParamCopies: IntSet
|
||||
@@ -111,7 +107,6 @@ type
|
||||
extraIndent: int
|
||||
up: PProc # up the call chain; required for closure support
|
||||
declaredGlobals: IntSet
|
||||
previousFileName: string # For frameInfo inside templates.
|
||||
|
||||
template config*(p: PProc): ConfigRef = p.module.config
|
||||
|
||||
@@ -159,8 +154,6 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||
options: TOptions): PProc =
|
||||
result = PProc(
|
||||
blocks: @[],
|
||||
optionsStack: if module.initProc != nil: module.initProc.optionsStack
|
||||
else: @[],
|
||||
options: options,
|
||||
module: module,
|
||||
procDef: procDef,
|
||||
@@ -268,7 +261,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
|
||||
if m.config.hcrOn:
|
||||
# When hot reloading is enabled, we must ensure that the names
|
||||
# of functions and types will be preserved across rebuilds:
|
||||
result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config))
|
||||
result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
|
||||
else:
|
||||
result.add("_")
|
||||
result.add(rope(s.id))
|
||||
@@ -559,36 +552,28 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
|
||||
r.res = frmt % [a, b, tmp, tmp2]
|
||||
r.kind = resExpr
|
||||
|
||||
proc unsignedTrimmer(size: BiggestInt): string =
|
||||
proc unsignedTrimmerJS(size: BiggestInt): Rope =
|
||||
case size
|
||||
of 1: "& 0xff"
|
||||
of 2: "& 0xffff"
|
||||
of 4: ">>> 0"
|
||||
else: ""
|
||||
of 1: rope"& 0xff"
|
||||
of 2: rope"& 0xffff"
|
||||
of 4: rope">>> 0"
|
||||
else: rope""
|
||||
|
||||
proc signedTrimmer(size: BiggestInt): string =
|
||||
# sign extension is done by shifting to the left and then back to the right
|
||||
"<< $1 >> $1" % [$(32 - size * 8)]
|
||||
|
||||
template unsignedTrimmer(size: BiggestInt): Rope =
|
||||
size.unsignedTrimmerJS
|
||||
|
||||
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
||||
reassign: static[bool] = false) =
|
||||
var x, y: TCompRes
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
let size = n[1].typ.skipTypes(abstractRange).size
|
||||
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
||||
when reassign:
|
||||
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
|
||||
if size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "$1 = BigInt.asUintN(64, ($4 $2 $3))" % [a, rope op, y.rdLoc, tmp]
|
||||
else:
|
||||
let trimmer = unsignedTrimmer(size)
|
||||
r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
|
||||
r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
|
||||
else:
|
||||
if size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "BigInt.asUintN(64, ($1 $2 $3))" % [x.rdLoc, rope op, y.rdLoc]
|
||||
else:
|
||||
let trimmer = unsignedTrimmer(size)
|
||||
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
|
||||
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
|
||||
r.kind = resExpr
|
||||
|
||||
template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
@@ -629,103 +614,32 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
template applyFormat(frmtA, frmtB) =
|
||||
if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
|
||||
|
||||
template bitwiseExpr(op: string) =
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
if typ.kind in {tyUInt, tyUInt32}:
|
||||
r.res = "(($1 $2 $3) >>> 0)" % [xLoc, op, yLoc]
|
||||
else:
|
||||
r.res = "($1 $2 $3)" % [xLoc, op, yLoc]
|
||||
|
||||
case op
|
||||
of mAddI:
|
||||
if i == 0:
|
||||
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
useMagic(p, "addInt64")
|
||||
applyFormat("addInt64($1, $2)")
|
||||
else:
|
||||
applyFormat("addInt($1, $2)")
|
||||
else:
|
||||
applyFormat("($1 + $2)")
|
||||
of mSubI:
|
||||
if i == 0:
|
||||
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
useMagic(p, "subInt64")
|
||||
applyFormat("subInt64($1, $2)")
|
||||
else:
|
||||
applyFormat("subInt($1, $2)")
|
||||
else:
|
||||
applyFormat("($1 - $2)")
|
||||
of mMulI:
|
||||
if i == 0:
|
||||
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
useMagic(p, "mulInt64")
|
||||
applyFormat("mulInt64($1, $2)")
|
||||
else:
|
||||
applyFormat("mulInt($1, $2)")
|
||||
else:
|
||||
applyFormat("($1 * $2)")
|
||||
of mDivI:
|
||||
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
useMagic(p, "divInt64")
|
||||
applyFormat("divInt64($1, $2)", "$1 / $2")
|
||||
else:
|
||||
applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
|
||||
of mModI:
|
||||
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
useMagic(p, "modInt64")
|
||||
applyFormat("modInt64($1, $2)", "$1 % $2")
|
||||
else:
|
||||
applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
|
||||
of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
|
||||
of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)")
|
||||
of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)")
|
||||
of mDivI: applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
|
||||
of mModI: 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 mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
|
||||
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
|
||||
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
|
||||
of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
|
||||
of mShrI:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))")
|
||||
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("($1 >> BigInt($2))")
|
||||
else:
|
||||
if typ.kind in {tyInt..tyInt32}:
|
||||
let trimmerU = unsignedTrimmer(typ.size)
|
||||
let trimmerS = signedTrimmer(typ.size)
|
||||
r.res = "((($1 $2) >>> $3) $4)" % [xLoc, trimmerU, yLoc, trimmerS]
|
||||
else:
|
||||
applyFormat("($1 >>> $2)")
|
||||
of mShrI: applyFormat("", "")
|
||||
of mShlI:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
if typ.size == 8:
|
||||
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asIntN(64, $1 << BigInt($2))")
|
||||
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asUintN(64, $1 << BigInt($2))")
|
||||
else:
|
||||
applyFormat("($1 * Math.pow(2, $2))")
|
||||
if n[1].typ.size <= 4:
|
||||
applyFormat("($1 << $2)", "($1 << $2)")
|
||||
else:
|
||||
if typ.kind in {tyUInt..tyUInt32}:
|
||||
let trimmer = unsignedTrimmer(typ.size)
|
||||
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
|
||||
else:
|
||||
let trimmer = signedTrimmer(typ.size)
|
||||
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
|
||||
applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))")
|
||||
of mAshrI:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
if typ.size == 8:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("($1 >> BigInt($2))")
|
||||
else:
|
||||
applyFormat("Math.floor($1 / Math.pow(2, $2))")
|
||||
if n[1].typ.size <= 4:
|
||||
applyFormat("($1 >> $2)", "($1 >> $2)")
|
||||
else:
|
||||
if typ.kind in {tyUInt..tyUInt32}:
|
||||
applyFormat("($1 >>> $2)")
|
||||
else:
|
||||
applyFormat("($1 >> $2)")
|
||||
of mBitandI: bitwiseExpr("&")
|
||||
of mBitorI: bitwiseExpr("|")
|
||||
of mBitxorI: bitwiseExpr("^")
|
||||
applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))")
|
||||
of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
|
||||
of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
|
||||
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
|
||||
of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
|
||||
of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
|
||||
of mAddU: applyFormat("", "")
|
||||
@@ -761,16 +675,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
|
||||
of mNot: applyFormat("!($1)", "!($1)")
|
||||
of mUnaryPlusI: applyFormat("+($1)", "+($1)")
|
||||
of mBitnotI:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
if typ.kind in {tyUInt..tyUInt64}:
|
||||
if typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
|
||||
applyFormat("BigInt.asUintN(64, ~($1))")
|
||||
else:
|
||||
let trimmer = unsignedTrimmer(typ.size)
|
||||
r.res = "(~($1) $2)" % [xLoc, trimmer]
|
||||
else:
|
||||
applyFormat("~($1)")
|
||||
of mBitnotI: applyFormat("~($1)", "~($1)")
|
||||
of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
|
||||
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
|
||||
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
|
||||
@@ -789,14 +694,17 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
of mMulU: binaryUintExpr(p, n, r, "*")
|
||||
of mDivU:
|
||||
binaryUintExpr(p, n, r, "/")
|
||||
if optJsBigInt64 notin p.config.globalOptions and
|
||||
n[1].typ.skipTypes(abstractRange).size == 8:
|
||||
# bigint / already truncates
|
||||
if n[1].typ.skipTypes(abstractRange).size == 8:
|
||||
r.res = "Math.trunc($1)" % [r.res]
|
||||
of mDivI:
|
||||
arithAux(p, n, r, op)
|
||||
of mModI:
|
||||
arithAux(p, n, r, op)
|
||||
of mShrI:
|
||||
var x, y: TCompRes
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc]
|
||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
arithAux(p, n, r, op)
|
||||
of mEqRef:
|
||||
@@ -824,16 +732,10 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||
let line = toLinenumber(n.info)
|
||||
if line < 0:
|
||||
return
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
lineF(p, "//$1$n", [sourceLine(p.config, n.info)])
|
||||
if optLineDir in p.options or optLineDir in p.config.options:
|
||||
lineF(p, "$1", [lineDir(p.config, n.info, line)])
|
||||
if hasFrameInfo(p):
|
||||
lineF(p, "F.line = $1;$n", [rope(line)])
|
||||
let currentFileName = toFilename(p.config, n.info)
|
||||
if p.previousFileName != currentFileName:
|
||||
lineF(p, "F.filename = $1;$n", [makeJSString(currentFileName)])
|
||||
p.previousFileName = currentFileName
|
||||
|
||||
proc genWhileStmt(p: PProc, n: PNode) =
|
||||
var cond: TCompRes
|
||||
@@ -896,7 +798,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
|
||||
@@ -1198,7 +1100,7 @@ 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
|
||||
@@ -1519,8 +1421,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:
|
||||
@@ -1850,25 +1759,15 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
|
||||
createRecordVarAux(p, t.n, excludedFieldIDs, output)
|
||||
t = t[0]
|
||||
|
||||
proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string =
|
||||
proc arrayTypeForElemType(typ: PType): string =
|
||||
let typ = typ.skipTypes(abstractRange)
|
||||
case typ.kind
|
||||
of tyInt, tyInt32: "Int32Array"
|
||||
of tyInt16: "Int16Array"
|
||||
of tyInt8: "Int8Array"
|
||||
of tyInt64:
|
||||
if optJsBigInt64 in conf.globalOptions:
|
||||
"BigInt64Array"
|
||||
else:
|
||||
""
|
||||
of tyUInt, tyUInt32: "Uint32Array"
|
||||
of tyUInt16: "Uint16Array"
|
||||
of tyUInt8, tyChar, tyBool: "Uint8Array"
|
||||
of tyUInt64:
|
||||
if optJsBigInt64 in conf.globalOptions:
|
||||
"BigUint64Array"
|
||||
else:
|
||||
""
|
||||
of tyFloat32: "Float32Array"
|
||||
of tyFloat64, tyFloat: "Float64Array"
|
||||
of tyEnum:
|
||||
@@ -1882,18 +1781,11 @@ proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string =
|
||||
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyInt8..tyInt32, tyUInt8..tyUInt32, tyEnum, tyChar:
|
||||
result = putToSeq("0", indirect)
|
||||
of tyInt, tyUInt:
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
|
||||
if $t.sym.loc.r == "bigint":
|
||||
result = putToSeq("0n", indirect)
|
||||
else:
|
||||
result = putToSeq("0", indirect)
|
||||
of tyInt64, tyUInt64:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
result = putToSeq("0n", indirect)
|
||||
else:
|
||||
result = putToSeq("0", indirect)
|
||||
of tyFloat..tyFloat128:
|
||||
result = putToSeq("0.0", indirect)
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
|
||||
@@ -1907,7 +1799,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
of tyArray:
|
||||
let length = toInt(lengthOrd(p.config, t))
|
||||
let e = elemType(t)
|
||||
let jsTyp = arrayTypeForElemType(p.config, e)
|
||||
let jsTyp = arrayTypeForElemType(e)
|
||||
if jsTyp.len > 0:
|
||||
result = "new $1($2)" % [rope(jsTyp), rope(length)]
|
||||
elif length > 32:
|
||||
@@ -1945,7 +1837,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:
|
||||
@@ -2082,11 +1974,7 @@ proc genNewSeq(p: PProc, n: PNode) =
|
||||
|
||||
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||
case skipTypes(n[1].typ, abstractVar + abstractRange).kind
|
||||
of tyEnum, tyInt..tyInt32, tyUInt..tyUInt32, tyChar: gen(p, n[1], r)
|
||||
of tyInt64, tyUInt64:
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
unaryExpr(p, n, r, "", "Number($1)")
|
||||
else: gen(p, n[1], r)
|
||||
of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r)
|
||||
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)")
|
||||
else: internalError(p.config, n.info, "genOrd")
|
||||
|
||||
@@ -2198,13 +2086,6 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
|
||||
genReset(p, n)
|
||||
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||
|
||||
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.kind = resVal
|
||||
r.res = p.getTemp()
|
||||
gen(p, n[1], a)
|
||||
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
|
||||
|
||||
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.res = rope("[")
|
||||
@@ -2316,34 +2197,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = "($1).length - 1" % [x.rdLoc]
|
||||
r.kind = resExpr
|
||||
of mInc:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
case typ.kind
|
||||
of tyUInt..tyUInt32:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
|
||||
binaryUintExpr(p, n, r, "+", true)
|
||||
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)
|
||||
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)
|
||||
else: binaryExpr(p, n, r, "addInt64", "$1 = addInt64($3, BigInt($2))", true)
|
||||
else:
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
|
||||
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true)
|
||||
of ast.mDec:
|
||||
let typ = n[1].typ.skipTypes(abstractVarRange)
|
||||
case typ.kind
|
||||
of tyUInt..tyUInt32:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
|
||||
binaryUintExpr(p, n, r, "-", true)
|
||||
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)
|
||||
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)
|
||||
else: binaryExpr(p, n, r, "subInt64", "$1 = subInt64($3, BigInt($2))", true)
|
||||
else:
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
|
||||
@@ -2399,10 +2260,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
of mMove:
|
||||
genMove(p, n, r)
|
||||
of mDup:
|
||||
genDup(p, n, r)
|
||||
of mEnsureMove:
|
||||
gen(p, n[1], r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
|
||||
@@ -2441,7 +2298,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
## Nim sequence maps to JS array.
|
||||
var t = skipTypes(n.typ, abstractInst)
|
||||
let e = elemType(t)
|
||||
let jsTyp = arrayTypeForElemType(p.config, e)
|
||||
let jsTyp = arrayTypeForElemType(e)
|
||||
if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0:
|
||||
# generate typed array
|
||||
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
|
||||
@@ -2522,29 +2379,7 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = "(!!($1))" % [r.res]
|
||||
r.kind = resExpr
|
||||
elif toInt:
|
||||
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number($1)" % [r.res]
|
||||
else:
|
||||
r.res = "(($1) | 0)" % [r.res]
|
||||
elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}:
|
||||
r.res = "BigInt($1)" % [r.res]
|
||||
elif src.kind in {tyFloat..tyFloat64}:
|
||||
r.res = "BigInt(Math.trunc($1))" % [r.res]
|
||||
elif src.kind == tyUInt64:
|
||||
r.res = "BigInt.asIntN(64, $1)" % [r.res]
|
||||
elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if fromUint or src.kind in {tyBool, tyChar, tyEnum}:
|
||||
r.res = "BigInt($1)" % [r.res]
|
||||
elif fromInt: # could be negative
|
||||
r.res = "BigInt.asUintN(64, BigInt($1))" % [r.res]
|
||||
elif src.kind in {tyFloat..tyFloat64}:
|
||||
r.res = "BigInt.asUintN(64, BigInt(Math.trunc($1)))" % [r.res]
|
||||
elif src.kind == tyInt64:
|
||||
r.res = "BigInt.asUintN(64, $1)" % [r.res]
|
||||
elif toUint or dest.kind in tyFloat..tyFloat64:
|
||||
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number($1)" % [r.res]
|
||||
r.res = "(($1) | 0)" % [r.res]
|
||||
else:
|
||||
# TODO: What types must we handle here?
|
||||
discard
|
||||
@@ -2555,11 +2390,7 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
|
||||
var a, b: TCompRes
|
||||
gen(p, n[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
|
||||
if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "XXX maybe emit masking instructions here"
|
||||
else:
|
||||
@@ -2653,18 +2484,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
if prc.typ[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast[resultPos].sym
|
||||
let mname = mangleName(p.module, resultSym)
|
||||
# otherwise uses "fat pointers"
|
||||
let useRawPointer = not isIndirect(resultSym) and
|
||||
let returnAddress = not isIndirect(resultSym) and
|
||||
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
|
||||
mapType(p, resultSym.typ) == etyBaseIndex
|
||||
if useRawPointer:
|
||||
if returnAddress:
|
||||
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
|
||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||
else:
|
||||
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
|
||||
gen(p, prc.ast[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
if returnAddress:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
@@ -2726,14 +2556,9 @@ proc genStmt(p: PProc, n: PNode) =
|
||||
if r.res != "": lineF(p, "$#;$n", [r.res])
|
||||
|
||||
proc genPragma(p: PProc, n: PNode) =
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
for it in n.sons:
|
||||
case whichPragma(it)
|
||||
of wEmit: genAsmOrEmitStmt(p, it[1])
|
||||
of wPush:
|
||||
processPushBackendOption(p.optionsStack, p.options, n, i+1)
|
||||
of wPop:
|
||||
processPopBackendOption(p.optionsStack, p.options)
|
||||
else: discard
|
||||
|
||||
proc genCast(p: PProc, n: PNode, r: var TCompRes) =
|
||||
@@ -2748,35 +2573,24 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let fromInt = (src.kind in tyInt..tyInt32)
|
||||
let fromUint = (src.kind in tyUInt..tyUInt32)
|
||||
|
||||
if toUint:
|
||||
if fromInt or fromUint:
|
||||
r.res = "Number(BigInt.asUintN($1, BigInt($2)))" % [$(dest.size * 8), r.res]
|
||||
elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res]
|
||||
if toUint and (fromInt or fromUint):
|
||||
let trimmer = unsignedTrimmer(dest.size)
|
||||
r.res = "($1 $2)" % [r.res, trimmer]
|
||||
elif toInt:
|
||||
if fromInt or fromUint:
|
||||
r.res = "Number(BigInt.asIntN($1, BigInt($2)))" % [$(dest.size * 8), r.res]
|
||||
elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number(BigInt.asIntN($1, $2))" % [$(dest.size * 8), r.res]
|
||||
elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}:
|
||||
r.res = "BigInt($1)" % [r.res]
|
||||
elif src.kind in {tyFloat..tyFloat64}:
|
||||
r.res = "BigInt(Math.trunc($1))" % [r.res]
|
||||
elif src.kind == tyUInt64:
|
||||
r.res = "BigInt.asIntN(64, $1)" % [r.res]
|
||||
elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
|
||||
if fromUint or src.kind in {tyBool, tyChar, tyEnum}:
|
||||
r.res = "BigInt($1)" % [r.res]
|
||||
elif fromInt: # could be negative
|
||||
r.res = "BigInt.asUintN(64, BigInt($1))" % [r.res]
|
||||
elif src.kind in {tyFloat..tyFloat64}:
|
||||
r.res = "BigInt.asUintN(64, BigInt(Math.trunc($1)))" % [r.res]
|
||||
elif src.kind == tyInt64:
|
||||
r.res = "BigInt.asUintN(64, $1)" % [r.res]
|
||||
elif dest.kind in tyFloat..tyFloat64:
|
||||
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
|
||||
r.res = "Number($1)" % [r.res]
|
||||
if fromInt:
|
||||
return
|
||||
elif fromUint:
|
||||
if src.size == 4 and dest.size == 4:
|
||||
# XXX prevent multi evaluations
|
||||
r.res = "($1 | 0)" % [r.res]
|
||||
else:
|
||||
let trimmer = unsignedTrimmer(dest.size)
|
||||
let minuend = case dest.size
|
||||
of 1: "0xfe"
|
||||
of 2: "0xfffe"
|
||||
of 4: "0xfffffffe"
|
||||
else: ""
|
||||
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
|
||||
elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
|
||||
r.address = r.res
|
||||
r.res = "null"
|
||||
@@ -2795,25 +2609,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkSym:
|
||||
genSym(p, n, r)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case n.typ.skipTypes(abstractVarRange).kind
|
||||
of tyBool:
|
||||
if n.typ.kind == tyBool:
|
||||
r.res = if n.intVal == 0: rope"false" else: rope"true"
|
||||
of tyUInt64:
|
||||
r.res = rope($cast[BiggestUInt](n.intVal))
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
r.res.add('n')
|
||||
of tyInt64:
|
||||
let wrap = n.intVal < 0 # wrap negative integers with parens
|
||||
if wrap: r.res.add '('
|
||||
r.res.addInt n.intVal
|
||||
if optJsBigInt64 in p.config.globalOptions:
|
||||
r.res.add('n')
|
||||
if wrap: r.res.add ')'
|
||||
else:
|
||||
let wrap = n.intVal < 0 # wrap negative integers with parens
|
||||
if wrap: r.res.add '('
|
||||
r.res.addInt n.intVal
|
||||
if wrap: r.res.add ')'
|
||||
r.res = rope(n.intVal)
|
||||
r.kind = resExpr
|
||||
of nkNilLit:
|
||||
if isEmptyType(n.typ):
|
||||
@@ -3007,7 +2806,7 @@ proc genModule(p: PProc, n: PNode) =
|
||||
if p.config.hcrOn and n.kind == nkStmtList:
|
||||
let moduleSym = p.module.module
|
||||
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
|
||||
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts, p.config)
|
||||
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts)
|
||||
lineF(p, "var $1;$n", [moduleLoadedVar])
|
||||
var inGuardedBlock = false
|
||||
|
||||
@@ -3024,15 +2823,14 @@ proc genModule(p: PProc, n: PNode) =
|
||||
if optStackTrace in p.options:
|
||||
p.body.add(frameDestroy(p))
|
||||
|
||||
proc processJSCodeGen*(b: PPassContext, n: PNode): PNode =
|
||||
proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
## Generate JS code for a node.
|
||||
result = n
|
||||
let m = BModule(b)
|
||||
if pipelineutils.skipCodegen(m.config, n): return n
|
||||
if passes.skipCodegen(m.config, n): return n
|
||||
if m.module == nil: internalError(m.config, n.info, "myProcess")
|
||||
let globals = PGlobals(m.graph.backend)
|
||||
var p = newInitProc(globals, m)
|
||||
m.initProc = p
|
||||
p.unique = globals.unique
|
||||
genModule(p, n)
|
||||
p.g.code.add(p.locals)
|
||||
@@ -3046,7 +2844,7 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
|
||||
var p = newInitProc(globals, m)
|
||||
attachProc(p, prc)
|
||||
|
||||
var disp = generateMethodDispatchers(graph, m.idgen)
|
||||
var disp = generateMethodDispatchers(graph)
|
||||
for i in 0..<disp.len:
|
||||
let prc = disp[i].sym
|
||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||
@@ -3064,7 +2862,7 @@ proc getClassName(t: PType): Rope =
|
||||
if s.loc.r != "": result = s.loc.r
|
||||
else: result = rope(s.name.s)
|
||||
|
||||
proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
## Finalize JS code generation of a Nim module.
|
||||
## Param `n` may contain nodes returned from the last module close call.
|
||||
var m = BModule(b)
|
||||
@@ -3074,14 +2872,14 @@ proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
for i in countdown(high(graph.globalDestructors), 0):
|
||||
n.add graph.globalDestructors[i]
|
||||
# Process any nodes left over from the last call to `myClose`.
|
||||
result = processJSCodeGen(b, n)
|
||||
result = myProcess(b, n)
|
||||
# Some codegen is different (such as no stacktraces; see `initProcOptions`)
|
||||
# when `std/system` is being processed.
|
||||
if sfSystemModule in m.module.flags:
|
||||
PGlobals(graph.backend).inSystem = false
|
||||
# Check if codegen should continue before any files are generated.
|
||||
# It may bail early is if too many errors have been raised.
|
||||
if pipelineutils.skipCodegen(m.config, n): return n
|
||||
if passes.skipCodegen(m.config, n): return n
|
||||
# Nim modules are compiled into a single JS file.
|
||||
# If this is the main module, then this is the final call to `myClose`.
|
||||
if sfMainModule in m.module.flags:
|
||||
@@ -3099,6 +2897,9 @@ proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
if not writeRope(code, outFile):
|
||||
rawMessage(m.config, errCannotOpenFile, outFile.string)
|
||||
|
||||
proc setupJSgen*(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
|
||||
## Create the JS backend pass context `BModule` for a Nim module.
|
||||
result = newModule(graph, s)
|
||||
result.idgen = idgen
|
||||
|
||||
const JSgenPass* = makePass(myOpen, myProcess, myClose)
|
||||
|
||||
@@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet, tyOpenArray:
|
||||
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet:
|
||||
var s =
|
||||
"var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
|
||||
@@ -140,7 +140,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
|
||||
rawAddSon(result, intType)
|
||||
|
||||
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
|
||||
result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info)
|
||||
result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info)
|
||||
result.typ = createClosureIterStateType(g, iter, idgen)
|
||||
|
||||
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
|
||||
@@ -154,7 +154,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
|
||||
result = iter.ast[resultPos].sym
|
||||
else:
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
|
||||
result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {})
|
||||
result.typ = iter.typ[0]
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
@@ -258,7 +258,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:
|
||||
@@ -266,7 +267,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
|
||||
addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen)
|
||||
env = indirectAccess(newSymNode(it), hp, hp.info)
|
||||
else:
|
||||
let e = newSym(skLet, iter.name, idgen, owner, n.info)
|
||||
let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info)
|
||||
e.typ = hp.typ
|
||||
e.flags = hp.flags
|
||||
env = newSymNode(e)
|
||||
@@ -292,26 +293,23 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner:
|
||||
|
||||
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
let s = n.sym
|
||||
let isEnv = s.name.id == getIdent(g.cache, ":env").id
|
||||
if illegalCapture(s):
|
||||
localError(g.config, n.info,
|
||||
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
|
||||
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
|
||||
" Consider using a <ref $2> which can be captured.") %
|
||||
[s.name.s, typeToString(s.typ), g.config$s.info])
|
||||
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
|
||||
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
|
||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
[s.name.s, owner.name.s, $owner.typ.callConv])
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
if not isEnv:
|
||||
owner.typ.callConv = ccClosure
|
||||
owner.typ.callConv = ccClosure
|
||||
|
||||
type
|
||||
DetectionPass = object
|
||||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo: bool
|
||||
inTypeOf: bool
|
||||
graph: ModuleGraph
|
||||
idgen: IdGenerator
|
||||
|
||||
@@ -382,7 +380,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
|
||||
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info)
|
||||
let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info)
|
||||
result.typ = fieldType
|
||||
when false:
|
||||
if c.graph.config.selectedGC == gcDestructors:
|
||||
@@ -415,15 +413,12 @@ 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
|
||||
let t = c.getEnvTypeForOwner(owner, info)
|
||||
if cp == nil:
|
||||
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
|
||||
cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = t
|
||||
addHiddenParam(fn, cp)
|
||||
@@ -449,15 +444,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
let body = transformBody(c.graph, c.idgen, s, useCache)
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
|
||||
let interested = interestingVar(s)
|
||||
if ow == owner:
|
||||
if owner.isIterator:
|
||||
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})
|
||||
|
||||
@@ -466,7 +458,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
else:
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# direct or indirect dependency:
|
||||
elif innerClosure or interested:
|
||||
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
|
||||
discard """
|
||||
proc outer() =
|
||||
var x: int
|
||||
@@ -483,12 +475,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 +510,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
|
||||
@@ -560,7 +545,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
result = n
|
||||
|
||||
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode =
|
||||
var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info)
|
||||
var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = typ
|
||||
result = newSymNode(v)
|
||||
@@ -584,7 +569,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass;
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen)
|
||||
c.envVars[owner.id] = result
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info)
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = envVarType
|
||||
c.unownedEnvVars[owner.id] = newSymNode(v)
|
||||
@@ -668,7 +653,7 @@ proc closureCreationForIter(iter: PNode;
|
||||
d: var DetectionPass; c: var LiftingPass): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
|
||||
let owner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
|
||||
var vnode: PNode
|
||||
@@ -807,8 +792,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:
|
||||
@@ -876,7 +859,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
idgen: IdGenerator, force: bool): PNode =
|
||||
idgen: IdGenerator): PNode =
|
||||
# XXX backend == backendJs does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
@@ -885,7 +868,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
g.config.backend == backendJs and not isCompileTime) or
|
||||
(fn.skipGenericOwner.kind != skModule and not force):
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
@@ -960,7 +943,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
|
||||
let iter = op.sym
|
||||
|
||||
let hp = getHiddenParam(g, iter)
|
||||
env = newSym(skLet, iter.name, idgen, owner, body.info)
|
||||
env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info)
|
||||
env.typ = hp.typ
|
||||
env.flags = hp.flags
|
||||
|
||||
@@ -988,15 +971,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
|
||||
|
||||
@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of openPars:
|
||||
if tsLeading in tok.spacing and not em.endsInWhite and
|
||||
if tok.strongSpaceA and not em.endsInWhite and
|
||||
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
|
||||
wrSpace em
|
||||
wr(em, $tok.tokType, ltSomeParLe)
|
||||
@@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
wr(em, $tok.tokType, ltOther)
|
||||
if not em.inquote: wrSpace(em)
|
||||
of tkOpr, tkDotDot:
|
||||
if em.inquote or (tok.spacing == {} and
|
||||
if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
|
||||
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
|
||||
# bug #9504: remember to not spacify a keyword:
|
||||
lastTokWasTerse = true
|
||||
@@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
if not em.endsInWhite: wrSpace(em)
|
||||
wr(em, tok.ident.s, ltOpr)
|
||||
template isUnary(tok): bool =
|
||||
tok.spacing == {tsLeading}
|
||||
tok.strongSpaceB == tsNone and tok.strongSpaceA
|
||||
|
||||
if not isUnary(tok):
|
||||
rememberSplit(splitBinary)
|
||||
|
||||
@@ -23,6 +23,7 @@ when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, formatfloat]
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||
@@ -93,18 +94,19 @@ type
|
||||
base2, base8, base16
|
||||
|
||||
TokenSpacing* = enum
|
||||
tsLeading, tsTrailing, tsEof
|
||||
tsNone, tsTrailing, tsEof
|
||||
|
||||
Token* = object # a Nim token
|
||||
tokType*: TokType # the type of the token
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
spacing*: set[TokenSpacing] # spaces around token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
# preceded with indentation
|
||||
ident*: PIdent # the parsed identifier
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
strongSpaceA*: bool # leading spaces of an operator
|
||||
strongSpaceB*: TokenSpacing # trailing spaces of an operator
|
||||
literal*: string # the parsed (string) literal; and
|
||||
# documentation comments are here too
|
||||
line*, col*: int
|
||||
@@ -125,8 +127,6 @@ type
|
||||
cache*: IdentCache
|
||||
when defined(nimsuggest):
|
||||
previousToken: TLineInfo
|
||||
tokenEnd*: TLineInfo
|
||||
previousTokenEnd*: TLineInfo
|
||||
config*: ConfigRef
|
||||
|
||||
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
|
||||
@@ -176,7 +176,7 @@ proc initToken*(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.spacing = {}
|
||||
L.strongSpaceA = false
|
||||
L.literal = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -189,7 +189,7 @@ proc fillToken(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.spacing = {}
|
||||
L.strongSpaceA = false
|
||||
setLen(L.literal, 0)
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -735,6 +735,10 @@ proc handleCRLF(L: var Lexer, pos: int): int =
|
||||
template registerLine =
|
||||
let col = L.getColNumber(pos)
|
||||
|
||||
when not defined(nimpretty):
|
||||
if col > MaxLineLength:
|
||||
lexMessagePos(L, hintLineTooLong, pos)
|
||||
|
||||
case L.buf[pos]
|
||||
of CR:
|
||||
registerLine()
|
||||
@@ -954,15 +958,13 @@ proc getOperator(L: var Lexer, tok: var Token) =
|
||||
tokenEnd(tok, pos-1)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceding spaces:
|
||||
tok.spacing = tok.spacing - {tsTrailing, tsEof}
|
||||
var trailing = false
|
||||
tok.strongSpaceB = tsNone
|
||||
while L.buf[pos] == ' ':
|
||||
inc pos
|
||||
trailing = true
|
||||
if tok.strongSpaceB != tsTrailing:
|
||||
tok.strongSpaceB = tsTrailing
|
||||
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tok.spacing.incl(tsEof)
|
||||
elif trailing:
|
||||
tok.spacing.incl(tsTrailing)
|
||||
tok.strongSpaceB = tsEof
|
||||
|
||||
proc getPrecedence*(tok: Token): int =
|
||||
## Calculates the precedence of the given token.
|
||||
@@ -1073,6 +1075,7 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
when defined(nimpretty): tok.literal.add "\L"
|
||||
if isDoc:
|
||||
when not defined(nimpretty): tok.literal.add "\n"
|
||||
inc tok.iNumber
|
||||
var c = toStrip
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
@@ -1091,6 +1094,8 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
proc scanComment(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tok.tokType = tkComment
|
||||
# iNumber contains the number of '\n' in the token
|
||||
tok.iNumber = 0
|
||||
assert L.buf[pos+1] == '#'
|
||||
when defined(nimpretty):
|
||||
tok.commentOffsetA = L.offsetBase + pos
|
||||
@@ -1133,6 +1138,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
dec c
|
||||
inc tok.iNumber
|
||||
else:
|
||||
if L.buf[pos] > ' ':
|
||||
L.indentAhead = indent
|
||||
@@ -1145,7 +1151,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
proc skip(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tokenBegin(tok, pos)
|
||||
tok.spacing.excl(tsLeading)
|
||||
tok.strongSpaceA = false
|
||||
when defined(nimpretty):
|
||||
var hasComment = false
|
||||
var commentIndent = L.currLineIndent
|
||||
@@ -1156,7 +1162,8 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
case L.buf[pos]
|
||||
of ' ':
|
||||
inc(pos)
|
||||
tok.spacing.incl(tsLeading)
|
||||
if not tok.strongSpaceA:
|
||||
tok.strongSpaceA = true
|
||||
of '\t':
|
||||
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
|
||||
inc(pos)
|
||||
@@ -1178,7 +1185,7 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
pos = L.bufpos
|
||||
else:
|
||||
break
|
||||
tok.spacing.excl(tsLeading)
|
||||
tok.strongSpaceA = false
|
||||
when defined(nimpretty):
|
||||
if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent
|
||||
if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'):
|
||||
@@ -1217,10 +1224,6 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
template atTokenEnd() {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
L.previousTokenEnd.line = L.tokenEnd.line
|
||||
L.previousTokenEnd.col = L.tokenEnd.col
|
||||
L.tokenEnd.line = tok.line.uint16
|
||||
L.tokenEnd.col = getColNumber(L, L.bufpos).int16
|
||||
# we attach the cursor to the last *strong* token
|
||||
if tok.tokType notin weakTokens:
|
||||
L.previousToken.line = tok.line.uint16
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## This module implements lifting for type-bound operations
|
||||
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
|
||||
## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``).
|
||||
|
||||
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
|
||||
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
|
||||
@@ -34,7 +34,6 @@ type
|
||||
|
||||
template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
|
||||
template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
|
||||
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
|
||||
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
||||
@@ -50,9 +49,9 @@ proc at(a, i: PNode, elemType: PType): PNode =
|
||||
result[1] = i
|
||||
result.typ = elemType
|
||||
|
||||
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
|
||||
proc destructorOverriden(g: ModuleGraph; t: PType): bool =
|
||||
let op = getAttachedOp(g, t, attachedDestructor)
|
||||
op != nil and sfOverridden in op.flags
|
||||
op != nil and sfOverriden in op.flags
|
||||
|
||||
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
for i in 0..<t.len:
|
||||
@@ -83,14 +82,12 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
|
||||
result = genBuiltin(c.g, c.idgen, magic, name, i)
|
||||
|
||||
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
|
||||
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
|
||||
body.add newAsgnStmt(x, y)
|
||||
elif c.kind == attachedDestructor and c.addMemReset:
|
||||
let call = genBuiltin(c, mDefault, "default", x)
|
||||
call.typ = t
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif c.kind == attachedWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
|
||||
if x.kind == nkHiddenDeref:
|
||||
@@ -140,34 +137,25 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
|
||||
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
|
||||
destroy.add(newSymNode(op))
|
||||
if op.typ[1].kind != tyVar:
|
||||
destroy.add x
|
||||
else:
|
||||
destroy.add genAddr(c, x)
|
||||
destroy.add genAddr(c, x)
|
||||
if sfNeverRaises notin op.flags:
|
||||
c.canRaise = true
|
||||
if c.addMemReset:
|
||||
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
|
||||
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x))
|
||||
else:
|
||||
result = destroy
|
||||
|
||||
proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
result = newNodeIT(nkCall, x.info, op.typ[0])
|
||||
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, 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 +194,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,38 +205,14 @@ 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:
|
||||
# destroys in reverse order #24719
|
||||
if c.kind == attachedDestructor:
|
||||
for i in countdown(n.len-1, 0):
|
||||
fillBodyObj(c, n[i], body, x, y, enforceDefaultOp, enforceWasMoved)
|
||||
else:
|
||||
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) =
|
||||
template fillBase =
|
||||
if t.len > 0 and t[0] != nil:
|
||||
let dest = newNodeIT(nkHiddenSubConv, c.info, t[0])
|
||||
dest.add newNodeI(nkEmpty, c.info)
|
||||
dest.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, dest, src)
|
||||
template fillFields =
|
||||
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
|
||||
|
||||
if c.kind == attachedDestructor:
|
||||
# destroys in reverse order #24719
|
||||
fillFields()
|
||||
fillBase()
|
||||
else:
|
||||
fillBase()
|
||||
fillFields()
|
||||
if t.len > 0 and t[0] != nil:
|
||||
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) =
|
||||
var hasCase = isCaseObj(t.n)
|
||||
@@ -272,7 +236,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
# for every field (dependent on dest.kind):
|
||||
# `=` dest.field, src.field
|
||||
# =destroy(blob)
|
||||
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
|
||||
dummy.typ = y.typ
|
||||
if ccgIntroducedPtr(c.g.config, dummy, y.typ):
|
||||
# Because of potential aliasing when the src param is passed by ref, we need to check for equality here,
|
||||
@@ -281,7 +245,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
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, x.info, tyBool)
|
||||
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
|
||||
temp.typ = x.typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
@@ -291,7 +255,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
#body.add newAsgnStmt(blob, x)
|
||||
|
||||
var wasMovedCall = newNodeI(nkCall, c.info)
|
||||
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
|
||||
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved)))
|
||||
wasMovedCall.add x # mWasMoved does not take the address
|
||||
body.add wasMovedCall
|
||||
|
||||
@@ -304,7 +268,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)
|
||||
|
||||
@@ -313,7 +276,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
|
||||
result.typ = getSysType(g, info, tyBool)
|
||||
|
||||
proc getCycleParam(c: TLiftCtx): PNode =
|
||||
assert c.kind in {attachedAsgn, attachedDup}
|
||||
assert c.kind == attachedAsgn
|
||||
if c.fn.typ.len == 4:
|
||||
result = c.fn.typ.n.lastSon
|
||||
assert result.kind == nkSym
|
||||
@@ -352,9 +315,6 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newOpCall(c, op, y))
|
||||
|
||||
proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newOpCall(c, op, y))
|
||||
|
||||
proc usesBuiltinArc(t: PType): bool =
|
||||
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
|
||||
result = types.searchTypeFor(t, wrap)
|
||||
@@ -379,9 +339,9 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
field: var PSym): bool =
|
||||
if optSeqDestructors in c.g.config.globalOptions:
|
||||
var op = field
|
||||
let destructorOverridden = destructorOverridden(c.g, t)
|
||||
let destructorOverriden = destructorOverriden(c.g, t)
|
||||
if op != nil and op != c.fn and
|
||||
(sfOverridden in op.flags or destructorOverridden):
|
||||
(sfOverriden in op.flags or destructorOverriden):
|
||||
if sfError in op.flags:
|
||||
incl c.fn.flags, sfError
|
||||
#else:
|
||||
@@ -389,7 +349,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
onUse(c.info, op)
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
elif op == nil and destructorOverridden:
|
||||
elif op == nil and destructorOverriden:
|
||||
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
@@ -427,7 +387,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
|
||||
let t = orig.skipTypes(abstractInst - {tyDistinct})
|
||||
var op = t.destructor
|
||||
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
@@ -450,7 +410,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
case c.kind
|
||||
of attachedDestructor:
|
||||
var op = t.destructor
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
@@ -464,7 +424,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
#result = addDestructorCall(c, t, body, x)
|
||||
of attachedAsgn, attachedSink, attachedTrace:
|
||||
var op = getAttachedOp(c.g, t, c.kind)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic =trace:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
@@ -482,36 +442,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
body.add newDeepCopyCall(c, op, x, y)
|
||||
result = true
|
||||
|
||||
of attachedWasMoved:
|
||||
var op = getAttachedOp(c.g, t, attachedWasMoved)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op)
|
||||
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add genWasMovedCall(c, op, x)
|
||||
result = true
|
||||
|
||||
of attachedDup:
|
||||
var op = getAttachedOp(c.g, t, attachedDup)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
|
||||
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add newDupCall(c, op, x, y)
|
||||
result = true
|
||||
|
||||
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)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
|
||||
temp.typ = getSysType(c.g, body.info, tyInt)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
@@ -521,7 +453,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
body.add v
|
||||
|
||||
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
|
||||
temp.typ = value.typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
@@ -568,28 +500,14 @@ 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:
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
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:
|
||||
@@ -603,18 +521,17 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add genBuiltin(c, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
if canFormAcycle(c.g, t.elemType):
|
||||
if canFormAcycle(t.elemType):
|
||||
# follow all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
|
||||
# recursions are tricky, so we might need to forward the generated
|
||||
# operation here:
|
||||
var t = t
|
||||
if t.assignment == nil or t.destructor == nil or t.dup == nil:
|
||||
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
if t.assignment == nil or t.destructor == nil:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.g.canonTypes.getOrDefault(h)
|
||||
if canon != nil: t = canon
|
||||
|
||||
@@ -639,22 +556,15 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
doAssert t.destructor != nil
|
||||
body.add destructorCall(c, t.destructor, x)
|
||||
of attachedTrace:
|
||||
if t.kind != tyString and canFormAcycle(c.g, t.elemType):
|
||||
if t.kind != tyString and canFormAcycle(t.elemType):
|
||||
let op = getAttachedOp(c.g, t, c.kind)
|
||||
if op == nil:
|
||||
return # protect from recursion
|
||||
body.add newHookCall(c, op, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
of attachedDup:
|
||||
# XXX: replace these with assertions.
|
||||
let op = getAttachedOp(c.g, t, c.kind)
|
||||
if op == nil:
|
||||
return # protect from recursion
|
||||
body.add newDupCall(c, op, x, y)
|
||||
|
||||
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDeepCopy, attachedDup:
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
|
||||
of attachedSink:
|
||||
let moveCall = genBuiltin(c, mMove, "move", x)
|
||||
@@ -666,11 +576,10 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genBuiltin(c, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
discard "strings are atomic and have no inner elements that are to trace"
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc cyclicType*(g: ModuleGraph, t: PType): bool =
|
||||
proc cyclicType*(t: PType): bool =
|
||||
case t.kind
|
||||
of tyRef: result = types.canFormAcycle(g, t.lastSon)
|
||||
of tyRef: result = types.canFormAcycle(t.lastSon)
|
||||
of tyProc: result = t.callConv == ccClosure
|
||||
else: result = false
|
||||
|
||||
@@ -698,15 +607,10 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let elemType = t.lastSon
|
||||
|
||||
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
|
||||
|
||||
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
|
||||
(not isPureObject(elemType)) and
|
||||
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
|
||||
# dynamic Acyclic refs need to use dyn decRef
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
|
||||
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
declareTempOf(c, body, x)
|
||||
else:
|
||||
x
|
||||
@@ -728,8 +632,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
|
||||
elif isInheritableAcyclicRef:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
@@ -765,16 +667,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# If the ref is polymorphic we have to account for this
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
|
||||
#echo "can follow ", elemType, " static ", isFinal(elemType)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
of attachedDup:
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g,
|
||||
"nimIncRefCyclic", c.info, y, getCycleParam(c)))
|
||||
else:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g,
|
||||
"nimIncRef", c.info, y))
|
||||
|
||||
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
## Closures are really like refs except they always use a virtual destructor
|
||||
@@ -784,7 +676,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
declareTempOf(c, body, xenv)
|
||||
else:
|
||||
xenv
|
||||
@@ -818,21 +710,11 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
|
||||
else:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, cond, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace:
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
@@ -845,9 +727,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
|
||||
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
|
||||
of attachedDestructor:
|
||||
# it's better to prepend the destruction of weak refs in order to
|
||||
# prevent wrong "dangling refs exist" problems:
|
||||
@@ -860,7 +739,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
@@ -882,13 +760,10 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedSink, attachedAsgn:
|
||||
body.add genIf(c, x, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, x, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind == attachedDeepCopy:
|
||||
@@ -900,7 +775,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
call[1] = y
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
case c.kind
|
||||
@@ -915,11 +790,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
|
||||
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yy.typ = getSysType(c.g, c.info, tyPointer)
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
|
||||
of attachedDestructor:
|
||||
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
if body.len == 0:
|
||||
@@ -928,7 +798,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
@@ -940,13 +809,10 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedSink, attachedAsgn:
|
||||
body.add genIf(c, xx, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, xx, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
@@ -955,7 +821,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyPtr, tyUncheckedArray, tyVar, tyLent:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyRef:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
atomicRefOp(c, t, body, x, y)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options):
|
||||
@@ -964,7 +830,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyProc:
|
||||
if t.callConv == ccClosure:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
atomicClosureOp(c, t, body, x, y)
|
||||
else:
|
||||
closureOp(c, t, body, x, y)
|
||||
@@ -1010,25 +876,10 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyObject:
|
||||
if not considerUserDefinedOp(c, t, body, x, y):
|
||||
if t.sym != nil and sfImportc in t.sym.flags:
|
||||
case c.kind
|
||||
of {attachedAsgn, attachedSink, attachedDup}:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
if c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags:
|
||||
body.add newAsgnStmt(x, y)
|
||||
else:
|
||||
if c.kind == attachedDup:
|
||||
var op2 = getAttachedOp(c.g, t, attachedAsgn)
|
||||
if op2 != nil and sfOverridden in op2.flags:
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op2)
|
||||
body.add newHookCall(c, t.assignment, x, y)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
of tyDistinct:
|
||||
if not considerUserDefinedOp(c, t, body, x, y):
|
||||
fillBody(c, t[0], body, x, y)
|
||||
@@ -1061,56 +912,15 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
|
||||
result = getAttachedOp(g, baseType, kind)
|
||||
setAttachedOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
result = newSym(skProc, procname, idgen, owner, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
let src = newSym(skParam, getIdent(g.cache, "src"),
|
||||
idgen, result, info)
|
||||
res.typ = typ
|
||||
src.typ = typ
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, owner)
|
||||
result.typ.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result.typ, res.typ)
|
||||
result.typ.n.add newNodeI(nkEffectList, info)
|
||||
|
||||
result.typ.addParam src
|
||||
|
||||
if g.config.selectedGC == gcOrc and
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
idgen, result, info)
|
||||
cycleParam.typ = getSysType(g, info, tyBool)
|
||||
result.typ.addParam cycleParam
|
||||
|
||||
var n = newNodeI(nkProcDef, info, bodyPos+2)
|
||||
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
|
||||
n[namePos] = newSymNode(result)
|
||||
n[paramsPos] = result.typ.n
|
||||
n[bodyPos] = newNodeI(nkStmtList, info)
|
||||
n[resultPos] = newSymNode(res)
|
||||
result.ast = n
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
|
||||
if kind == attachedDup:
|
||||
return symDupPrototype(g, typ, owner, kind, info, idgen)
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
result = newSym(skProc, procname, idgen, owner, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
|
||||
result = newSym(skProc, procname, nextSymId(idgen), owner, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(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})):
|
||||
dest.typ = typ
|
||||
else:
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
|
||||
nextSymId(idgen), result, info)
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
if kind == attachedTrace:
|
||||
src.typ = getSysType(g, info, tyPointer)
|
||||
else:
|
||||
@@ -1118,13 +928,13 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
|
||||
result.typ = newProcType(info, nextTypeId(idgen), owner)
|
||||
result.typ.addParam dest
|
||||
if kind notin {attachedDestructor, attachedWasMoved}:
|
||||
if kind != attachedDestructor:
|
||||
result.typ.addParam src
|
||||
|
||||
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
cyclicType(typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
idgen, result, info)
|
||||
nextSymId(idgen), result, info)
|
||||
cycleParam.typ = getSysType(g, info, tyBool)
|
||||
result.typ.addParam cycleParam
|
||||
|
||||
@@ -1136,9 +946,6 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
result.ast = n
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
if kind == attachedWasMoved:
|
||||
incl result.flags, sfNoSideEffect
|
||||
incl result.typ.flags, tfNoSideEffect
|
||||
|
||||
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
|
||||
@@ -1159,25 +966,22 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
|
||||
fn: result)
|
||||
|
||||
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
|
||||
let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
|
||||
let src = case kind
|
||||
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
of attachedDup: newSymNode(result.typ.n[1].sym)
|
||||
let dest = result.typ.n[1].sym
|
||||
let d = newDeref(newSymNode(dest))
|
||||
let src = if kind == attachedDestructor: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
else: newSymNode(result.typ.n[2].sym)
|
||||
|
||||
# register this operation already:
|
||||
setAttachedOpPartial(g, idgen.module, typ, kind, result)
|
||||
|
||||
if kind == attachedSink and destructorOverridden(g, typ):
|
||||
if kind == attachedSink and destructorOverriden(g, typ):
|
||||
## compiler can use a combination of `=destroy` and memCopy for sink op
|
||||
dest.flags.incl sfCursor
|
||||
let op = getAttachedOp(g, typ, attachedDestructor)
|
||||
result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
|
||||
result.ast[bodyPos].add newOpCall(a, getAttachedOp(g, typ, attachedDestructor), d[0])
|
||||
result.ast[bodyPos].add newAsgnStmt(d, src)
|
||||
else:
|
||||
var tk: TTypeKind
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
|
||||
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
|
||||
else:
|
||||
tk = tyNone # no special casing for strings and seqs
|
||||
@@ -1188,26 +992,18 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
||||
else:
|
||||
fillBody(a, typ, result.ast[bodyPos], d, src)
|
||||
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not isObjLackingTypeField(typ):
|
||||
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
|
||||
# bug #19205: Do not forget to also copy the hidden type field:
|
||||
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
|
||||
|
||||
if not a.canRaise:
|
||||
incl result.flags, sfNeverRaises
|
||||
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
|
||||
@@ -1215,7 +1011,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
|
||||
a.addMemReset = true
|
||||
let discrimantDest = result.typ.n[1].sym
|
||||
|
||||
let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
|
||||
let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
|
||||
dst.typ = makePtrType(typ.owner, typ, idgen)
|
||||
let dstSym = newSymNode(dst)
|
||||
let d = newDeref(dstSym)
|
||||
@@ -1241,7 +1037,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
|
||||
if op != nil:
|
||||
if op.ast.isGenericRoutine:
|
||||
internalError(g.config, info, "resolved destructor is generic")
|
||||
if op.magic == mDestroy and t.kind != tyString:
|
||||
if op.magic == mDestroy:
|
||||
internalError(g.config, info, "patching mDestroy with mDestroy?")
|
||||
n[0] = newSymNode(op)
|
||||
for x in n: patchBody(g, c, x, info, idgen)
|
||||
@@ -1251,7 +1047,13 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
|
||||
let op = getAttachedOp(g, t, kind)
|
||||
if op != nil and op.ast != nil and op.ast.isGenericRoutine:
|
||||
if t.typeInst != nil:
|
||||
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen)
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
a.g = g
|
||||
a.kind = kind
|
||||
a.c = c
|
||||
a.idgen = idgen
|
||||
|
||||
let opInst = instantiateGeneric(a, op, t, t.typeInst)
|
||||
if opInst.ast != nil:
|
||||
patchBody(g, c, opInst.ast, info, a.idgen)
|
||||
@@ -1259,7 +1061,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;
|
||||
@@ -1273,7 +1075,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
|
||||
|
||||
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
|
||||
var canon = g.canonTypes.getOrDefault(h)
|
||||
if canon == nil:
|
||||
g.canonTypes[h] = skipped
|
||||
@@ -1294,15 +1096,15 @@ 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]
|
||||
for k in attachedWasMoved..lastAttached:
|
||||
var generics: array[attachedDestructor..attachedTrace, bool]
|
||||
for k in attachedDestructor..lastAttached:
|
||||
generics[k] = getAttachedOp(g, canon, k) != nil
|
||||
if not generics[k]:
|
||||
setAttachedOp(g, idgen.module, canon, k,
|
||||
symPrototype(g, canon, canon.owner, k, info, idgen))
|
||||
|
||||
# we generate the destructor first so that other operators can depend on it:
|
||||
for k in attachedWasMoved..lastAttached:
|
||||
for k in attachedDestructor..lastAttached:
|
||||
if not generics[k]:
|
||||
discard produceSym(g, c, canon, k, info, idgen)
|
||||
else:
|
||||
|
||||
@@ -44,7 +44,6 @@ type
|
||||
errRstSandboxedDirective,
|
||||
errProveInit, # deadcode
|
||||
errGenerated,
|
||||
errFailedMove,
|
||||
errUser,
|
||||
# warnings
|
||||
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
|
||||
@@ -58,7 +57,6 @@ type
|
||||
warnRstBrokenLink = "BrokenLink",
|
||||
warnRstLanguageXNotSupported = "LanguageXNotSupported",
|
||||
warnRstFieldXNotSupported = "FieldXNotSupported",
|
||||
warnRstUnusedImportdoc = "UnusedImportdoc",
|
||||
warnRstStyle = "warnRstStyle",
|
||||
warnCommentXIgnored = "CommentXIgnored",
|
||||
warnTypelessParam = "TypelessParam",
|
||||
@@ -84,18 +82,15 @@ type
|
||||
warnCstringConv = "CStringConv",
|
||||
warnPtrToCstringConv = "PtrToCstringConv",
|
||||
warnEffect = "Effect",
|
||||
warnCastSizes = "CastSizes", # deadcode
|
||||
warnAboveMaxSizeSet = "AboveMaxSizeSet",
|
||||
warnCastSizes = "CastSizes"
|
||||
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
|
||||
warnUnnamedBreak = "UnnamedBreak",
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnImplicitDefaultValue = "ImplicitDefaultValue",
|
||||
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
hintCC = "CC",
|
||||
hintLineTooLong = "LineTooLong",
|
||||
hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport",
|
||||
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
|
||||
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
|
||||
@@ -105,10 +100,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] = [
|
||||
@@ -130,7 +125,6 @@ const
|
||||
errRstSandboxedDirective: "disabled directive: '$1'",
|
||||
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
|
||||
errGenerated: "$1",
|
||||
errFailedMove: "$1",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open '$1'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
@@ -147,7 +141,6 @@ const
|
||||
warnRstBrokenLink: "broken link '$1'",
|
||||
warnRstLanguageXNotSupported: "language '$1' not supported",
|
||||
warnRstFieldXNotSupported: "field '$1' not supported",
|
||||
warnRstUnusedImportdoc: "importdoc for '$1' is not used",
|
||||
warnRstStyle: "RST style: $1",
|
||||
warnCommentXIgnored: "comment '$1' ignored",
|
||||
warnTypelessParam: "", # deadcode
|
||||
@@ -186,21 +179,18 @@ 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",
|
||||
warnCastSizes: "$1",
|
||||
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
|
||||
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
|
||||
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`
|
||||
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
|
||||
hintCC: "CC: $1",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintDuplicateModuleImport: "$1",
|
||||
hintXCannotRaiseY: "$1",
|
||||
@@ -227,12 +217,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,7 +240,7 @@ type
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv}
|
||||
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
@@ -281,7 +271,7 @@ type
|
||||
# and parsed; usually "" but is used
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
dirty*: bool # for 'nimpretty' like tooling
|
||||
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
|
||||
when defined(nimpretty):
|
||||
fullContent*: string
|
||||
FileIndex* = distinct int32
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
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
|
||||
@@ -95,7 +95,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(ctx.module) and # ignore foreign packages
|
||||
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
|
||||
sym.kind != skResult and # ignore `result`
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
@@ -136,7 +136,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(ctx.module) and # ignore foreign packages
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
|
||||
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
|
||||
@@ -147,10 +147,6 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
|
||||
if pragmaName != wanted:
|
||||
lintReport(conf, info, wanted, pragmaName)
|
||||
|
||||
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
|
||||
## Check builtin pragma uses match their definition's style.
|
||||
## 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
|
||||
checkPragmaUseImpl(ctx.config, info, w, pragmaName)
|
||||
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
checkPragmaUseImpl(conf, info, w, pragmaName)
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
#
|
||||
|
||||
# This module implements lookup helpers.
|
||||
import std/[algorithm, strutils, tables]
|
||||
import std/[algorithm, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
|
||||
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -96,6 +94,17 @@ iterator localScopesFrom*(c: PContext; scope: PScope): PScope =
|
||||
if s == c.topLevelScope: break
|
||||
yield s
|
||||
|
||||
proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
|
||||
if s == nil or s.kind != skAlias:
|
||||
result = s
|
||||
else:
|
||||
result = s.owner
|
||||
if conf.cmd == cmdNimfix:
|
||||
prettybase.replaceDeprecated(conf, n.info, s, result)
|
||||
else:
|
||||
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
|
||||
s.name.s & " is deprecated")
|
||||
|
||||
proc isShadowScope*(s: PScope): bool {.inline.} =
|
||||
s.parent != nil and s.parent.depthLevel == s.depthLevel
|
||||
|
||||
@@ -137,7 +146,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 +159,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:
|
||||
@@ -161,7 +170,6 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
|
||||
# really iterate over all symbols in all the scopes. This is expensive
|
||||
# and only used by suggest.nim.
|
||||
var isLocal = true
|
||||
|
||||
var scopeN = 0
|
||||
for scope in allScopes(c.currentScope):
|
||||
if scope == c.topLevelScope: isLocal = false
|
||||
@@ -176,17 +184,6 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
|
||||
assert s != nil
|
||||
yield (s, scopeN, isLocal)
|
||||
|
||||
iterator uniqueSyms*(c: PContext): (PSym, int, bool) =
|
||||
## Like [allSyms] except only returns unique symbols (Uniqueness determined by line + name)
|
||||
# Track seen symbols so we don't duplicate them.
|
||||
# The int is for the symbols name, and line info is
|
||||
# to be able to tell apart symbols with same name but on different lines
|
||||
var seen = initHashSet[(TLineInfo, int)]()
|
||||
for res in allSyms(c):
|
||||
if not seen.containsOrIncl((res[0].info, res[0].name.id)):
|
||||
yield res
|
||||
|
||||
|
||||
proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym =
|
||||
var marked = initIntSet()
|
||||
var symSet = OverloadableSyms
|
||||
@@ -219,28 +216,11 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
|
||||
if i == limit: return
|
||||
inc i
|
||||
|
||||
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
|
||||
result = @[]
|
||||
for scope in allScopes(c.currentScope):
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter:
|
||||
result.add candidate
|
||||
candidate = nextIdentIter(ti, scope.symbols)
|
||||
|
||||
if result.len == 0:
|
||||
var marked = initIntSet()
|
||||
for im in c.imports.mitems:
|
||||
for s in symbols(im, marked, s, c.graph):
|
||||
if s.kind in filter:
|
||||
result.add s
|
||||
|
||||
proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
|
||||
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 +236,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 +245,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, nextSymId(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,7 +277,7 @@ 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]]
|
||||
@@ -381,18 +311,15 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
|
||||
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
|
||||
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
|
||||
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
|
||||
if sym.name.id == ord(wUnderscore): return
|
||||
let conflict = scope.addUniqueSym(sym)
|
||||
if conflict != nil:
|
||||
if sym.kind == skModule and conflict.kind == skModule:
|
||||
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
|
||||
# e.g.: import foo; import foo
|
||||
# xxx we could refine this by issuing a different hint for the case
|
||||
# where a duplicate import happens inside an include.
|
||||
if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]:
|
||||
#only hints if the conflict is the actual module not just a shared name
|
||||
localError(c.config, info, hintDuplicateModuleImport,
|
||||
"duplicate import of '$1'; previous import here: $2" %
|
||||
[sym.name.s, c.config $ conflict.info])
|
||||
localError(c.config, info, hintDuplicateModuleImport,
|
||||
"duplicate import of '$1'; previous import here: $2" %
|
||||
[sym.name.s, c.config $ conflict.info])
|
||||
else:
|
||||
wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated)
|
||||
|
||||
@@ -438,12 +365,11 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
|
||||
if fn.kind notin OverloadableSyms:
|
||||
internalError(c.config, fn.info, "addOverloadableSymAt")
|
||||
return
|
||||
if fn.name.id != ord(wUnderscore):
|
||||
let check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(c, fn.info, fn.name.s, check.info)
|
||||
else:
|
||||
scope.addSym(fn)
|
||||
let check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(c, fn.info, fn.name.s, check.info)
|
||||
else:
|
||||
scope.addSym(fn)
|
||||
|
||||
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
## adds an overloadable symbol on the scope and the interface if appropriate
|
||||
@@ -480,6 +406,13 @@ proc mergeShadowScope*(c: PContext) =
|
||||
else:
|
||||
c.addInterfaceDecl(sym)
|
||||
|
||||
when false:
|
||||
# `nimfix` used to call `altSpelling` and prettybase.replaceDeprecated(n.info, ident, alt)
|
||||
proc altSpelling(c: PContext, x: PIdent): PIdent =
|
||||
case x.s[0]
|
||||
of 'A'..'Z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
else: result = x
|
||||
|
||||
import std/editdistance, heapqueue
|
||||
|
||||
@@ -502,7 +435,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
|
||||
@@ -512,29 +445,29 @@ proc fixSpelling(c: PContext, ident: PIdent, result: var string) =
|
||||
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
|
||||
var msg: string
|
||||
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
|
||||
addDeclaredLoc(msg, c.config, sym) # `msg` needed for deterministic ordering.
|
||||
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
|
||||
|
||||
if list.len == 0: return
|
||||
let e0 = list[0]
|
||||
var
|
||||
count = 0
|
||||
last: PIdent = nil
|
||||
var count = 0
|
||||
while true:
|
||||
# pending https://github.com/timotheecour/Nim/issues/373 use more efficient `itemsSorted`.
|
||||
if list.len == 0: break
|
||||
let e = list.pop()
|
||||
if c.config.spellSuggestMax == spellSuggestSecretSauce:
|
||||
const
|
||||
minLengthForSuggestion = 4
|
||||
maxCount = 3 # avoids ton of matches; three counts for equal distances
|
||||
if e.dist > e0.dist or count >= maxCount or name0.len < minLengthForSuggestion: break
|
||||
smallThres = 2
|
||||
maxCountForSmall = 4
|
||||
# avoids ton of operator matches when mis-matching short symbols such as `i`
|
||||
# other heuristics could be devised, such as only suggesting operators if `name0`
|
||||
# is an operator (likewise with non-operators).
|
||||
if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break
|
||||
elif count >= c.config.spellSuggestMax: break
|
||||
if count == 0:
|
||||
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
|
||||
if e.sym.name != last:
|
||||
result.add e.msg
|
||||
count.inc
|
||||
last = e.sym.name
|
||||
result.add e.msg
|
||||
count.inc
|
||||
|
||||
proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PSym =
|
||||
var err = "ambiguous identifier: '" & s.name.s & "'"
|
||||
@@ -557,10 +490,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:
|
||||
@@ -579,44 +512,36 @@ proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
|
||||
errorUseQualifier(c, info, candidates, prefix)
|
||||
|
||||
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
|
||||
var err: string
|
||||
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
|
||||
if c.recursiveDep.len > 0:
|
||||
err.add "\nThis might be caused by a recursive module dependency:\n"
|
||||
err.add c.recursiveDep
|
||||
# prevent excessive errors for 'nim check'
|
||||
c.recursiveDep = ""
|
||||
var 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
|
||||
# prevent excessive errors for 'nim check'
|
||||
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.
|
||||
var amb = false
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
result = searchInScopes(c, n.ident, amb)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n.ident, n.info)
|
||||
result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config)
|
||||
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)
|
||||
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
|
||||
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,45 +552,36 @@ 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)
|
||||
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
|
||||
else:
|
||||
let candidates = lookUpCandidates(c, ident, allExceptModule)
|
||||
let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config)
|
||||
if candidates.len > 0:
|
||||
result = candidates[0]
|
||||
amb = candidates.len > 1
|
||||
if amb and checkAmbiguity in flags:
|
||||
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})
|
||||
@@ -677,20 +593,13 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
ident = considerQuotedIdent(c, n[1])
|
||||
if ident != nil:
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
|
||||
else:
|
||||
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
|
||||
var amb: bool = false
|
||||
result = errorUseQualifier(c, n.info, m, amb)
|
||||
else:
|
||||
result = someSym(c.graph, m, ident)
|
||||
result = someSym(c.graph, m, ident).skipAlias(n, c.config)
|
||||
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)
|
||||
elif checkUndeclared in flags and
|
||||
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
|
||||
localError(c.config, n[1].info, "identifier expected, but got: " &
|
||||
@@ -702,10 +611,6 @@ 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
|
||||
@@ -714,7 +619,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
var scope = c.currentScope
|
||||
o.mode = oimNoQualifier
|
||||
while true:
|
||||
result = initIdentIter(o.it, scope.symbols, ident)
|
||||
result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config)
|
||||
if result != nil:
|
||||
o.currentScope = scope
|
||||
break
|
||||
@@ -722,7 +627,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
scope = scope.parent
|
||||
if scope == nil:
|
||||
for i in 0..c.imports.high:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config)
|
||||
if result != nil:
|
||||
o.currentScope = nil
|
||||
o.importIdx = i
|
||||
@@ -745,10 +650,10 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if o.m == c.module:
|
||||
# a module may access its private members:
|
||||
result = initIdentIter(o.it, c.topLevelScope.symbols,
|
||||
ident)
|
||||
ident).skipAlias(n, c.config)
|
||||
o.mode = oimSelfModule
|
||||
else:
|
||||
result = initModuleIter(o.mit, c.graph, o.m, ident)
|
||||
result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config)
|
||||
else:
|
||||
noidentError(c.config, n[1], n)
|
||||
result = errorSym(c, n[1])
|
||||
@@ -781,7 +686,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
|
||||
var idx = o.importIdx+1
|
||||
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
|
||||
while idx < c.imports.len:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
if result != nil:
|
||||
# oh, we were wrong, some other module had the symbol, so remember that:
|
||||
o.importIdx = idx
|
||||
@@ -791,7 +696,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
|
||||
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
|
||||
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)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
#while result != nil and result.id in o.marked:
|
||||
# result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx])
|
||||
if result != nil:
|
||||
@@ -806,29 +711,29 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
of oimNoQualifier:
|
||||
if o.currentScope != nil:
|
||||
assert o.importIdx < 0
|
||||
result = nextIdentIter(o.it, o.currentScope.symbols)
|
||||
result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name)
|
||||
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config)
|
||||
# BUGFIX: o.it.name <-> n.ident
|
||||
else:
|
||||
o.importIdx = 0
|
||||
if c.imports.len > 0:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
if result == nil:
|
||||
result = nextOverloadIterImports(o, c, n)
|
||||
break
|
||||
elif o.importIdx < c.imports.len:
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
|
||||
if result == nil:
|
||||
result = nextOverloadIterImports(o, c, n)
|
||||
else:
|
||||
result = nil
|
||||
of oimSelfModule:
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols)
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
|
||||
of oimOtherModule:
|
||||
result = nextModuleIter(o.mit, c.graph)
|
||||
result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config)
|
||||
of oimSymChoice:
|
||||
if o.symChoiceIndex < n.len:
|
||||
result = n[o.symChoiceIndex].sym
|
||||
@@ -839,12 +744,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.mode = oimSymChoiceLocalLookup
|
||||
o.currentScope = c.currentScope
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked)
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked)
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
else:
|
||||
o.importIdx = 0
|
||||
result = symChoiceExtension(o, c, n)
|
||||
@@ -853,12 +758,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
incl o.marked, result.id
|
||||
of oimSymChoiceLocalLookup:
|
||||
if o.currentScope != nil:
|
||||
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
|
||||
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked)
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
else:
|
||||
o.importIdx = 0
|
||||
result = symChoiceExtension(o, c, n)
|
||||
@@ -867,10 +772,10 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
incl o.marked, result.id
|
||||
|
||||
elif o.importIdx < c.imports.len:
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
|
||||
#assert result.id notin o.marked
|
||||
#while result != nil and result.id in o.marked:
|
||||
# result = nextIdentIter(o.it, c.imports[o.importIdx])
|
||||
# result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config)
|
||||
if result == nil:
|
||||
inc o.importIdx
|
||||
result = symChoiceExtension(o, c, n)
|
||||
|
||||
@@ -79,7 +79,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
|
||||
if avoidTemp:
|
||||
tempAsNode = value
|
||||
else:
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
@@ -100,7 +100,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
|
||||
## freely, multiple times. This is frequently required and such a builtin would also be
|
||||
## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
|
||||
result = newNodeIT(nkStmtListExpr, value.info, value.typ)
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
@@ -122,10 +122,29 @@ 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, "_"), nextSymId(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(nkEmpty, 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 :-(
|
||||
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
|
||||
var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options)
|
||||
temp.typ = n[1].typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
incl(temp.flags, sfGenSym)
|
||||
@@ -152,7 +171,8 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
|
||||
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
|
||||
result.n = newNodeI(nkRecList, info)
|
||||
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
|
||||
idgen, owner, info, owner.options)
|
||||
nextSymId(idgen),
|
||||
owner, info, owner.options)
|
||||
incl s.flags, sfAnon
|
||||
s.typ = result
|
||||
result.sym = s
|
||||
@@ -214,13 +234,10 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||
# This is hacky but the clean solution is much more complex than it looks.
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
|
||||
idgen, s.owner, s.info, s.options)
|
||||
nextSymId(idgen), s.owner, s.info, s.options)
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
field.typ = t
|
||||
if s.kind in {skLet, skVar, skField, skForVar}:
|
||||
#field.bitsize = s.bitsize
|
||||
field.alignment = s.alignment
|
||||
assert t.kind != tyTyped
|
||||
propagateToOwner(obj, t)
|
||||
field.position = obj.n.len
|
||||
@@ -233,7 +250,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
|
||||
result = lookupInRecord(obj.n, s.itemId)
|
||||
if result == nil:
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen,
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen),
|
||||
s.owner, s.info, s.options)
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
@@ -330,8 +347,7 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
|
||||
|
||||
proc callCodegenProc*(g: ModuleGraph; name: string;
|
||||
info: TLineInfo = unknownLineInfo;
|
||||
arg1: PNode = nil, arg2: PNode = nil,
|
||||
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
|
||||
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
let sym = magicsys.getCompilerProc(g, name)
|
||||
if sym == nil:
|
||||
|
||||
@@ -26,8 +26,9 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
|
||||
result = systemModuleSym(g, getIdent(g.cache, name))
|
||||
if result == nil:
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
|
||||
let id = getIdent(g.cache, name)
|
||||
@@ -38,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
|
||||
result = r
|
||||
if result != nil: return result
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
|
||||
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
|
||||
|
||||
@@ -13,12 +13,12 @@ when not defined(nimcore):
|
||||
{.error: "nimcore MUST be defined for Nim's core tooling".}
|
||||
|
||||
import
|
||||
std/[strutils, os, times, tables, with, json],
|
||||
std/[strutils, os, times, tables, sha1, with, json],
|
||||
llstream, ast, lexer, syntaxes, options, msgs,
|
||||
condsyms,
|
||||
idents, extccomp,
|
||||
sem, idents, passes, extccomp,
|
||||
cgen, nversion,
|
||||
platform, nimconf, depends,
|
||||
platform, nimconf, passaux, depends, vm,
|
||||
modules,
|
||||
modulegraphs, lineinfos, pathutils, vmprofiler
|
||||
|
||||
@@ -29,12 +29,12 @@ when defined(nimPreviewSlimSystem):
|
||||
import ic / [cbackend, integrity, navigator]
|
||||
from ic / ic import rodViewer
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
import pipelines
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import docgen
|
||||
import jsgen, docgen, docgen2
|
||||
|
||||
proc semanticPasses(g: ModuleGraph) =
|
||||
registerPass g, verbosePass
|
||||
registerPass g, semPass
|
||||
|
||||
proc writeDepsFile(g: ModuleGraph) =
|
||||
let fname = g.config.nimcacheDir / RelativeFile(g.config.projectName & ".deps")
|
||||
@@ -68,18 +68,12 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
|
||||
fl.close()
|
||||
|
||||
proc commandGenDepend(graph: ModuleGraph) =
|
||||
setPipeLinePass(graph, GenDependPass)
|
||||
compilePipelineProject(graph)
|
||||
semanticPasses(graph)
|
||||
registerPass(graph, gendependPass)
|
||||
compileProject(graph)
|
||||
let project = graph.config.projectFull
|
||||
writeDepsFile(graph)
|
||||
generateDot(graph, project)
|
||||
|
||||
# dot in graphivz tool kit is required
|
||||
let graphvizDotPath = findExe("dot")
|
||||
if graphvizDotPath.len == 0:
|
||||
quit("gendepend: Graphviz's tool dot is required," &
|
||||
"see https://graphviz.org/download for downloading")
|
||||
|
||||
execExternalProgram(graph.config, "dot -Tpng -o" &
|
||||
changeFileExt(project, "png").string &
|
||||
' ' & changeFileExt(project, "dot").string)
|
||||
@@ -93,8 +87,8 @@ proc commandCheck(graph: ModuleGraph) =
|
||||
defineSymbol(conf.symbols, "nimconfig")
|
||||
elif conf.backend == backendJs:
|
||||
setTarget(conf.target, osJS, cpuJS)
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
semanticPasses(graph) # use an empty backend for semantic checking only
|
||||
compileProject(graph)
|
||||
|
||||
if conf.symbolFiles != disabledSf:
|
||||
case conf.ideCmd
|
||||
@@ -108,20 +102,22 @@ when not defined(leanCompiler):
|
||||
proc commandDoc2(graph: ModuleGraph; ext: string) =
|
||||
handleDocOutputOptions graph.config
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
semanticPasses(graph)
|
||||
case ext:
|
||||
of TexExt:
|
||||
setPipeLinePass(graph, Docgen2TexPass)
|
||||
of JsonExt:
|
||||
setPipeLinePass(graph, Docgen2JsonPass)
|
||||
of HtmlExt:
|
||||
setPipeLinePass(graph, Docgen2Pass)
|
||||
of TexExt: registerPass(graph, docgen2TexPass)
|
||||
of JsonExt: registerPass(graph, docgen2JsonPass)
|
||||
of HtmlExt: registerPass(graph, docgen2Pass)
|
||||
else: doAssert false, $ext
|
||||
compilePipelineProject(graph)
|
||||
compileProject(graph)
|
||||
finishDoc2Pass(graph.config.projectName)
|
||||
|
||||
proc commandCompileToC(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
semanticPasses(graph)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
registerPass(graph, cgenPass)
|
||||
|
||||
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
|
||||
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
|
||||
# nothing changed
|
||||
@@ -131,11 +127,7 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
if not extccomp.ccHasSaneOverflow(conf):
|
||||
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
|
||||
|
||||
if conf.symbolFiles == disabledSf:
|
||||
setPipeLinePass(graph, CgenPass)
|
||||
else:
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
compileProject(graph)
|
||||
if graph.config.errorCounter > 0:
|
||||
return # issue #9933
|
||||
if conf.symbolFiles == disabledSf:
|
||||
@@ -151,7 +143,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:
|
||||
@@ -168,35 +160,41 @@ proc commandCompileToJS(graph: ModuleGraph) =
|
||||
conf.exc = excCpp
|
||||
setTarget(conf.target, osJS, cpuJS)
|
||||
defineSymbol(conf.symbols, "ecmascript") # For backward compatibility
|
||||
setPipeLinePass(graph, JSgenPass)
|
||||
compilePipelineProject(graph)
|
||||
semanticPasses(graph)
|
||||
registerPass(graph, JSgenPass)
|
||||
compileProject(graph)
|
||||
if optGenScript in conf.globalOptions:
|
||||
writeDepsFile(graph)
|
||||
|
||||
proc commandInteractive(graph: ModuleGraph) =
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
proc interactivePasses(graph: ModuleGraph) =
|
||||
initDefines(graph.config.symbols)
|
||||
defineSymbol(graph.config.symbols, "nimscript")
|
||||
# note: seems redundant with -d:nimHasLibFFI
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
setPipeLinePass(graph, InterpreterPass)
|
||||
compilePipelineSystemModule(graph)
|
||||
registerPass(graph, verbosePass)
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
|
||||
proc commandInteractive(graph: ModuleGraph) =
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
interactivePasses(graph)
|
||||
compileSystemModule(graph)
|
||||
if graph.config.commandArgs.len > 0:
|
||||
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
else:
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
|
||||
let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config))
|
||||
discard processPipelineModule(graph, m, idgen, s)
|
||||
processModule(graph, m, idgen, s)
|
||||
|
||||
proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
L: Lexer = default(Lexer)
|
||||
tok: Token = default(Token)
|
||||
L: Lexer
|
||||
tok: Token
|
||||
initToken(tok)
|
||||
openLexer(L, f, stream, cache, config)
|
||||
while true:
|
||||
@@ -243,6 +241,8 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
let cache = graph.cache
|
||||
|
||||
# In "nim serve" scenario, each command must reset the registered passes
|
||||
clearPasses(graph)
|
||||
conf.lastCmdTime = epochTime()
|
||||
conf.searchPaths.add(conf.libpath)
|
||||
|
||||
@@ -417,7 +417,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of cmdJsonscript:
|
||||
setOutFile(graph.config)
|
||||
commandJsonScript(graph)
|
||||
of cmdUnknown, cmdNone, cmdIdeTools:
|
||||
of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix:
|
||||
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
|
||||
|
||||
if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}:
|
||||
|
||||
297
compiler/md5_old.nim
Normal file
297
compiler/md5_old.nim
Normal file
@@ -0,0 +1,297 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# `std/md5` without VM and JavaScript support, to circumvent a bug with
|
||||
# openarrays on Nim < 1.4.
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.push styleChecks: off.}
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
MD5CBits = array[0..7, uint8]
|
||||
MD5Digest* = array[0..15, uint8]
|
||||
## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_.
|
||||
MD5Buffer = array[0..63, uint8]
|
||||
MD5Context* {.final.} = object
|
||||
state: MD5State
|
||||
count: array[0..1, uint32]
|
||||
buffer: MD5Buffer
|
||||
|
||||
const
|
||||
padding: array[0..63, uint8] = [
|
||||
0x80'u8, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
]
|
||||
|
||||
proc F(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and y) or ((not x) and z)
|
||||
|
||||
proc G(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and z) or (y and (not z))
|
||||
|
||||
proc H(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = x xor y xor z
|
||||
|
||||
proc I(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = y xor (x or (not z))
|
||||
|
||||
proc rot(x: var uint32, n: uint8) {.inline.} =
|
||||
x = (x shl n) or (x shr (32'u32 - n))
|
||||
|
||||
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + F(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + G(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + H(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + I(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc encode(dest: var MD5Block, src: openArray[uint8]) =
|
||||
var j = 0
|
||||
for i in 0..high(dest):
|
||||
dest[i] = uint32(ord(src[j])) or
|
||||
uint32(ord(src[j+1])) shl 8 or
|
||||
uint32(ord(src[j+2])) shl 16 or
|
||||
uint32(ord(src[j+3])) shl 24
|
||||
inc(j, 4)
|
||||
|
||||
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
|
||||
var i = 0
|
||||
for j in 0..high(src):
|
||||
dest[i] = uint8(src[j] and 0xff'u32)
|
||||
dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
|
||||
dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
|
||||
dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
|
||||
inc(i, 4)
|
||||
|
||||
template slice(s: string | cstring, a, b): openArray[uint8] =
|
||||
s.toOpenArrayByte(a, b)
|
||||
|
||||
template slice(s: openArray[uint8], a, b): openArray[uint8] =
|
||||
s.toOpenArray(a, b)
|
||||
|
||||
proc transform(buffer: openArray[uint8], state: var MD5State) =
|
||||
var
|
||||
myBlock: MD5Block
|
||||
encode(myBlock, buffer)
|
||||
var a = state[0]
|
||||
var b = state[1]
|
||||
var c = state[2]
|
||||
var d = state[3]
|
||||
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
|
||||
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
|
||||
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
|
||||
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
|
||||
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
|
||||
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
|
||||
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
|
||||
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
|
||||
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
|
||||
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
|
||||
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
|
||||
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
|
||||
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
|
||||
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
|
||||
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
|
||||
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
|
||||
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
|
||||
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
|
||||
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
|
||||
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
|
||||
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
|
||||
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
|
||||
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
|
||||
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
|
||||
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
|
||||
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
|
||||
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
|
||||
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
|
||||
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
|
||||
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
|
||||
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
|
||||
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
|
||||
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
|
||||
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
|
||||
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
|
||||
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
|
||||
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
|
||||
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
|
||||
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
|
||||
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
|
||||
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
|
||||
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
|
||||
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
|
||||
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
|
||||
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
|
||||
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
|
||||
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
|
||||
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
|
||||
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
|
||||
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
|
||||
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
|
||||
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
|
||||
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
|
||||
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
|
||||
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
|
||||
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
|
||||
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
|
||||
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
|
||||
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
|
||||
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
|
||||
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
|
||||
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
|
||||
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
|
||||
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
|
||||
state[0] = state[0] + a
|
||||
state[1] = state[1] + b
|
||||
state[2] = state[2] + c
|
||||
state[3] = state[3] + d
|
||||
|
||||
proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.}
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [],
|
||||
tags: [], gcsafe.}
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.}
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [],
|
||||
tags: [], gcsafe.} =
|
||||
## Updates the `MD5Context` with the `input` data of length `len`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
md5Update(c, input.slice(0, len - 1))
|
||||
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## Computes the `MD5Digest` value for a string `s`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
|
||||
## of the `MD5Digest`
|
||||
## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
|
||||
runnableExamples:
|
||||
assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(d: MD5Digest): string =
|
||||
## Converts a `MD5Digest` value into its string representation.
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
add(result, digits[(d[i].int shr 4) and 0xF])
|
||||
add(result, digits[d[i].int and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
## Computes an MD5 value of `s` and returns its string representation.
|
||||
##
|
||||
## **See also:**
|
||||
## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
|
||||
runnableExamples:
|
||||
assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## Checks if two `MD5Digest` values are identical.
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
|
||||
proc clearBuffer(c: var MD5Context) {.inline.} =
|
||||
zeroMem(addr(c.buffer), sizeof(MD5Buffer))
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## Initializes an `MD5Context`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
c.state[0] = 0x67452301'u32
|
||||
c.state[1] = 0xEFCDAB89'u32
|
||||
c.state[2] = 0x98BADCFE'u32
|
||||
c.state[3] = 0x10325476'u32
|
||||
c.count[0] = 0'u32
|
||||
c.count[1] = 0'u32
|
||||
clearBuffer(c)
|
||||
|
||||
proc writeBuffer(c: var MD5Context, index: int,
|
||||
input: openArray[uint8], inputIndex, len: int) {.inline.} =
|
||||
copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len)
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) =
|
||||
## Updates the `MD5Context` with the `input` data.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
c.count[0] = c.count[0] + (uint32(input.len) shl 3)
|
||||
if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32
|
||||
c.count[1] = c.count[1] + (uint32(input.len) shr 29)
|
||||
var PartLen = 64 - Index
|
||||
if input.len >= PartLen:
|
||||
writeBuffer(c, Index, input, 0, PartLen)
|
||||
transform(c.buffer, c.state)
|
||||
var i = PartLen
|
||||
while i + 63 < input.len:
|
||||
transform(input.slice(i, i + 63), c.state)
|
||||
inc(i, 64)
|
||||
if i < input.len:
|
||||
writeBuffer(c, 0, input, i, input.len - i)
|
||||
elif input.len > 0:
|
||||
writeBuffer(c, Index, input, 0, input.len)
|
||||
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
## Finishes the `MD5Context` and stores the result in `digest`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var
|
||||
Bits: MD5CBits
|
||||
PadLen: int
|
||||
decode(Bits, c.count)
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
if Index < 56: PadLen = 56 - Index
|
||||
else: PadLen = 120 - Index
|
||||
md5Update(c, padding.slice(0, PadLen - 1))
|
||||
md5Update(c, Bits)
|
||||
decode(digest, c.state)
|
||||
clearBuffer(c)
|
||||
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.pop.} #{.push styleChecks: off.}
|
||||
@@ -11,8 +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 ../dist/checksums/src/checksums/md5
|
||||
import intsets, tables, hashes, md5_old
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
|
||||
import ic / [packed_ast, ic]
|
||||
|
||||
@@ -57,19 +56,6 @@ type
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
isDecl*: bool
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
SemPass
|
||||
JSgenPass
|
||||
CgenPass
|
||||
EvalPass
|
||||
InterpreterPass
|
||||
GenDependPass
|
||||
Docgen2TexPass
|
||||
Docgen2JsonPass
|
||||
Docgen2Pass
|
||||
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
ifaces*: seq[Iface] ## indexed by int32 fileIdx
|
||||
@@ -80,7 +66,6 @@ type
|
||||
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
|
||||
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
|
||||
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
|
||||
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
|
||||
enumToStringProcs*: Table[ItemId, LazySym]
|
||||
emittedTypeInfo*: Table[string, FileIndex]
|
||||
|
||||
@@ -119,7 +104,6 @@ type
|
||||
cacheCounters*: Table[string, BiggestInt] # IC: implemented
|
||||
cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented
|
||||
passes*: seq[TPass]
|
||||
pipelinePass*: PipelinePass
|
||||
onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
@@ -129,8 +113,6 @@ type
|
||||
idgen*: IdGenerator
|
||||
operators*: Operators
|
||||
|
||||
cachedFiles*: StringTableRef
|
||||
|
||||
TPassContext* = object of RootObj # the pass's context
|
||||
idgen*: IdGenerator
|
||||
PPassContext* = ref TPassContext
|
||||
@@ -251,7 +233,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 +254,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
|
||||
@@ -416,7 +398,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
||||
result = g.doStopCompile != nil and g.doStopCompile()
|
||||
|
||||
proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {})
|
||||
result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {})
|
||||
result.magic = m
|
||||
result.flags = {sfNeverRaises}
|
||||
|
||||
@@ -482,7 +464,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()
|
||||
|
||||
@@ -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 == "$":
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
|
||||
import
|
||||
ast, magicsys, msgs, options,
|
||||
idents, lexer, syntaxes, modulegraphs,
|
||||
lineinfos, pathutils
|
||||
idents, lexer, passes, syntaxes, llstream, modulegraphs,
|
||||
lineinfos, pathutils, tables, packages
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
import std/strtabs
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ic / replayer
|
||||
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
magicsys.resetSysTypes(g)
|
||||
@@ -23,12 +25,12 @@ proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
|
||||
getIdent(graph.cache, splitFile(filename).name)
|
||||
|
||||
proc partialInitModule*(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
let packSym = getPackage(graph, fileIdx)
|
||||
result.owner = packSym
|
||||
result.position = int fileIdx
|
||||
|
||||
proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
@@ -36,23 +38,103 @@ proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
name: getModuleIdent(graph, filename),
|
||||
info: newLineInfo(fileIdx, 1, 1))
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s &
|
||||
"'; a module name must be a valid Nim identifier.")
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
graph.registerModule(result)
|
||||
|
||||
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
var flags = flags
|
||||
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
|
||||
result = graph.getModule(fileIdx)
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
if sfMainModule in flags:
|
||||
if graph.config.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
var cachedModules: seq[FileIndex]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
processModuleAux("import(dirty)")
|
||||
graph.markClientsDirty(fileIdx)
|
||||
|
||||
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
|
||||
# this is called by the semantic checking phase
|
||||
assert graph.config != nil
|
||||
result = compileModule(graph, fileIdx, {}, s)
|
||||
graph.addDep(s, fileIdx)
|
||||
# keep track of import relationships
|
||||
if graph.config.hcrOn:
|
||||
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
|
||||
#if sfSystemModule in result.flags:
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
graph.config.notes =
|
||||
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
else: graph.config.foreignPackageNotes
|
||||
|
||||
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
|
||||
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 connectCallbacks*(graph: ModuleGraph) =
|
||||
graph.includeFileCallback = includeModule
|
||||
graph.importModuleCallback = importModule
|
||||
|
||||
proc compileSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
connectCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc wantMainModule*(conf: ConfigRef) =
|
||||
if conf.projectFull.isEmpty:
|
||||
fatal(conf, gCmdLineInfo, "command expects a filename")
|
||||
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
|
||||
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
configComplete(graph)
|
||||
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
|
||||
conf.projectMainIdx2 = projectFile
|
||||
|
||||
let packSym = getPackage(graph, projectFile)
|
||||
graph.config.mainPackageId = packSym.getPackageId
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
graph.compileSystemModule()
|
||||
discard graph.compileModule(projectFile, {sfMainModule})
|
||||
|
||||
proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
|
||||
result = graph.newModule(fileInfoIdx(graph.config, filename))
|
||||
registerModule(graph, result)
|
||||
|
||||
@@ -125,16 +125,9 @@ 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
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
if line < int high(uint16):
|
||||
@@ -226,7 +219,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
|
||||
|
||||
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
conf.m.fileInfos[fileIdx.int32].hash = hash
|
||||
else:
|
||||
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
|
||||
@@ -234,7 +227,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
|
||||
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
result = conf.m.fileInfos[fileIdx.int32].hash
|
||||
else:
|
||||
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
|
||||
@@ -429,8 +422,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 +430,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:
|
||||
@@ -516,8 +504,7 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
|
||||
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
|
||||
|
||||
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false,
|
||||
ignoreError = false) {.gcsafe, noinline.} =
|
||||
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.gcsafe, noinline.} =
|
||||
var
|
||||
title: string
|
||||
color: ForegroundColor
|
||||
@@ -547,21 +534,19 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
ignoreMsg = not conf.hasWarn(msg)
|
||||
if not ignoreMsg and msg in conf.warningAsErrors:
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
else:
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
if not ignoreMsg: writeContext(conf, info)
|
||||
color = WarningColor
|
||||
inc(conf.warnCounter)
|
||||
of hintMin..hintMax:
|
||||
sev = Severity.Hint
|
||||
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)
|
||||
@@ -583,8 +568,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
" compiler msg initiated here", KindColor,
|
||||
KindFormat % $hintMsgOrigin,
|
||||
resetStyle, conf.unitSep)
|
||||
if not ignoreError:
|
||||
handleError(conf, msg, eh, s, ignoreMsg)
|
||||
handleError(conf, msg, eh, s, ignoreMsg)
|
||||
if msg in fatalMsgs:
|
||||
# most likely would have died here but just in case, we restore state
|
||||
conf.m.errorOutputs = errorOutputsOld
|
||||
@@ -649,16 +633,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})
|
||||
|
||||
@@ -909,7 +909,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
else: ""
|
||||
|
||||
var cache = newIdentCache()
|
||||
var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info)
|
||||
var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info)
|
||||
|
||||
op.magic = magic
|
||||
result = nkInfix.newTree(
|
||||
@@ -920,7 +920,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
|
||||
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
var cache = newIdentCache()
|
||||
var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info)
|
||||
var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info)
|
||||
|
||||
op.magic = mNot
|
||||
result = nkPrefix.newTree(
|
||||
|
||||
@@ -7,15 +7,14 @@ define:nimcore
|
||||
define:nimPreviewFloatRoundtrip
|
||||
define:nimPreviewSlimSystem
|
||||
define:nimPreviewCstringConversion
|
||||
define:nimPreviewProcConversion
|
||||
define:nimPreviewRangeDefault
|
||||
define:nimPreviewNonVarDestructor
|
||||
threads:off
|
||||
|
||||
#import:"$projectpath/testability"
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
tlsEmulation:off
|
||||
@end
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
@@ -32,7 +31,6 @@ define:useStdoutAsStdmsg
|
||||
warning[ObservableStores]:off
|
||||
@end
|
||||
|
||||
|
||||
@if nimHasWarningAsError:
|
||||
warningAsError[GcUnsafe2]:on
|
||||
@end
|
||||
@@ -40,7 +38,3 @@ define:useStdoutAsStdmsg
|
||||
@if nimHasWarnUnnamedBreak:
|
||||
warningAserror[UnnamedBreak]:on
|
||||
@end
|
||||
|
||||
@if nimHasWarnBareExcept:
|
||||
warningAserror[BareExcept]:on
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,10 @@ import std/[os, strutils, parseopt]
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) and not defined(nimKochBootstrap):
|
||||
# remove workaround pending bootstrap >= 1.5.1
|
||||
# refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536
|
||||
# alternative would be to prepend `currentSourcePath.parentDir.quoteShell`
|
||||
when defined(gcc):
|
||||
when defined(x86):
|
||||
{.link: "../icons/nim.res".}
|
||||
@@ -38,15 +41,6 @@ when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
proc nimbleLockExists(config: ConfigRef): bool =
|
||||
const nimbleLock = "nimble.lock"
|
||||
let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
|
||||
if optSkipParentConfigFiles notin config.globalOptions:
|
||||
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
|
||||
if fileExists(dir / nimbleLock):
|
||||
return true
|
||||
return fileExists(pd.string / nimbleLock)
|
||||
|
||||
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
@@ -80,11 +74,6 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}:
|
||||
rawMessage(config, errGenerated, errArgsNeedRunOption)
|
||||
|
||||
if config.nimbleLockExists:
|
||||
# disable nimble path if nimble.lock is present.
|
||||
# see https://github.com/nim-lang/nimble/issues/1004
|
||||
disableNimblePath(config)
|
||||
|
||||
proc getNimRunExe(conf: ConfigRef): string =
|
||||
# xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to
|
||||
# customize the binary to run the command with, e.g. for custom `nodejs` or `wine`.
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||
|
||||
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
|
||||
tables
|
||||
std/sha1, tables
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
|
||||
if not conf.searchPaths.contains(path):
|
||||
conf.searchPaths.insert(path, 0)
|
||||
|
||||
@@ -9,16 +9,10 @@
|
||||
|
||||
## exposes the Nim VM to clients.
|
||||
import
|
||||
ast, modules, condsyms,
|
||||
options, llstream, lineinfos, vm,
|
||||
ast, astalgo, modules, passes, condsyms,
|
||||
options, sem, llstream, lineinfos, vm,
|
||||
vmdef, modulegraphs, idents, os, pathutils,
|
||||
scriptconfig, std/[compilesettings, tables]
|
||||
|
||||
import pipelines
|
||||
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, syncio]
|
||||
passaux, scriptconfig, std/compilesettings
|
||||
|
||||
type
|
||||
Interpreter* = ref object ## Use Nim as an interpreter with this object
|
||||
@@ -40,7 +34,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:
|
||||
@@ -78,14 +72,11 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
|
||||
assert i != nil
|
||||
assert i.mainModule != nil, "no main module selected"
|
||||
initStrTables(i.graph, i.mainModule)
|
||||
i.graph.cacheSeqs.clear()
|
||||
i.graph.cacheCounters.clear()
|
||||
i.graph.cacheTables.clear()
|
||||
i.mainModule.ast = nil
|
||||
|
||||
let s = if scriptStream != nil: scriptStream
|
||||
else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
|
||||
discard processPipelineModule(i.graph, i.mainModule, i.idgen, s)
|
||||
processModule(i.graph, i.mainModule, i.idgen, s)
|
||||
|
||||
proc findNimStdLib*(): string =
|
||||
## Tries to find a path to a valid "system.nim" file.
|
||||
@@ -118,10 +109,12 @@ proc createInterpreter*(scriptName: string;
|
||||
var conf = newConfigRef()
|
||||
var cache = newIdentCache()
|
||||
var graph = newModuleGraph(cache, conf)
|
||||
connectPipelineCallbacks(graph)
|
||||
connectCallbacks(graph)
|
||||
initDefines(conf.symbols)
|
||||
for define in defines:
|
||||
defineSymbol(conf.symbols, define[0], define[1])
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
|
||||
for p in searchPaths:
|
||||
conf.searchPaths.add(AbsoluteDir p)
|
||||
@@ -136,8 +129,7 @@ proc createInterpreter*(scriptName: string;
|
||||
if registerOps:
|
||||
vm.registerAdditionalOps() # Required to register parts of stdlib modules
|
||||
graph.vm = vm
|
||||
setPipeLinePass(graph, EvalPass)
|
||||
graph.compilePipelineSystemModule()
|
||||
graph.compileSystemModule()
|
||||
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName, idgen: idgen)
|
||||
|
||||
proc destroyInterpreter*(i: Interpreter) =
|
||||
@@ -167,11 +159,13 @@ proc runRepl*(r: TLLRepl;
|
||||
defineSymbol(conf.symbols, "nimscript")
|
||||
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
registerPass(graph, verbosePass)
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = idGeneratorFromModule(m)
|
||||
|
||||
if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)
|
||||
setPipeLinePass(graph, InterpreterPass)
|
||||
graph.compilePipelineSystemModule()
|
||||
discard processPipelineModule(graph, m, idgen, llStreamOpenStdIn(r))
|
||||
graph.compileSystemModule()
|
||||
processModule(graph, m, idgen, llStreamOpenStdIn(r))
|
||||
|
||||
111
compiler/nimfix/nimfix.nim
Normal file
111
compiler/nimfix/nimfix.nim
Normal file
@@ -0,0 +1,111 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
|
||||
|
||||
import strutils, os, parseopt
|
||||
import compiler/[options, commands, modules, sem,
|
||||
passes, passaux, linter,
|
||||
msgs, nimconf,
|
||||
extccomp, condsyms,
|
||||
modulegraphs, idents]
|
||||
|
||||
const Usage = """
|
||||
Nimfix - Tool to patch Nim code
|
||||
Usage:
|
||||
nimfix [options] projectfile.nim
|
||||
|
||||
Options:
|
||||
--overwriteFiles:on|off overwrite the original nim files.
|
||||
DEFAULT is ON!
|
||||
--wholeProject overwrite every processed file.
|
||||
--checkExtern:on|off style check also extern names
|
||||
--styleCheck:on|off|auto performs style checking for identifiers
|
||||
and suggests an alternative spelling;
|
||||
'auto' corrects the spelling.
|
||||
--bestEffort try to fix the code even when there
|
||||
are errors.
|
||||
|
||||
In addition, all command line options of Nim are supported.
|
||||
"""
|
||||
|
||||
proc mainCommand =
|
||||
registerPass verbosePass
|
||||
registerPass semPass
|
||||
conf.setCmd cmdNimfix
|
||||
searchPaths.add options.libpath
|
||||
if gProjectFull.len != 0:
|
||||
# current path is always looked first for modules
|
||||
searchPaths.insert(gProjectPath, 0)
|
||||
|
||||
compileProject(newModuleGraph(), newIdentCache())
|
||||
pretty.overwriteFiles()
|
||||
|
||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
gOnlyMainfile = true
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
case p.key.normalize
|
||||
of "overwritefiles":
|
||||
case p.val.normalize
|
||||
of "on": gOverWrite = true
|
||||
of "off": gOverWrite = false
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "checkextern":
|
||||
case p.val.normalize
|
||||
of "on": gCheckExtern = true
|
||||
of "off": gCheckExtern = false
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "stylecheck":
|
||||
case p.val.normalize
|
||||
of "off": gStyleCheck = StyleCheck.None
|
||||
of "on": gStyleCheck = StyleCheck.Warn
|
||||
of "auto": gStyleCheck = StyleCheck.Auto
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "wholeproject": gOnlyMainfile = false
|
||||
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
|
||||
else:
|
||||
processSwitch(pass, p, config)
|
||||
of cmdArgument:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
# if processArgument(pass, p, argsCount): break
|
||||
|
||||
proc handleCmdLine(config: ConfigRef) =
|
||||
if paramCount() == 0:
|
||||
stdout.writeLine(Usage)
|
||||
else:
|
||||
processCmdLine(passCmd1, "", config)
|
||||
if gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
gProjectName = p.name
|
||||
else:
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig, config) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "", config)
|
||||
mainCommand()
|
||||
|
||||
when compileOption("gc", "refc"):
|
||||
GC_disableMarkAndSweep()
|
||||
|
||||
condsyms.initDefines()
|
||||
defineSymbol "nimfix"
|
||||
handleCmdline newConfigRef()
|
||||
17
compiler/nimfix/nimfix.nim.cfg
Normal file
17
compiler/nimfix/nimfix.nim.cfg
Normal file
@@ -0,0 +1,17 @@
|
||||
# Special configuration file for the Nim project
|
||||
# gc:markAndSweep
|
||||
|
||||
hint[XDeclaredButNotUsed]:off
|
||||
path:"$projectPath/.."
|
||||
|
||||
path:"$lib/packages/docutils"
|
||||
path:"$nim"
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
symbol:nimfix
|
||||
define:nimfix
|
||||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
define:booting
|
||||
define:noDocgen
|
||||
45
compiler/nimfix/prettybase.nim
Normal file
45
compiler/nimfix/prettybase.nim
Normal file
@@ -0,0 +1,45 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import strutils except Letters
|
||||
import ".." / [ast, msgs, lineinfos, idents, options, linter]
|
||||
|
||||
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
|
||||
let line = sourceLine(conf, info)
|
||||
var first = min(info.col.int, line.len)
|
||||
if first < 0: return
|
||||
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||
while first > 0 and line[first-1] in Letters: dec first
|
||||
if first < 0: return
|
||||
if line[first] == '`': inc first
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
conf.m.fileInfos[info.fileIndex.int32].dirty = true
|
||||
#if newSym.s == "File": writeStackTrace()
|
||||
|
||||
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
|
||||
replaceDeprecated(conf, info, oldSym.name, newSym.name)
|
||||
|
||||
proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
|
||||
let line = sourceLine(conf, info)
|
||||
var first = info.col.int
|
||||
if line[first] != '#': inc first
|
||||
|
||||
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
conf.m.fileInfos[info.fileIndex.int32].dirty = true
|
||||
@@ -7,4 +7,4 @@ proc findNodeJs*(): string {.inline.} =
|
||||
result = findExe("node")
|
||||
if result.len == 0:
|
||||
echo "Please install NodeJS first, see https://nodejs.org/en/download"
|
||||
raise newException(IOError, "NodeJS not found in PATH")
|
||||
raise newException(IOError, "NodeJS not found in PATH: " & result)
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
DefaultSetElements* = 1 shl 8
|
||||
## assumed set element count when using int literals
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@ import
|
||||
|
||||
from trees import exprStructuralEquivalent
|
||||
|
||||
import std/strutils
|
||||
|
||||
const
|
||||
nfMarkForDeletion = nfNone # faster than a lookup table
|
||||
|
||||
@@ -112,17 +110,16 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
|
||||
var reverse = false
|
||||
if n[0].kind == nkSym:
|
||||
let s = n[0].sym
|
||||
let name = s.name.s.normalize
|
||||
if name == "=wasmoved":
|
||||
if s.magic == mWasMoved:
|
||||
b.wasMovedLocs.add n
|
||||
special = true
|
||||
elif name == "=destroy":
|
||||
elif s.name.s == "=destroy":
|
||||
if c.inFinally > 0 and (b.hasReturn or b.hasBreak):
|
||||
discard "cannot optimize away the destructor"
|
||||
else:
|
||||
c.wasMovedDestroyPair b, n
|
||||
special = true
|
||||
elif name == "=sink":
|
||||
elif s.name.s == "=sink":
|
||||
reverse = true
|
||||
|
||||
if not special:
|
||||
@@ -279,8 +276,8 @@ 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 c: Con
|
||||
var b: BasicBlock
|
||||
analyse(c, b, n)
|
||||
if c.somethingTodo:
|
||||
result = shallowCopy(n)
|
||||
|
||||
@@ -24,7 +24,7 @@ const
|
||||
useEffectSystem* = true
|
||||
useWriteTracking* = false
|
||||
hasFFI* = defined(nimHasLibFFI)
|
||||
copyrightYear* = "2023"
|
||||
copyrightYear* = "2022"
|
||||
|
||||
nimEnableCovariance* = defined(nimEnableCovariance)
|
||||
|
||||
@@ -49,7 +49,6 @@ type # please make sure we have under 32 options
|
||||
optSinkInference # 'sink T' inference
|
||||
optCursorInference
|
||||
optImportHidden
|
||||
optQuirky
|
||||
|
||||
TOptions* = set[TOption]
|
||||
TGlobalOption* = enum
|
||||
@@ -79,8 +78,6 @@ type # please make sure we have under 32 options
|
||||
optThreadAnalysis, # thread analysis pass
|
||||
optTlsEmulation, # thread var emulation turned on
|
||||
optGenIndex # generate index file for documentation;
|
||||
optGenIndexOnly # generate only index file for documentation
|
||||
optNoImportdoc # disable loading external documentation files
|
||||
optEmbedOrigSrc # embed the original source in the generated code
|
||||
# also: generate header file
|
||||
optIdeDebug # idetools: debug mode
|
||||
@@ -103,11 +100,12 @@ type # please make sure we have under 32 options
|
||||
optBenchmarkVM # Enables cpuTime() in the VM
|
||||
optProduceAsm # produce assembler code
|
||||
optPanics # turn panics (sysFatal) into a process termination
|
||||
optNimV1Emulation # emulate Nim v1.0
|
||||
optNimV12Emulation # emulate Nim v1.2
|
||||
optNimV16Emulation # emulate Nim v1.6
|
||||
optSourcemap
|
||||
optProfileVM # enable VM profiler
|
||||
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
|
||||
optShowNonExportedFields # for documentation: show fields that are not exported
|
||||
optJsBigInt64 # use bigints for 64-bit integers in JS
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
@@ -167,6 +165,7 @@ type
|
||||
cmdInteractive # start interactive session
|
||||
cmdNop
|
||||
cmdJsonscript # compile a .json build file
|
||||
cmdNimfix
|
||||
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
|
||||
|
||||
const
|
||||
@@ -184,7 +183,6 @@ type
|
||||
gcRegions = "regions"
|
||||
gcArc = "arc"
|
||||
gcOrc = "orc"
|
||||
gcAtomicArc = "atomicArc"
|
||||
gcMarkAndSweep = "markAndSweep"
|
||||
gcHooks = "hooks"
|
||||
gcRefc = "refc"
|
||||
@@ -195,7 +193,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
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
dotOperators,
|
||||
@@ -220,10 +218,7 @@ type
|
||||
unicodeOperators, # deadcode
|
||||
flexibleOptionalParams,
|
||||
strictDefs,
|
||||
strictCaseObjects,
|
||||
openSym, # remove nfDisabledOpenSym when this is default
|
||||
# alternative to above:
|
||||
genericsOpenSym
|
||||
strictCaseObjects
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -236,7 +231,6 @@ type
|
||||
## are not anymore.
|
||||
laxEffects
|
||||
## Lax effects system prior to Nim 2.0.
|
||||
verboseTypeMismatch
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
@@ -281,26 +275,8 @@ type
|
||||
scope*, localUsages*, globalUsages*: int # more usages is better
|
||||
tokenLen*: int
|
||||
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
|
||||
@@ -352,7 +328,6 @@ type
|
||||
|
||||
cppDefines*: HashSet[string] # (*)
|
||||
headerFile*: string
|
||||
nimbasePattern*: string # pattern to find nimbase.h
|
||||
features*: set[Feature]
|
||||
legacyFeatures*: set[LegacyFeature]
|
||||
arguments*: string ## the arguments to be passed to the program that
|
||||
@@ -430,14 +405,6 @@ type
|
||||
nimMainPrefix*: string
|
||||
vmProfileData*: ProfileData
|
||||
|
||||
expandProgress*: bool
|
||||
expandLevels*: int
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
clientProcessId*: int
|
||||
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
if a.len > 0:
|
||||
@@ -500,8 +467,7 @@ const
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
|
||||
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
|
||||
optTrMacros, optStyleCheck, optCursorInference}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
|
||||
optJsBigInt64}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace}
|
||||
|
||||
proc getSrcTimestamp(): DateTime =
|
||||
try:
|
||||
@@ -643,7 +609,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr, osNuttX}
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr}
|
||||
of "linux":
|
||||
result = conf.target.targetOS in {osLinux, osAndroid}
|
||||
of "bsd":
|
||||
@@ -665,8 +631,6 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
result = conf.target.targetOS == osFreeRTOS
|
||||
of "zephyr":
|
||||
result = conf.target.targetOS == osZephyr
|
||||
of "nuttx":
|
||||
result = conf.target.targetOS == osNuttX
|
||||
of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
|
||||
of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
|
||||
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
|
||||
@@ -741,24 +705,22 @@ proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
|
||||
## clone or using installed nim, so that these exist: `result/doc/advopt.txt`
|
||||
## and `result/lib/system.nim`
|
||||
if not conf.prefixDir.isEmpty: result = conf.prefixDir
|
||||
else:
|
||||
let binParent = AbsoluteDir splitPath(getAppDir()).head
|
||||
when defined(posix):
|
||||
if binParent == AbsoluteDir"/usr":
|
||||
result = AbsoluteDir"/usr/lib/nim"
|
||||
elif binParent == AbsoluteDir"/usr/local":
|
||||
result = AbsoluteDir"/usr/local/lib/nim"
|
||||
else:
|
||||
result = binParent
|
||||
else:
|
||||
result = binParent
|
||||
else: result = AbsoluteDir splitPath(getAppDir()).head
|
||||
|
||||
proc setDefaultLibpath*(conf: ConfigRef) =
|
||||
# set default value (can be overwritten):
|
||||
if conf.libpath.isEmpty:
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir(conf)
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
when defined(posix):
|
||||
if prefix == AbsoluteDir"/usr":
|
||||
conf.libpath = AbsoluteDir"/usr/lib/nim"
|
||||
elif prefix == AbsoluteDir"/usr/local":
|
||||
conf.libpath = AbsoluteDir"/usr/local/lib/nim"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
|
||||
# Special rule to support other tools (nimble) which import the compiler
|
||||
# modules and make use of them.
|
||||
@@ -888,6 +850,14 @@ template patchModule(conf: ConfigRef) {.dirty.} =
|
||||
let ov = conf.moduleOverrides[key]
|
||||
if ov.len > 0: result = AbsoluteFile(ov)
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo):
|
||||
proc isRelativeTo(path, base: string): bool =
|
||||
# pending #13212 use os.isRelativeTo
|
||||
let path = path.normalizedPath
|
||||
let base = base.normalizedPath
|
||||
let ret = relativePath(path, base)
|
||||
result = path.len > 0 and not ret.startsWith ".."
|
||||
|
||||
const stdlibDirs* = [
|
||||
"pure", "core", "arch",
|
||||
"pure/collections",
|
||||
@@ -932,7 +902,6 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile =
|
||||
# returns path to module
|
||||
var m = addFileExt(modulename, NimExt)
|
||||
var hasRelativeDot = false
|
||||
if m.startsWith(pkgPrefix):
|
||||
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
|
||||
else:
|
||||
@@ -946,11 +915,7 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi
|
||||
else: # If prefixed with std/ why would we add the current module path!
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = AbsoluteFile currentPath / m
|
||||
if m.startsWith('.') and not fileExists(result):
|
||||
result = AbsoluteFile ""
|
||||
hasRelativeDot = true
|
||||
|
||||
if not fileExists(result) and not hasRelativeDot:
|
||||
if not fileExists(result):
|
||||
result = findFile(conf, m)
|
||||
patchModule(conf)
|
||||
|
||||
@@ -1028,12 +993,6 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
|
||||
result = optDynlibOverrideAll in conf.globalOptions or
|
||||
conf.dllOverrides.hasKey(lib.canonDynlibName)
|
||||
|
||||
proc showNonExportedFields*(conf: ConfigRef) =
|
||||
incl(conf.globalOptions, optShowNonExportedFields)
|
||||
|
||||
proc expandDone*(conf: ConfigRef): bool =
|
||||
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
of "sug": ideSug
|
||||
@@ -1073,11 +1032,9 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideProject: "project"
|
||||
of ideGlobalSymbols: "globalSymbols"
|
||||
of ideDeclaration: "declaration"
|
||||
of ideExpand: "expand"
|
||||
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.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## Package related procs.
|
||||
##
|
||||
##
|
||||
## See Also:
|
||||
## * `packagehandling` for package path handling
|
||||
## * `modulegraphs.getPackage`
|
||||
@@ -22,7 +22,7 @@ when defined(nimPreviewSlimSystem):
|
||||
|
||||
proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
## Return a new package symbol.
|
||||
##
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.getPackage`
|
||||
let
|
||||
@@ -31,7 +31,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
info = newLineInfo(fileIdx, 1, 1)
|
||||
pkgName = getPackageName(conf, filename.string)
|
||||
pkgIdent = getIdent(cache, pkgName)
|
||||
newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info)
|
||||
newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
|
||||
|
||||
func getPackageSymbol*(sym: PSym): PSym =
|
||||
## Return the owning package symbol.
|
||||
@@ -47,15 +47,7 @@ func getPackageId*(sym: PSym): int =
|
||||
|
||||
func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
|
||||
## Return whether the symbol belongs to the project's package.
|
||||
##
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
conf.mainPackageId == sym.getPackageId
|
||||
|
||||
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
|
||||
|
||||
@@ -280,15 +280,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
|
||||
|
||||
@@ -42,7 +42,7 @@ when isMainModule or defined(nimTestGrammar):
|
||||
|
||||
proc checkSameGrammar*() =
|
||||
doAssert sameFileContent(newGrammarText, "doc/grammar.txt"),
|
||||
"execute 'nim r compiler/parser.nim' to keep grammar.txt up-to-date"
|
||||
"execute 'nim r compiler.nim' to keep grammar.txt up-to-date"
|
||||
else:
|
||||
writeGrammarFile("doc/grammar.txt")
|
||||
import ".." / tools / grammar_nanny
|
||||
@@ -301,16 +301,17 @@ proc isRightAssociative(tok: Token): bool {.inline.} =
|
||||
proc isUnary(tok: Token): bool =
|
||||
## Check if the given token is a unary operator
|
||||
tok.tokType in {tkOpr, tkDotDot} and
|
||||
tok.spacing == {tsLeading}
|
||||
tok.strongSpaceB == tsNone and
|
||||
tok.strongSpaceA
|
||||
|
||||
proc checkBinary(p: Parser) {.inline.} =
|
||||
## Check if the current parser token is a binary operator.
|
||||
# we don't check '..' here as that's too annoying
|
||||
if p.tok.tokType == tkOpr:
|
||||
if p.tok.spacing == {tsTrailing}:
|
||||
if p.tok.strongSpaceB == tsTrailing and not p.tok.strongSpaceA:
|
||||
parMessage(p, warnInconsistentSpacing, prettyTok(p.tok))
|
||||
|
||||
#| module = complexOrSimpleStmt ^* (';' / IND{=})
|
||||
#| module = stmt ^* (';' / IND{=})
|
||||
#|
|
||||
#| comma = ',' COMMENT?
|
||||
#| semicolon = ';' COMMENT?
|
||||
@@ -320,7 +321,7 @@ proc checkBinary(p: Parser) {.inline.} =
|
||||
#| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
|
||||
#| | 'or' | 'xor' | 'and'
|
||||
#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from'
|
||||
#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | '..'
|
||||
#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
|
||||
#|
|
||||
#| prefixOperator = operator
|
||||
#|
|
||||
@@ -353,16 +354,9 @@ proc colcom(p: var Parser, n: PNode) =
|
||||
|
||||
const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
|
||||
|
||||
template setEndInfo() =
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = TLineInfo(fileIndex: p.lex.fileIdx,
|
||||
line: p.lex.previousTokenEnd.line,
|
||||
col: p.lex.previousTokenEnd.col)
|
||||
|
||||
proc parseSymbol(p: var Parser, mode = smNormal): PNode =
|
||||
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
#| | IDENT | 'addr' | 'type' | 'static'
|
||||
#| symbolOrKeyword = symbol | KEYW
|
||||
#| | IDENT | KEYW
|
||||
case p.tok.tokType
|
||||
of tkSymbol:
|
||||
result = newIdentNodeP(p.tok.ident, p)
|
||||
@@ -412,7 +406,6 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
|
||||
# if it is a keyword:
|
||||
#if not isKeyword(p.tok.tokType): getTok(p)
|
||||
result = p.emptyNode
|
||||
setEndInfo()
|
||||
|
||||
proc equals(p: var Parser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkEquals:
|
||||
@@ -436,8 +429,7 @@ proc colonOrEquals(p: var Parser, a: PNode): PNode =
|
||||
result = equals(p, a)
|
||||
|
||||
proc exprColonEqExpr(p: var Parser): PNode =
|
||||
#| exprColonEqExpr = expr ((':'|'=') expr
|
||||
#| / doBlock extraPostExprBlock*)?
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, a)
|
||||
@@ -445,8 +437,7 @@ proc exprColonEqExpr(p: var Parser): PNode =
|
||||
result = colonOrEquals(p, a)
|
||||
|
||||
proc exprEqExpr(p: var Parser): PNode =
|
||||
#| exprEqExpr = expr ('=' expr
|
||||
#| / doBlock extraPostExprBlock*)?
|
||||
#| exprEqExpr = expr ('=' expr)?
|
||||
var a = parseExpr(p)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, a)
|
||||
@@ -517,7 +508,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
|
||||
optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseSymbol(p, smAfterDot))
|
||||
if p.tok.tokType == tkBracketLeColon and tsLeading notin p.tok.spacing:
|
||||
if p.tok.tokType == tkBracketLeColon and not p.tok.strongSpaceA:
|
||||
var x = newNodeI(nkBracketExpr, p.parLineInfo)
|
||||
# rewrite 'x.y[:z]()' to 'y[z](x)'
|
||||
x.add result[1]
|
||||
@@ -526,7 +517,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
|
||||
var y = newNodeI(nkCall, p.parLineInfo)
|
||||
y.add x
|
||||
y.add result[0]
|
||||
if p.tok.tokType == tkParLe and tsLeading notin p.tok.spacing:
|
||||
if p.tok.tokType == tkParLe and not p.tok.strongSpaceA:
|
||||
exprColonEqExprListAux(p, tkParRi, y)
|
||||
result = y
|
||||
|
||||
@@ -541,7 +532,7 @@ proc dotLikeExpr(p: var Parser, a: PNode): PNode =
|
||||
result.add(parseSymbol(p, smAfterDot))
|
||||
|
||||
proc qualifiedIdent(p: var Parser): PNode =
|
||||
#| qualifiedIdent = symbol ('.' optInd symbolOrKeyword)?
|
||||
#| qualifiedIdent = symbol ('.' optInd symbol)?
|
||||
result = parseSymbol(p)
|
||||
if p.tok.tokType == tkDot: result = dotExpr(p, result)
|
||||
|
||||
@@ -586,7 +577,6 @@ proc parseCast(p: var Parser): PNode =
|
||||
result.add(exprColonEqExpr(p))
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
setEndInfo()
|
||||
|
||||
proc setBaseFlags(n: PNode, base: NumericalBase) =
|
||||
case base
|
||||
@@ -609,7 +599,6 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
|
||||
getTok(p)
|
||||
else:
|
||||
result = a
|
||||
setEndInfo()
|
||||
|
||||
proc complexOrSimpleStmt(p: var Parser): PNode
|
||||
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
|
||||
@@ -649,8 +638,7 @@ proc parsePar(p: var Parser): PNode =
|
||||
#| ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | pragmaStmt
|
||||
#| | simpleExpr ( (doBlock extraPostExprBlock*)
|
||||
#| | ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
#| optPar ')'
|
||||
#
|
||||
@@ -715,7 +703,6 @@ proc parsePar(p: var Parser): PNode =
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
setEndInfo()
|
||||
|
||||
proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode =
|
||||
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
@@ -872,8 +859,8 @@ proc isDotLike(tok: Token): bool =
|
||||
proc primarySuffix(p: var Parser, r: PNode,
|
||||
baseIndent: int, mode: PrimaryMode): PNode =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')'
|
||||
#| | '.' optInd symbolOrKeyword ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit?
|
||||
#| | DOTLIKEOP optInd symbolOrKeyword generalizedLit?
|
||||
#| | '.' optInd symbol ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit?
|
||||
#| | DOTLIKEOP optInd symbol generalizedLit?
|
||||
#| | '[' optInd exprColonEqExprList optPar ']'
|
||||
#| | '{' optInd exprColonEqExprList optPar '}'
|
||||
# XXX strong spaces need to be reflected above
|
||||
@@ -885,7 +872,7 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
case p.tok.tokType
|
||||
of tkParLe:
|
||||
# progress guaranteed
|
||||
if tsLeading in p.tok.spacing:
|
||||
if p.tok.strongSpaceA:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
@@ -897,13 +884,13 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
result = parseGStrLit(p, result)
|
||||
of tkBracketLe:
|
||||
# progress guaranteed
|
||||
if tsLeading in p.tok.spacing:
|
||||
if p.tok.strongSpaceA:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkCurlyLe:
|
||||
# progress guaranteed
|
||||
if tsLeading in p.tok.spacing:
|
||||
if p.tok.strongSpaceA:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
@@ -954,7 +941,6 @@ proc parseOperators(p: var Parser, headNode: PNode,
|
||||
a.add(b)
|
||||
result = a
|
||||
opPrec = getPrecedence(p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode =
|
||||
var mode = mode
|
||||
@@ -1004,11 +990,10 @@ proc parsePragma(p: var Parser): PNode =
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
dec p.em.keepIndents
|
||||
setEndInfo()
|
||||
|
||||
proc identVis(p: var Parser; allowDot=false): PNode =
|
||||
#| identVis = symbol OPR? # postfix position
|
||||
#| identVisDot = symbol '.' optInd symbolOrKeyword OPR?
|
||||
#| identVisDot = symbol '.' optInd symbol OPR?
|
||||
var a = parseSymbol(p)
|
||||
if p.tok.tokType == tkOpr:
|
||||
when defined(nimpretty):
|
||||
@@ -1073,7 +1058,6 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result.add(newNodeP(nkEmpty, p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTuple(p: var Parser, indentAllowed = false): PNode =
|
||||
#| tupleTypeBracket = '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
@@ -1118,7 +1102,6 @@ proc parseTuple(p: var Parser, indentAllowed = false): PNode =
|
||||
parMessage(p, errGenerated, "the syntax for tuple types is 'tuple[...]', not 'tuple(...)'")
|
||||
else:
|
||||
result = newNodeP(nkTupleClassTy, p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseParamList(p: var Parser, retColon = true): PNode =
|
||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
@@ -1167,7 +1150,6 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
dec p.em.keepIndents
|
||||
setEndInfo()
|
||||
|
||||
proc optPragmas(p: var Parser): PNode =
|
||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
|
||||
@@ -1188,7 +1170,6 @@ proc parseDoBlock(p: var Parser; info: TLineInfo): PNode =
|
||||
result = newProcNode(nkDo, info,
|
||||
body = result, params = params, name = p.emptyNode, pattern = p.emptyNode,
|
||||
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
|
||||
#| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
@@ -1200,22 +1181,17 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
|
||||
let pragmas = optPragmas(p)
|
||||
if p.tok.tokType == tkEquals and isExpr:
|
||||
getTok(p)
|
||||
result = newProcNode(kind, info, body = p.emptyNode,
|
||||
skipComment(p, result)
|
||||
result = newProcNode(kind, info, body = parseStmt(p),
|
||||
params = params, name = p.emptyNode, pattern = p.emptyNode,
|
||||
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
|
||||
skipComment(p, result)
|
||||
result[bodyPos] = parseStmt(p)
|
||||
else:
|
||||
result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
|
||||
if hasSignature or pragmas.kind != nkEmpty:
|
||||
if hasSignature:
|
||||
result.add(params)
|
||||
else: # pragmas but no param list, implies typeclass with pragmas
|
||||
result.add(p.emptyNode)
|
||||
if hasSignature:
|
||||
result.add(params)
|
||||
if kind == nkFuncDef:
|
||||
parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
|
||||
result.add(pragmas)
|
||||
setEndInfo()
|
||||
|
||||
proc isExprStart(p: Parser): bool =
|
||||
case p.tok.tokType
|
||||
@@ -1235,7 +1211,6 @@ proc parseSymbolList(p: var Parser, result: PNode) =
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, s)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
mode: PrimaryMode): PNode =
|
||||
@@ -1264,7 +1239,6 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
parseSymbolList(p, list)
|
||||
if mode == pmTypeDef and not isTypedef:
|
||||
result = parseOperators(p, result, -1, mode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode
|
||||
|
||||
@@ -1290,7 +1264,6 @@ proc parseFor(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
template nimprettyDontTouch(body) =
|
||||
when defined(nimpretty):
|
||||
@@ -1329,7 +1302,6 @@ proc parseExpr(p: var Parser): PNode =
|
||||
nimprettyDontTouch:
|
||||
result = parseTry(p, isExpr=true)
|
||||
else: result = simpleExpr(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseEnum(p: var Parser): PNode
|
||||
proc parseObject(p: var Parser): PNode
|
||||
@@ -1339,7 +1311,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
|
||||
#| simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix*
|
||||
#| commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'|
|
||||
#| 'static'|'enum'|'tuple'|'object'|'proc')
|
||||
#| primary = simplePrimary (commandStart expr (doBlock extraPostExprBlock*)?)?
|
||||
#| primary = simplePrimary (commandStart expr)
|
||||
#| / operatorB primary
|
||||
#| / routineExpr
|
||||
#| / rawTypeDesc
|
||||
@@ -1396,7 +1368,7 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
|
||||
let notOpr = newIdentNodeP(p.tok.ident, p)
|
||||
getTok(p)
|
||||
optInd(p, notOpr)
|
||||
let b = primary(p, pmTypeDesc)
|
||||
let b = parseExpr(p)
|
||||
result = newNodeP(nkInfix, p)
|
||||
result.add notOpr
|
||||
result.add a
|
||||
@@ -1407,8 +1379,8 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
|
||||
proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
#| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' |
|
||||
#| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?)
|
||||
#| ('not' primary)?
|
||||
#| typeDescExpr = (routineType / simpleExpr) ('not' primary)?
|
||||
#| ('not' expr)?
|
||||
#| typeDescExpr = (routineType / simpleExpr) ('not' expr)?
|
||||
#| typeDesc = rawTypeDesc / typeDescExpr
|
||||
newlineWasSplitting(p)
|
||||
if fullExpr:
|
||||
@@ -1430,7 +1402,6 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkConcept:
|
||||
result = p.emptyNode
|
||||
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)
|
||||
@@ -1440,13 +1411,12 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
else:
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDefValue(p: var Parser): PNode =
|
||||
#| typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
|
||||
#| ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl))
|
||||
#| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks?)?))
|
||||
#| ('not' primary)?
|
||||
#| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?))
|
||||
#| ('not' expr)?
|
||||
case p.tok.tokType
|
||||
of tkTuple: result = parseTuple(p, true)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDef)
|
||||
@@ -1471,7 +1441,6 @@ proc parseTypeDefValue(p: var Parser): PNode =
|
||||
result.add(commandParam(p, isFirstParam, pmTypeDef))
|
||||
result = postExprBlocks(p, result)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc makeCall(n: PNode): PNode =
|
||||
## Creates a call if the given node isn't already a call.
|
||||
@@ -1482,13 +1451,12 @@ proc makeCall(n: PNode): PNode =
|
||||
result.add n
|
||||
|
||||
proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
#| extraPostExprBlock = ( IND{=} doBlock
|
||||
#| | IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' optionalExprList ':' stmt
|
||||
#| | IND{=} 'finally' ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )
|
||||
#| postExprBlocks = (doBlock / ':' (extraPostExprBlock / stmt)) extraPostExprBlock*
|
||||
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
#| | IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' optionalExprList ':' stmt
|
||||
#| | IND{=} 'finally' ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
result = x
|
||||
if p.tok.indent >= 0: return
|
||||
|
||||
@@ -1505,7 +1473,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
result = makeCall(result)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
if not (p.tok.tokType in {tkOf, tkElif, tkElse, tkExcept, tkFinally} and sameInd(p)):
|
||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
var stmtList = newNodeP(nkStmtList, p)
|
||||
stmtList.add parseStmt(p)
|
||||
# to keep backwards compatibility (see tests/vm/tstringnil)
|
||||
@@ -1593,7 +1561,6 @@ proc parseExprStmt(p: var Parser): PNode =
|
||||
else:
|
||||
result = a
|
||||
result = postExprBlocks(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = parseExpr(p)
|
||||
@@ -1605,7 +1572,6 @@ proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseImport(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| importStmt = 'import' optInd expr
|
||||
@@ -1634,7 +1600,6 @@ proc parseImport(p: var Parser, kind: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIncludeStmt(p: var Parser): PNode =
|
||||
#| includeStmt = 'include' optInd expr ^+ comma
|
||||
@@ -1651,7 +1616,6 @@ proc parseIncludeStmt(p: var Parser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseFromStmt(p: var Parser): PNode =
|
||||
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
@@ -1672,7 +1636,6 @@ proc parseFromStmt(p: var Parser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| returnStmt = 'return' optInd expr?
|
||||
@@ -1694,7 +1657,6 @@ proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
|
||||
var e = parseExpr(p)
|
||||
e = postExprBlocks(p, e)
|
||||
result.add(e)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condStmt = expr colcom stmt COMMENT?
|
||||
@@ -1719,12 +1681,11 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condExpr = expr colcom stmt optInd
|
||||
#| ('elif' expr colcom stmt optInd)*
|
||||
#| 'else' colcom stmt
|
||||
#| condExpr = expr colcom expr optInd
|
||||
#| ('elif' expr colcom expr optInd)*
|
||||
#| 'else' colcom expr
|
||||
#| ifExpr = 'if' condExpr
|
||||
#| whenExpr = 'when' condExpr
|
||||
result = newNodeP(kind, p)
|
||||
@@ -1744,7 +1705,6 @@ proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseWhile(p: var Parser): PNode =
|
||||
#| whileStmt = 'while' expr colcom stmt
|
||||
@@ -1754,7 +1714,6 @@ proc parseWhile(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseCase(p: var Parser): PNode =
|
||||
#| ofBranch = 'of' exprList colcom stmt
|
||||
@@ -1802,7 +1761,6 @@ proc parseCase(p: var Parser): PNode =
|
||||
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
setEndInfo()
|
||||
|
||||
proc parseTry(p: var Parser; isExpr: bool): PNode =
|
||||
#| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
|
||||
@@ -1812,13 +1770,11 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
|
||||
#| (optInd 'except' optionalExprList colcom stmt)*
|
||||
#| (optInd 'finally' colcom stmt)?
|
||||
result = newNodeP(nkTryStmt, p)
|
||||
let parentIndent = p.currInd # isExpr
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
var b: PNode = nil
|
||||
|
||||
while sameOrNoInd(p) or (isExpr and parentIndent <= p.tok.indent):
|
||||
while sameOrNoInd(p) or isExpr:
|
||||
case p.tok.tokType
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
@@ -1831,14 +1787,12 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
|
||||
b.add(parseStmt(p))
|
||||
result.add(b)
|
||||
if b == nil: parMessage(p, "expected 'except'")
|
||||
setEndInfo()
|
||||
|
||||
proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseBlock(p: var Parser): PNode =
|
||||
#| blockStmt = 'block' symbol? colcom stmt
|
||||
@@ -1849,7 +1803,6 @@ proc parseBlock(p: var Parser): PNode =
|
||||
else: result.add(parseSymbol(p))
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
|
||||
#| staticStmt = 'static' colcom stmt
|
||||
@@ -1858,7 +1811,6 @@ proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseAsm(p: var Parser): PNode =
|
||||
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
||||
@@ -1875,7 +1827,6 @@ proc parseAsm(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
return
|
||||
getTok(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseGenericParam(p: var Parser): PNode =
|
||||
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
|
||||
@@ -1911,7 +1862,6 @@ proc parseGenericParam(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result.add(p.emptyNode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseGenericParamList(p: var Parser): PNode =
|
||||
#| genericParamList = '[' optInd
|
||||
@@ -1930,14 +1880,12 @@ proc parseGenericParamList(p: var Parser): PNode =
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkBracketRi)
|
||||
setEndInfo()
|
||||
|
||||
proc parsePattern(p: var Parser): PNode =
|
||||
#| pattern = '{' stmt '}'
|
||||
eat(p, tkCurlyLe)
|
||||
result = parseStmt(p)
|
||||
eat(p, tkCurlyRi)
|
||||
setEndInfo()
|
||||
|
||||
proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
|
||||
@@ -1982,7 +1930,6 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
|
||||
#else:
|
||||
# assert false, p.lex.config$body.info # avoids hard to track bugs, fail early.
|
||||
# Yeah, that worked so well. There IS a bug in this logic, now what?
|
||||
setEndInfo()
|
||||
|
||||
proc newCommentStmt(p: var Parser): PNode =
|
||||
#| commentStmt = COMMENT
|
||||
@@ -2018,7 +1965,6 @@ proc parseSection(p: var Parser, kind: TNodeKind,
|
||||
result.add(defparser(p))
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc parseEnum(p: var Parser): PNode =
|
||||
#| enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
|
||||
@@ -2065,7 +2011,6 @@ proc parseEnum(p: var Parser): PNode =
|
||||
break
|
||||
if result.len <= 1:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectPart(p: var Parser): PNode
|
||||
proc parseObjectWhen(p: var Parser): PNode =
|
||||
@@ -2091,7 +2036,6 @@ proc parseObjectWhen(p: var Parser): PNode =
|
||||
branch.add(parseObjectPart(p))
|
||||
flexComment(p, branch)
|
||||
result.add(branch)
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectCase(p: var Parser): PNode =
|
||||
#| objectBranch = 'of' exprList colcom objectPart
|
||||
@@ -2133,7 +2077,6 @@ proc parseObjectCase(p: var Parser): PNode =
|
||||
if b.kind == nkElse: break
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
setEndInfo()
|
||||
|
||||
proc parseObjectPart(p: var Parser): PNode =
|
||||
#| objectPart = IND{>} objectPart^+IND{=} DED
|
||||
@@ -2166,7 +2109,6 @@ proc parseObjectPart(p: var Parser): PNode =
|
||||
result = p.emptyNode
|
||||
else:
|
||||
result = p.emptyNode
|
||||
setEndInfo()
|
||||
|
||||
proc parseObject(p: var Parser): PNode =
|
||||
#| objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart
|
||||
@@ -2187,7 +2129,6 @@ proc parseObject(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
else:
|
||||
result.add(parseObjectPart(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeClassParam(p: var Parser): PNode =
|
||||
let modifier =
|
||||
@@ -2205,7 +2146,6 @@ proc parseTypeClassParam(p: var Parser): PNode =
|
||||
result.add(p.parseSymbol)
|
||||
else:
|
||||
result = p.parseSymbol
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeClass(p: var Parser): PNode =
|
||||
#| conceptParam = ('var' | 'out')? symbol
|
||||
@@ -2249,7 +2189,6 @@ proc parseTypeClass(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
else:
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDef(p: var Parser): PNode =
|
||||
#|
|
||||
@@ -2283,35 +2222,22 @@ proc parseTypeDef(p: var Parser): PNode =
|
||||
else:
|
||||
result.add(p.emptyNode)
|
||||
indAndComment(p, result) # special extension!
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode =
|
||||
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' (':' optInd typeDescExpr)?
|
||||
#| varTuple = varTupleLhs '=' optInd expr
|
||||
#| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
result = newNodeP(nkVarTuple, p)
|
||||
getTok(p) # skip '('
|
||||
optInd(p, result)
|
||||
# progress guaranteed
|
||||
while p.tok.tokType in {tkSymbol, tkAccent, tkParLe}:
|
||||
var a: PNode
|
||||
if p.tok.tokType == tkParLe:
|
||||
a = parseVarTuple(p)
|
||||
a.add(p.emptyNode)
|
||||
else:
|
||||
a = identWithPragma(p, allowDot=true)
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
var a = identWithPragma(p, allowDot=true)
|
||||
result.add(a)
|
||||
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 =
|
||||
#| colonBody = colcom stmt postExprBlocks?
|
||||
@@ -2324,7 +2250,6 @@ proc parseVariable(p: var Parser): PNode =
|
||||
else: result = parseIdentColonEquals(p, {withPragma, withDot})
|
||||
result[^1] = postExprBlocks(p, result[^1])
|
||||
indAndComment(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseConstant(p: var Parser): PNode =
|
||||
#| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
|
||||
@@ -2344,7 +2269,6 @@ proc parseConstant(p: var Parser): PNode =
|
||||
result.add(parseExpr(p))
|
||||
result[^1] = postExprBlocks(p, result[^1])
|
||||
indAndComment(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseBind(p: var Parser, k: TNodeKind): PNode =
|
||||
#| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
|
||||
@@ -2360,7 +2284,6 @@ proc parseBind(p: var Parser, k: TNodeKind): PNode =
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
setEndInfo()
|
||||
|
||||
proc parseStmtPragma(p: var Parser): PNode =
|
||||
#| pragmaStmt = pragma (':' COMMENT? stmt)?
|
||||
@@ -2372,7 +2295,6 @@ proc parseStmtPragma(p: var Parser): PNode =
|
||||
skipComment(p, result)
|
||||
result.add a
|
||||
result.add parseStmt(p)
|
||||
setEndInfo()
|
||||
|
||||
proc simpleStmt(p: var Parser): PNode =
|
||||
#| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
|
||||
@@ -2515,10 +2437,24 @@ proc parseStmt(p: var Parser): PNode =
|
||||
if p.tok.tokType != tkSemiColon: break
|
||||
getTok(p)
|
||||
if err and p.tok.tokType == tkEof: break
|
||||
setEndInfo()
|
||||
|
||||
proc parseAll(p: var Parser): PNode =
|
||||
## Parses the rest of the input stream held by the parser into a PNode.
|
||||
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)
|
||||
|
||||
proc checkFirstLineIndentation*(p: var Parser) =
|
||||
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
|
||||
if p.tok.indent != 0 and p.tok.strongSpaceA:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
|
||||
proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
@@ -2549,17 +2485,6 @@ proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
result = complexOrSimpleStmt(p)
|
||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
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;
|
||||
@@ -2571,10 +2496,9 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
|
||||
var stream = llStreamOpen(s)
|
||||
stream.lineOffset = line
|
||||
|
||||
var p: Parser
|
||||
p.lex.errorHandler = errorHandler
|
||||
openParser(p, AbsoluteFile filename, stream, cache, config)
|
||||
var parser: Parser
|
||||
parser.lex.errorHandler = errorHandler
|
||||
openParser(parser, AbsoluteFile filename, stream, cache, config)
|
||||
|
||||
result = p.parseAll
|
||||
closeParser(p)
|
||||
setEndInfo()
|
||||
result = parser.parseAll
|
||||
closeParser(parser)
|
||||
|
||||
@@ -14,22 +14,13 @@ import
|
||||
options, ast, llstream, msgs,
|
||||
idents,
|
||||
syntaxes, modulegraphs, reorder,
|
||||
lineinfos,
|
||||
pipelineutils,
|
||||
modules, pathutils, packages,
|
||||
sem, semdata
|
||||
|
||||
import ic/replayer
|
||||
|
||||
export skipCodegen, resolveMod, prepareConfigNotes
|
||||
lineinfos, pathutils, packages
|
||||
|
||||
when defined(nimsuggest):
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
import std/sha1
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import std/tables
|
||||
import std/syncio
|
||||
|
||||
type
|
||||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||
@@ -47,6 +38,12 @@ proc makePass*(open: TPassOpen = nil,
|
||||
result.process = process
|
||||
result.isFrontend = isFrontend
|
||||
|
||||
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
|
||||
# can be used by codegen passes to determine whether they should do
|
||||
# something with `n`. Currently, this ignores `n` and uses the global
|
||||
# error count instead.
|
||||
result = config.errorCounter > 0
|
||||
|
||||
const
|
||||
maxPasses = 10
|
||||
|
||||
@@ -83,6 +80,13 @@ proc processTopLevelStmt(graph: ModuleGraph, n: PNode, a: var TPassContextArray)
|
||||
if isNil(m): return false
|
||||
result = true
|
||||
|
||||
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
|
||||
let fullPath = findModule(conf, module, relativeTo)
|
||||
if fullPath.isEmpty:
|
||||
result = InvalidFileIdx
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
|
||||
proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
|
||||
a: var TPassContextArray; m: PSym) =
|
||||
# XXX fixme this should actually be relative to the config file!
|
||||
@@ -96,6 +100,23 @@ proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNod
|
||||
importStmt.add str
|
||||
if not processTopLevelStmt(graph, importStmt, a): break
|
||||
|
||||
const
|
||||
imperativeCode = {low(TNodeKind)..high(TNodeKind)} - {nkTemplateDef, nkProcDef, nkMethodDef,
|
||||
nkMacroDef, nkConverterDef, nkIteratorDef, nkFuncDef, nkPragma,
|
||||
nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt}
|
||||
|
||||
proc prepareConfigNotes(graph: ModuleGraph; module: PSym) =
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if graph.config.belongsToProjectPackage(module):
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
else:
|
||||
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
|
||||
graph.config.notes = graph.config.foreignPackageNotes
|
||||
|
||||
proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
|
||||
result = true
|
||||
#module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")
|
||||
|
||||
proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
stream: PLLStream): bool {.discardable.} =
|
||||
if graph.stopCompile(): return true
|
||||
@@ -122,7 +143,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
while true:
|
||||
openParser(p, fileIdx, s, graph.cache, graph.config)
|
||||
|
||||
if (not belongsToStdlib(graph, module)) or module.name.s == "distros":
|
||||
if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"):
|
||||
# XXX what about caching? no processing then? what if I change the
|
||||
# modules to include between compilation runs? we'd need to track that
|
||||
# in ROD files. I think we should enable this feature only
|
||||
@@ -132,22 +153,43 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
processImplicits graph, graph.config.implicitIncludes, nkIncludeStmt, a, module
|
||||
|
||||
checkFirstLineIndentation(p)
|
||||
block processCode:
|
||||
if graph.stopCompile(): break processCode
|
||||
while true:
|
||||
if graph.stopCompile(): break
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break processCode
|
||||
|
||||
# read everything, no streaming possible
|
||||
var sl = newNodeI(nkStmtList, n.info)
|
||||
sl.add n
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
if n.kind == nkEmpty: break
|
||||
if (sfSystemModule notin module.flags and
|
||||
({sfNoForward, sfReorder} * module.flags != {} or
|
||||
codeReordering in graph.config.features)):
|
||||
# read everything, no streaming possible
|
||||
var sl = newNodeI(nkStmtList, n.info)
|
||||
sl.add n
|
||||
if sfReorder in module.flags or codeReordering in graph.config.features:
|
||||
sl = reorder(graph, sl, module)
|
||||
discard processTopLevelStmt(graph, sl, a)
|
||||
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
sl.add n
|
||||
if sfReorder in module.flags or codeReordering in graph.config.features:
|
||||
sl = reorder(graph, sl, module)
|
||||
discard processTopLevelStmt(graph, sl, a)
|
||||
break
|
||||
elif n.kind in imperativeCode:
|
||||
# read everything until the next proc declaration etc.
|
||||
var sl = newNodeI(nkStmtList, n.info)
|
||||
sl.add n
|
||||
var rest: PNode = nil
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty or n.kind notin imperativeCode:
|
||||
rest = n
|
||||
break
|
||||
sl.add n
|
||||
#echo "-----\n", sl
|
||||
if not processTopLevelStmt(graph, sl, a): break
|
||||
if rest != nil:
|
||||
#echo "-----\n", rest
|
||||
if not processTopLevelStmt(graph, rest, a): break
|
||||
else:
|
||||
#echo "----- single\n", n
|
||||
if not processTopLevelStmt(graph, n, a): break
|
||||
closeParser(p)
|
||||
if s.kind != llsStdIn: break
|
||||
closePasses(graph, a)
|
||||
@@ -157,99 +199,3 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
# They are responsible for closing the rod files. See `cbackend.nim`.
|
||||
closeRodFile(graph, module)
|
||||
result = true
|
||||
|
||||
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
var flags = flags
|
||||
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
|
||||
result = graph.getModule(fileIdx)
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
if sfMainModule in flags:
|
||||
if graph.config.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
var cachedModules: seq[FileIndex]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
processModuleAux("import(dirty)")
|
||||
graph.markClientsDirty(fileIdx)
|
||||
|
||||
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
|
||||
# this is called by the semantic checking phase
|
||||
assert graph.config != nil
|
||||
result = compileModule(graph, fileIdx, {}, s)
|
||||
graph.addDep(s, fileIdx)
|
||||
# keep track of import relationships
|
||||
if graph.config.hcrOn:
|
||||
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
|
||||
#if sfSystemModule in result.flags:
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
graph.config.notes =
|
||||
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
else: graph.config.foreignPackageNotes
|
||||
|
||||
proc connectCallbacks*(graph: ModuleGraph) =
|
||||
graph.includeFileCallback = modules.includeModule
|
||||
graph.importModuleCallback = importModule
|
||||
|
||||
proc compileSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
connectCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
configComplete(graph)
|
||||
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
|
||||
conf.projectMainIdx2 = projectFile
|
||||
|
||||
let packSym = getPackage(graph, projectFile)
|
||||
graph.config.mainPackageId = packSym.getPackageId
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
graph.compileSystemModule()
|
||||
discard graph.compileModule(projectFile, {sfMainModule})
|
||||
|
||||
proc mySemOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
result = preparePContext(graph, module, idgen)
|
||||
|
||||
proc mySemClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
closePContext(graph, c, n)
|
||||
|
||||
proc mySemProcess(context: PPassContext, n: PNode): PNode =
|
||||
result = semWithPContext(PContext(context), n)
|
||||
|
||||
const semPass* = makePass(mySemOpen, mySemProcess, mySemClose,
|
||||
isFrontend = true)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Path handling utilities for Nim. Strictly typed code in order
|
||||
## to avoid the never ending time sink in getting path handling right.
|
||||
|
||||
import os, pathnorm, strutils
|
||||
import os, pathnorm
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
@@ -102,52 +102,3 @@ when true:
|
||||
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
|
||||
|
||||
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
|
||||
|
||||
proc skipHomeDir(x: string): int =
|
||||
when defined(windows):
|
||||
if x.continuesWith("Users/", len("C:/")):
|
||||
result = 3
|
||||
else:
|
||||
result = 0
|
||||
else:
|
||||
if x.startsWith("/home/") or x.startsWith("/Users/"):
|
||||
result = 3
|
||||
elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")):
|
||||
result = 5
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc relevantPart(s: string; afterSlashX: int): string =
|
||||
result = newStringOfCap(s.len - 8)
|
||||
var slashes = afterSlashX
|
||||
for i in 0..<s.len:
|
||||
if slashes == 0:
|
||||
result.add s[i]
|
||||
elif s[i] == '/':
|
||||
dec slashes
|
||||
|
||||
template canonSlashes(x: string): string =
|
||||
when defined(windows):
|
||||
x.replace('\\', '/')
|
||||
else:
|
||||
x
|
||||
|
||||
proc customPathImpl(x: string): string =
|
||||
# Idea: Encode a "protocol" via "//protocol/path" which is not ambiguous
|
||||
# as path canonicalization would have removed the double slashes.
|
||||
# /mnt/X/Users/Y
|
||||
# X:\\Users\Y
|
||||
# /home/Y
|
||||
# -->
|
||||
# //user/
|
||||
if not isAbsolute(x):
|
||||
result = customPathImpl(canonSlashes(getCurrentDir() / x))
|
||||
else:
|
||||
let slashes = skipHomeDir(x)
|
||||
if slashes > 0:
|
||||
result = "//user/" & relevantPart(x, slashes)
|
||||
else:
|
||||
result = x
|
||||
|
||||
proc customPath*(x: string): string =
|
||||
customPathImpl canonSlashes x
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
|
||||
lineinfos, reorder, options, semdata, cgendata, modules, pathutils,
|
||||
packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg,
|
||||
liftdestructors
|
||||
|
||||
import pipelineutils
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import jsgen, docgen2
|
||||
|
||||
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
|
||||
import renderer
|
||||
import ic/replayer
|
||||
|
||||
|
||||
proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
|
||||
graph.pipelinePass = pass
|
||||
|
||||
proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): PNode =
|
||||
case graph.pipelinePass
|
||||
of CgenPass:
|
||||
result = semNode
|
||||
if bModule != nil:
|
||||
genTopLevelStmt(BModule(bModule), result)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processJSCodeGen(bModule, semNode)
|
||||
of GenDependPass:
|
||||
result = addDotDependency(bModule, semNode)
|
||||
of SemPass:
|
||||
result = graph.emptyNode
|
||||
of Docgen2Pass, Docgen2TexPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processNode(bModule, semNode)
|
||||
of Docgen2JsonPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processNodeJson(bModule, semNode)
|
||||
of EvalPass, InterpreterPass:
|
||||
result = interpreterCode(bModule, semNode)
|
||||
of NonePass:
|
||||
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
|
||||
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator,
|
||||
) =
|
||||
# XXX fixme this should actually be relative to the config file!
|
||||
let relativeTo = toFullPath(graph.config, m.info)
|
||||
for module in items(implicits):
|
||||
# implicit imports should not lead to a module importing itself
|
||||
if m.position != resolveMod(graph.config, module, relativeTo).int32:
|
||||
var importStmt = newNodeI(nodeKind, m.info)
|
||||
var str = newStrNode(nkStrLit, module)
|
||||
str.info = m.info
|
||||
importStmt.add str
|
||||
message(graph.config, importStmt.info, hintProcessingStmt, $idgen[])
|
||||
let semNode = semWithPContext(ctx, importStmt)
|
||||
if semNode == nil or processPipeline(graph, semNode, bModule) == nil:
|
||||
break
|
||||
|
||||
proc prePass(c: PContext; n: PNode) =
|
||||
for son in n:
|
||||
if son.kind == nkPragma:
|
||||
for s in son:
|
||||
var key = if s.kind in nkPragmaCallKinds and s.len > 1: s[0] else: s
|
||||
if key.kind in {nkBracketExpr, nkCast} or key.kind notin nkIdentKinds:
|
||||
continue
|
||||
let ident = whichKeyword(considerQuotedIdent(c, key))
|
||||
case ident
|
||||
of wReorder:
|
||||
pragmaNoForward(c, s, flag = sfReorder)
|
||||
of wExperimental:
|
||||
if isTopLevel(c) and s.kind in nkPragmaCallKinds and s.len == 2:
|
||||
let name = c.semConstExpr(c, s[1])
|
||||
case name.kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
try:
|
||||
let feature = parseEnum[Feature](name.strVal)
|
||||
if feature == codeReordering:
|
||||
c.features.incl feature
|
||||
c.module.flags.incl sfReorder
|
||||
except ValueError:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
stream: PLLStream): bool =
|
||||
if graph.stopCompile(): return true
|
||||
var
|
||||
p: Parser = default(Parser)
|
||||
s: PLLStream
|
||||
fileIdx = module.fileIdx
|
||||
|
||||
prepareConfigNotes(graph, module)
|
||||
let ctx = preparePContext(graph, module, idgen)
|
||||
let bModule: PPassContext =
|
||||
case graph.pipelinePass
|
||||
of CgenPass:
|
||||
setupCgen(graph, module, idgen)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
setupJSgen(graph, module, idgen)
|
||||
else:
|
||||
nil
|
||||
of EvalPass, InterpreterPass:
|
||||
setupEvalGen(graph, module, idgen)
|
||||
of GenDependPass:
|
||||
setupDependPass(graph, module, idgen)
|
||||
of Docgen2Pass:
|
||||
when not defined(leanCompiler):
|
||||
openHtml(graph, module, idgen)
|
||||
else:
|
||||
nil
|
||||
of Docgen2TexPass:
|
||||
when not defined(leanCompiler):
|
||||
openTex(graph, module, idgen)
|
||||
else:
|
||||
nil
|
||||
of Docgen2JsonPass:
|
||||
when not defined(leanCompiler):
|
||||
openJson(graph, module, idgen)
|
||||
else:
|
||||
nil
|
||||
of SemPass:
|
||||
nil
|
||||
of NonePass:
|
||||
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
|
||||
nil
|
||||
|
||||
if stream == nil:
|
||||
let filename = toFullPathConsiderDirty(graph.config, fileIdx)
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
rawMessage(graph.config, errCannotOpenFile, filename.string)
|
||||
return false
|
||||
else:
|
||||
s = stream
|
||||
|
||||
while true:
|
||||
syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)
|
||||
|
||||
if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"):
|
||||
# XXX what about caching? no processing then? what if I change the
|
||||
# modules to include between compilation runs? we'd need to track that
|
||||
# in ROD files. I think we should enable this feature only
|
||||
# for the interactive mode.
|
||||
if module.name.s != "nimscriptapi":
|
||||
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen
|
||||
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen
|
||||
|
||||
checkFirstLineIndentation(p)
|
||||
block processCode:
|
||||
if graph.stopCompile(): break processCode
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break processCode
|
||||
# read everything, no streaming possible
|
||||
var sl = newNodeI(nkStmtList, n.info)
|
||||
sl.add n
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
sl.add n
|
||||
|
||||
prePass(ctx, sl)
|
||||
if sfReorder in module.flags or codeReordering in graph.config.features:
|
||||
sl = reorder(graph, sl, module)
|
||||
if graph.pipelinePass != EvalPass:
|
||||
message(graph.config, sl.info, hintProcessingStmt, $idgen[])
|
||||
var semNode = semWithPContext(ctx, sl)
|
||||
discard processPipeline(graph, semNode, bModule)
|
||||
|
||||
closeParser(p)
|
||||
if s.kind != llsStdIn: break
|
||||
let finalNode = closePContext(graph, ctx, nil)
|
||||
case graph.pipelinePass
|
||||
of CgenPass:
|
||||
if bModule != nil:
|
||||
let disps = finalCodegenActions(graph, BModule(bModule), finalNode)
|
||||
if disps != nil:
|
||||
let ctx = preparePContext(graph, module, idgen)
|
||||
for disp in disps:
|
||||
let retTyp = disp.sym.typ[0]
|
||||
if retTyp != nil:
|
||||
# todo properly semcheck the code of dispatcher?
|
||||
createTypeBoundOps(graph, ctx, retTyp, disp.info, idgen)
|
||||
genProcAux(BModule(bModule), disp.sym)
|
||||
discard closePContext(graph, ctx, nil)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
discard finalJSCodeGen(graph, bModule, finalNode)
|
||||
of EvalPass, InterpreterPass:
|
||||
discard interpreterCode(bModule, finalNode)
|
||||
of SemPass, GenDependPass:
|
||||
discard
|
||||
of Docgen2Pass, Docgen2TexPass:
|
||||
when not defined(leanCompiler):
|
||||
discard closeDoc(graph, bModule, finalNode)
|
||||
of Docgen2JsonPass:
|
||||
when not defined(leanCompiler):
|
||||
discard closeJson(graph, bModule, finalNode)
|
||||
of NonePass:
|
||||
doAssert false, "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.
|
||||
# The C-like backends have been patched to support the IC mechanism.
|
||||
# They are responsible for closing the rod files. See `cbackend.nim`.
|
||||
closeRodFile(graph, module)
|
||||
result = true
|
||||
|
||||
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
var flags = flags
|
||||
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
|
||||
result = graph.getModule(fileIdx)
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
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]
|
||||
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)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
processModuleAux("import(dirty)")
|
||||
graph.markClientsDirty(fileIdx)
|
||||
|
||||
proc importPipelineModule(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
|
||||
# this is called by the semantic checking phase
|
||||
assert graph.config != nil
|
||||
result = compilePipelineModule(graph, fileIdx, {}, s)
|
||||
graph.addDep(s, fileIdx)
|
||||
# keep track of import relationships
|
||||
if graph.config.hcrOn:
|
||||
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
|
||||
#if sfSystemModule in result.flags:
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
graph.config.notes =
|
||||
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
else: graph.config.foreignPackageNotes
|
||||
|
||||
proc connectPipelineCallbacks*(graph: ModuleGraph) =
|
||||
graph.includeFileCallback = modules.includeModule
|
||||
graph.importModuleCallback = importPipelineModule
|
||||
|
||||
proc compilePipelineSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
connectPipelineCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compilePipelineModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectPipelineCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
configComplete(graph)
|
||||
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
|
||||
conf.projectMainIdx2 = projectFile
|
||||
|
||||
let packSym = getPackage(graph, projectFile)
|
||||
graph.config.mainPackageId = packSym.getPackageId
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
discard graph.compilePipelineModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
graph.compilePipelineSystemModule()
|
||||
discard graph.compilePipelineModule(projectFile, {sfMainModule})
|
||||
@@ -1,26 +0,0 @@
|
||||
import ast, options, lineinfos, pathutils, msgs, modulegraphs, packages
|
||||
|
||||
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
|
||||
# can be used by codegen passes to determine whether they should do
|
||||
# something with `n`. Currently, this ignores `n` and uses the global
|
||||
# error count instead.
|
||||
result = config.errorCounter > 0
|
||||
|
||||
proc resolveMod*(conf: ConfigRef; module, relativeTo: string): FileIndex =
|
||||
let fullPath = findModule(conf, module, relativeTo)
|
||||
if fullPath.isEmpty:
|
||||
result = InvalidFileIdx
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
|
||||
proc prepareConfigNotes*(graph: ModuleGraph; module: PSym) =
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if graph.config.belongsToProjectPackage(module):
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
else:
|
||||
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
|
||||
graph.config.notes = graph.config.foreignPackageNotes
|
||||
|
||||
proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
|
||||
result = true
|
||||
#module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")
|
||||
@@ -26,8 +26,7 @@ type
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr,
|
||||
osNuttX, osAny
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny
|
||||
|
||||
type
|
||||
TInfoOSProp* = enum
|
||||
@@ -194,10 +193,6 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "NuttX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
|
||||
@@ -31,7 +31,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
|
||||
return
|
||||
let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen)
|
||||
|
||||
let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
|
||||
let prc = newSym(skProc, n[3].ident, nextSymId c.idgen, iter.sym.owner, iter.sym.info)
|
||||
prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc)
|
||||
excl prc.typ.flags, tfCapturesEnv
|
||||
prc.typ.n.add newSymNode(getEnvParam(iter.sym))
|
||||
|
||||
@@ -26,7 +26,7 @@ proc semLocals*(c: PContext, n: PNode): PNode =
|
||||
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyUntyped, tyTyped, tyEmpty}:
|
||||
|
||||
if it.owner == owner:
|
||||
var field = newSym(skField, it.name, c.idgen, owner, n.info)
|
||||
var field = newSym(skField, it.name, nextSymId c.idgen, owner, n.info)
|
||||
field.typ = it.typ.skipTypes({tyVar})
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import
|
||||
os, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
|
||||
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
|
||||
types, lookups, lineinfos, pathutils, linter, modulepaths
|
||||
types, lookups, lineinfos, pathutils, linter
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -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}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
@@ -71,8 +71,7 @@ const
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage, wCodegenDecl,
|
||||
wSendable}
|
||||
wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage}
|
||||
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
|
||||
wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
@@ -84,7 +83,7 @@ const
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wDefine,
|
||||
wCompilerProc, wCore}
|
||||
paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl}
|
||||
paramPragmas* = {wNoalias, wInject, wGensym}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
|
||||
wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe,
|
||||
@@ -117,15 +116,7 @@ const
|
||||
proc invalidPragma*(c: PContext; n: PNode) =
|
||||
localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments}))
|
||||
proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
|
||||
var msg = "cannot attach a custom pragma to '" & s.name.s & "'"
|
||||
if s != nil:
|
||||
msg.add("; custom pragmas are not supported for ")
|
||||
case s.kind
|
||||
of skForVar: msg.add("`for` loop variables")
|
||||
of skEnumField: msg.add("enum fields")
|
||||
of skModule: msg.add("modules")
|
||||
else: msg.add("symbol kind " & $s.kind)
|
||||
localError(c.config, n.info, msg)
|
||||
localError(c.config, n.info, "cannot attach a custom pragma to '" & s.name.s & "'")
|
||||
|
||||
proc pragmaProposition(c: PContext, n: PNode) =
|
||||
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
||||
@@ -140,7 +131,7 @@ proc pragmaEnsures(c: PContext, n: PNode) =
|
||||
openScope(c)
|
||||
let o = getCurrOwner(c)
|
||||
if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil:
|
||||
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
|
||||
var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId(c.idgen), o, n.info)
|
||||
s.typ = o.typ.sons[0]
|
||||
incl(s.flags, sfUsed)
|
||||
addDecl(c, s)
|
||||
@@ -174,7 +165,9 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
||||
when hasFFI:
|
||||
s.cname = $s.loc.r
|
||||
|
||||
if c.config.cmd == cmdNimfix and '$' notin extname:
|
||||
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
||||
s.loc.flags.incl(lfFullExternalName)
|
||||
|
||||
proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
@@ -209,9 +202,9 @@ proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToObjc)
|
||||
|
||||
proc newEmptyStrNode(c: PContext; n: PNode, strVal: string = ""): PNode {.noinline.} =
|
||||
proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} =
|
||||
result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
|
||||
result.strVal = strVal
|
||||
result.strVal = ""
|
||||
|
||||
proc getStrLitNode(c: PContext, n: PNode): PNode =
|
||||
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
||||
@@ -243,17 +236,8 @@ 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) =
|
||||
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.typ.callConv = ccNoConvention
|
||||
incl c.config.globalOptions, optMixedMode
|
||||
|
||||
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
|
||||
sym.constraint = getStrLitNode(c, n)
|
||||
sym.flags.incl sfCodegenDecl
|
||||
|
||||
proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||
#if sfSystemModule notin c.module.flags:
|
||||
@@ -286,7 +270,7 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
|
||||
if isTurnedOn(c, n): resOptions.incl op
|
||||
else: resOptions.excl op
|
||||
|
||||
proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
|
||||
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
|
||||
if isTurnedOn(c, n):
|
||||
incl(c.module.flags, flag)
|
||||
c.features.incl codeReordering
|
||||
@@ -318,7 +302,7 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
|
||||
result.path = path
|
||||
c.libs.add result
|
||||
if path.kind in {nkStrLit..nkTripleStrLit}:
|
||||
result.isOverridden = options.isDynlibOverride(c.config, path.strVal)
|
||||
result.isOverriden = options.isDynlibOverride(c.config, path.strVal)
|
||||
|
||||
proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
||||
@@ -330,7 +314,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)
|
||||
@@ -338,12 +322,12 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
if (sym == nil) or (sym.kind == skModule):
|
||||
let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
if not lib.isOverridden:
|
||||
if not lib.isOverriden:
|
||||
c.optionStack[^1].dynlib = lib
|
||||
else:
|
||||
if n.kind in nkPragmaCallKinds:
|
||||
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
if not lib.isOverridden:
|
||||
if not lib.isOverriden:
|
||||
addToLib(lib, sym)
|
||||
incl(sym.loc.flags, lfDynamicLib)
|
||||
else:
|
||||
@@ -380,7 +364,7 @@ proc processNote(c: PContext, n: PNode) =
|
||||
else: invalidPragma(c, n)
|
||||
else: invalidPragma(c, n)
|
||||
|
||||
proc pragmaToOptions*(w: TSpecialWord): TOptions {.inline.} =
|
||||
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
|
||||
case w
|
||||
of wChecks: ChecksOptions
|
||||
of wObjChecks: {optObjCheck}
|
||||
@@ -406,7 +390,6 @@ proc pragmaToOptions*(w: TSpecialWord): TOptions {.inline.} =
|
||||
of wImplicitStatic: {optImplicitStatic}
|
||||
of wPatterns, wTrMacros: {optTrMacros}
|
||||
of wSinkInference: {optSinkInference}
|
||||
of wQuirky: {optQuirky}
|
||||
else: {}
|
||||
|
||||
proc processExperimental(c: PContext; n: PNode) =
|
||||
@@ -468,18 +451,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 +458,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]
|
||||
@@ -539,25 +509,18 @@ proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile =
|
||||
if result.isEmpty: result = AbsoluteFile s
|
||||
|
||||
proc processCompile(c: PContext, n: PNode) =
|
||||
## This pragma can take two forms. The first is a simple file input:
|
||||
## {.compile: "file.c".}
|
||||
## The second is a tuple where the second arg is the output name strutils formatter:
|
||||
## {.compile: ("file.c", "$1.o").}
|
||||
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile; customArgs: string) =
|
||||
var cf = Cfile(nimname: splitFile(src).name,
|
||||
cname: src, obj: dest, flags: {CfileFlag.External},
|
||||
customArgs: customArgs)
|
||||
if not fileExists(src):
|
||||
localError(c.config, n.info, "cannot find: " & src.string)
|
||||
else:
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
|
||||
|
||||
proc getStrLit(c: PContext, n: PNode; i: int): string =
|
||||
n[i] = c.semConstExpr(c, n[i])
|
||||
case n[i].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
result = n[i].strVal
|
||||
else:
|
||||
shallowCopy(result, n[i].strVal)
|
||||
@@ -591,8 +554,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
else:
|
||||
found = findFile(c.config, s)
|
||||
if found.isEmpty: found = AbsoluteFile s
|
||||
let mangled = completeCfilePath(c.config, mangleModuleName(c.config, found).AbsoluteFile)
|
||||
let obj = toObjFile(c.config, mangled)
|
||||
let obj = toObjFile(c.config, completeCfilePath(c.config, found, false))
|
||||
docompile(c, it, found, obj, customArgs)
|
||||
|
||||
proc processLink(c: PContext, n: PNode) =
|
||||
@@ -644,7 +606,7 @@ proc pragmaEmit(c: PContext, n: PNode) =
|
||||
if n1.kind == nkBracket:
|
||||
var b = newNodeI(nkBracket, n1.info, n1.len)
|
||||
for i in 0..<n1.len:
|
||||
b[i] = c.semExprWithType(c, n1[i], {efTypeAllowed})
|
||||
b[i] = c.semExpr(c, n1[i])
|
||||
n[1] = b
|
||||
else:
|
||||
n[1] = c.semConstExpr(c, n1)
|
||||
@@ -697,8 +659,7 @@ proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent:
|
||||
invalidPragma(c, n)
|
||||
|
||||
var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options)
|
||||
styleCheckDef(c, userPragma)
|
||||
var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), c.module, it.info, c.config.options)
|
||||
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
|
||||
strTableAdd(c.userPragmas, userPragma)
|
||||
|
||||
@@ -758,8 +719,19 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
|
||||
return
|
||||
if pragma.kind != nkBracket:
|
||||
localError(c.config, pragma.info, "list of key:value pairs expected"); return
|
||||
message(c.config, pragma.info, warnDeprecated,
|
||||
"deprecated statement is now a no-op, use regular deprecated pragma")
|
||||
for n in pragma:
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
|
||||
if dest == nil or dest.kind in routineKinds:
|
||||
localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines")
|
||||
let src = considerQuotedIdent(c, n[0])
|
||||
let alias = newSym(skAlias, src, nextSymId(c.idgen), dest, n[0].info, c.config.options)
|
||||
incl(alias.flags, sfExported)
|
||||
if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
|
||||
addInterfaceDecl(c, alias)
|
||||
n[1] = newSymNode(dest)
|
||||
else:
|
||||
localError(c.config, n.info, "key:value pair expected")
|
||||
|
||||
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||
if it.kind notin nkPragmaCallKinds or it.len != 2:
|
||||
@@ -775,12 +747,12 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||
# We return a dummy symbol; later passes over the type will repair it.
|
||||
# Generic instantiation needs to know about this too. But we're lazy
|
||||
# and perform the lookup on demand instead.
|
||||
result = newSym(skUnknown, considerQuotedIdent(c, n), c.idgen, nil, n.info,
|
||||
result = newSym(skUnknown, considerQuotedIdent(c, n), nextSymId(c.idgen), nil, n.info,
|
||||
c.config.options)
|
||||
else:
|
||||
result = qualifiedLookUp(c, n, {checkUndeclared})
|
||||
|
||||
proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
|
||||
proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||
var callNode: PNode
|
||||
|
||||
if n.kind in {nkIdent, nkSym}:
|
||||
@@ -800,11 +772,6 @@ proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
|
||||
invalidPragma(c, n)
|
||||
return n
|
||||
|
||||
# we have a valid custom pragma
|
||||
if sym != nil and sym.kind in {skEnumField, skForVar, skModule}:
|
||||
illegalCustomPragma(c, n, sym)
|
||||
return n
|
||||
|
||||
result = r
|
||||
# Transform the nkCall node back to its original form if possible
|
||||
if n.kind == nkIdent and r.len == 1:
|
||||
@@ -838,8 +805,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
validPragmas: TSpecialWords,
|
||||
comesFromPush, isStatement: bool): bool =
|
||||
var it = n[i]
|
||||
let keyDeep = it.kind in nkPragmaCallKinds and it.len > 1
|
||||
var key = if keyDeep: it[0] else: it
|
||||
var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it
|
||||
if key.kind == nkBracketExpr:
|
||||
processNote(c, it)
|
||||
return
|
||||
@@ -853,7 +819,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
else: discard
|
||||
return
|
||||
elif key.kind notin nkIdentKinds:
|
||||
n[i] = semCustomPragma(c, it, sym)
|
||||
n[i] = semCustomPragma(c, it)
|
||||
return
|
||||
let ident = considerQuotedIdent(c, key)
|
||||
var userPragma = strTableGet(c.userPragmas, ident)
|
||||
@@ -862,20 +828,17 @@ 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)
|
||||
|
||||
if keyDeep:
|
||||
localError(c.config, it.info, "user pragma cannot have arguments")
|
||||
|
||||
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:
|
||||
checkPragmaUse(c, key.info, k, ident.s, (if sym != nil: sym else: c.module))
|
||||
checkPragmaUse(c.config, key.info, k, ident.s)
|
||||
case k
|
||||
of wExportc, wExportCpp:
|
||||
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
@@ -963,8 +926,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wThreadVar:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, {sfThread, sfGlobal})
|
||||
of wDeadCodeElimUnused:
|
||||
warningDeprecated(c.config, n.info, "'{.deadcodeelim: on.}' is deprecated, now a noop") # deprecated, dead code elim always on
|
||||
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
||||
of wNoForward: pragmaNoForward(c, it)
|
||||
of wReorder: pragmaNoForward(c, it, flag = sfReorder)
|
||||
of wMagic: processMagic(c, it, sym)
|
||||
@@ -984,12 +946,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
# only supported for backwards compat, doesn't do anything anymore
|
||||
noVal(c, it)
|
||||
of wConstructor:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfConstructor)
|
||||
if sfImportc notin sym.flags:
|
||||
sym.constraint = newEmptyStrNode(c, it, getOptionalStr(c, it, ""))
|
||||
sym.constraint.strVal = sym.constraint.strVal
|
||||
sym.flags.incl {sfExportc, sfMangleCpp}
|
||||
sym.typ.callConv = ccNoConvention
|
||||
of wHeader:
|
||||
var lib = getLib(c, libHeader, getStrLitNode(c, it))
|
||||
addToLib(lib, sym)
|
||||
@@ -1083,12 +1041,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if sym.typ != nil:
|
||||
incl(sym.typ.flags, tfThread)
|
||||
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
|
||||
of wSendable:
|
||||
noVal(c, it)
|
||||
if sym != nil and sym.typ != nil:
|
||||
incl(sym.typ.flags, tfSendable)
|
||||
else:
|
||||
invalidPragma(c, it)
|
||||
of wGcSafe:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
@@ -1125,20 +1077,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)
|
||||
@@ -1220,17 +1165,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
invalidPragma(c, it)
|
||||
of wByRef:
|
||||
noVal(c, it)
|
||||
if sym != nil and sym.kind == skParam:
|
||||
sym.options.incl optByRef
|
||||
elif sym == nil or sym.typ == nil:
|
||||
if sym == nil or sym.typ == nil:
|
||||
processOption(c, it, c.config.options)
|
||||
else:
|
||||
incl(sym.typ.flags, tfByRef)
|
||||
of wByCopy:
|
||||
noVal(c, it)
|
||||
if sym.kind == skParam:
|
||||
incl(sym.flags, sfByCopy)
|
||||
elif sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
|
||||
if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ.flags, tfByCopy)
|
||||
of wPartial:
|
||||
noVal(c, it)
|
||||
@@ -1297,21 +1238,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
pragmaEnsures(c, it)
|
||||
of wEnforceNoRaises:
|
||||
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)
|
||||
|
||||
else: invalidPragma(c, it)
|
||||
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
||||
discard "ignore the .push pragma; it doesn't apply"
|
||||
else:
|
||||
# semCustomPragma gives appropriate error for invalid pragmas
|
||||
n[i] = semCustomPragma(c, it, sym)
|
||||
if sym == nil or (sym.kind in {skVar, skLet, skConst, skParam, skIterator,
|
||||
skField, skProc, skFunc, skConverter, skMethod, skType}):
|
||||
n[i] = semCustomPragma(c, it)
|
||||
elif sym != nil:
|
||||
illegalCustomPragma(c, it, sym)
|
||||
else:
|
||||
invalidPragma(c, it)
|
||||
|
||||
proc overwriteLineInfo(n: PNode; info: TLineInfo) =
|
||||
n.info = info
|
||||
|
||||
@@ -31,7 +31,7 @@ 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):
|
||||
@@ -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:
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
- Note that this code has been translated from a bootstrapping version written in Pascal.
|
||||
- So the code is **not** a poster child of good Nim code.
|
||||
|
||||
See [Internals of the Nim Compiler](https://nim-lang.github.io/Nim/intern.html) for more information.
|
||||
See [Internals of the Nim Compiler](https://nim-lang.org/docs/intern.html) for more information.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user